module Distribution.Simple.Program.Script (
invocationAsSystemScript,
invocationAsShellScript,
invocationAsBatchFile,
) where
import Distribution.Simple.Program.Run
import Distribution.System
import Data.Maybe
( maybeToList )
invocationAsSystemScript :: OS -> ProgramInvocation -> String
invocationAsSystemScript Windows = invocationAsBatchFile
invocationAsSystemScript _ = invocationAsShellScript
invocationAsShellScript :: ProgramInvocation -> String
invocationAsShellScript
ProgramInvocation {
progInvokePath = path,
progInvokeArgs = args,
progInvokeEnv = envExtra,
progInvokeCwd = mcwd,
progInvokeInput = minput
} = unlines $
[ "#!/bin/sh" ]
++ concatMap setEnv envExtra
++ [ "cd " ++ quote cwd | cwd <- maybeToList mcwd ]
++ [ (case minput of
Nothing -> ""
Just input -> "echo " ++ quote input ++ " | ")
++ unwords (map quote $ path : args) ++ " \"$@\""]
where
setEnv (var, Nothing) = ["unset " ++ var, "export " ++ var]
setEnv (var, Just val) = ["export " ++ var ++ "=" ++ quote val]
quote :: String -> String
quote s = "'" ++ escape s ++ "'"
escape [] = []
escape ('\'':cs) = "'\\''" ++ escape cs
escape (c :cs) = c : escape cs
invocationAsBatchFile :: ProgramInvocation -> String
invocationAsBatchFile
ProgramInvocation {
progInvokePath = path,
progInvokeArgs = args,
progInvokeEnv = envExtra,
progInvokeCwd = mcwd,
progInvokeInput = minput
} = unlines $
[ "@echo off" ]
++ map setEnv envExtra
++ [ "cd \"" ++ cwd ++ "\"" | cwd <- maybeToList mcwd ]
++ case minput of
Nothing ->
[ path ++ concatMap (' ':) args ]
Just input ->
[ "(" ]
++ [ "echo " ++ escape line | line <- lines input ]
++ [ ") | "
++ "\"" ++ path ++ "\""
++ concatMap (\arg -> ' ':quote arg) args ]
where
setEnv (var, Nothing) = "set " ++ var ++ "="
setEnv (var, Just val) = "set " ++ var ++ "=" ++ escape val
quote :: String -> String
quote s = "\"" ++ escapeQ s ++ "\""
escapeQ [] = []
escapeQ ('"':cs) = "\"\"\"" ++ escapeQ cs
escapeQ (c :cs) = c : escapeQ cs
escape [] = []
escape ('|':cs) = "^|" ++ escape cs
escape ('<':cs) = "^<" ++ escape cs
escape ('>':cs) = "^>" ++ escape cs
escape ('&':cs) = "^&" ++ escape cs
escape ('(':cs) = "^(" ++ escape cs
escape (')':cs) = "^)" ++ escape cs
escape ('^':cs) = "^^" ++ escape cs
escape (c :cs) = c : escape cs