diff options
-rw-r--r-- | CHANGELOG | 6 | ||||
-rw-r--r-- | Git/Hook.hs | 21 | ||||
-rw-r--r-- | Remote/External.hs | 25 | ||||
-rw-r--r-- | Utility/Shell.hs | 42 | ||||
-rw-r--r-- | doc/todo/refactor_shebang_handling_code_for_wider_use.mdwn | 2 |
5 files changed, 66 insertions, 30 deletions
@@ -1,3 +1,9 @@ +git-annex (6.20160809) UNRELEASED; urgency=medium + + * Windows: Handle shebang in external special remote program. + + -- Joey Hess <id@joeyh.name> Mon, 05 Sep 2016 11:51:49 -0400 + git-annex (6.20160808) unstable; urgency=medium * metadata --json output format has changed, adding a inner json object diff --git a/Git/Hook.hs b/Git/Hook.hs index f4424c60e..da999733d 100644 --- a/Git/Hook.hs +++ b/Git/Hook.hs @@ -12,6 +12,7 @@ module Git.Hook where import Common import Git import Utility.Tmp +import Utility.Shell #ifndef mingw32_HOST_OS import Utility.FileMode #endif @@ -75,23 +76,5 @@ hookExists h r = do runHook :: Hook -> Repo -> IO Bool runHook h r = do let f = hookFile h r - (c, ps) <- findcmd f + (c, ps) <- findShellCommand f boolSystem c ps - where -#ifndef mingw32_HOST_OS - findcmd = defcmd -#else - {- Like git for windows, parse the first line of the hook file, - - look for "#!", and dispatch the interpreter on the file. -} - findcmd f = do - l <- headMaybe . lines <$> catchDefaultIO "" (readFile f) - case l of - Just ('#':'!':rest) -> case words rest of - [] -> defcmd f - (c:ps) -> do - let ps' = map Param (ps ++ [f]) - ok <- inPath c - return (if ok then c else takeFileName c, ps') - _ -> defcmd f -#endif - defcmd f = return (f, []) diff --git a/Remote/External.hs b/Remote/External.hs index f88b069be..13c46585b 100644 --- a/Remote/External.hs +++ b/Remote/External.hs @@ -21,6 +21,7 @@ import Remote.Helper.Special import Remote.Helper.ReadOnly import Remote.Helper.Messages import Utility.Metered +import Utility.Shell import Messages.Progress import Types.Transfer import Logs.PreferredContent.Raw @@ -374,7 +375,13 @@ startExternal externaltype = do errrelayer <- mkStderrRelayer g <- Annex.gitRepo liftIO $ do - p <- propgit g cmdp + (cmd, ps) <- findShellCommand basecmd + let basep = (proc cmd (toCommand ps)) + { std_in = CreatePipe + , std_out = CreatePipe + , std_err = CreatePipe + } + p <- propgit g basep (Just hin, Just hout, Just herr, pid) <- createProcess p `catchIO` runerr fileEncoding hin @@ -391,24 +398,20 @@ startExternal externaltype = do , externalPrepared = Unprepared } where - cmd = externalRemoteProgram externaltype - cmdp = (proc cmd []) - { std_in = CreatePipe - , std_out = CreatePipe - , std_err = CreatePipe - } + basecmd = externalRemoteProgram externaltype + propgit g p = do environ <- propGitEnv g return $ p { env = Just environ } - runerr _ = error ("Cannot run " ++ cmd ++ " -- Make sure it's in your PATH and is executable.") + runerr _ = error ("Cannot run " ++ basecmd ++ " -- Make sure it's in your PATH and is executable.") checkearlytermination Nothing = noop - checkearlytermination (Just exitcode) = ifM (inPath cmd) - ( error $ unwords [ "failed to run", cmd, "(" ++ show exitcode ++ ")" ] + checkearlytermination (Just exitcode) = ifM (inPath basecmd) + ( error $ unwords [ "failed to run", basecmd, "(" ++ show exitcode ++ ")" ] , do path <- intercalate ":" <$> getSearchPath - error $ cmd ++ " is not installed in PATH (" ++ path ++ ")" + error $ basecmd ++ " is not installed in PATH (" ++ path ++ ")" ) stopExternal :: External -> Annex () diff --git a/Utility/Shell.hs b/Utility/Shell.hs index e71ca53aa..860ee11dd 100644 --- a/Utility/Shell.hs +++ b/Utility/Shell.hs @@ -9,6 +9,19 @@ module Utility.Shell where +import Utility.SafeCommand +#ifdef mingw32_HOST_OS +import Utility.Path +import Utility.FileSystemEncoding +import Utility.Exception +import Utility.PartialPrelude +#endif + +#ifdef mingw32_HOST_OS +import System.IO +import System.FilePath +#endif + shellPath_portable :: FilePath shellPath_portable = "/bin/sh" @@ -24,3 +37,32 @@ shebang_portable = "#!" ++ shellPath_portable shebang_local :: String shebang_local = "#!" ++ shellPath_local + +-- | On Windows, shebang is not handled by the kernel, so to support +-- shell scripts etc, have to look at the program being run and +-- parse it for shebang. +-- +-- This has no effect on Unix. +findShellCommand :: FilePath -> IO (FilePath, [CommandParam]) +findShellCommand f = do +#ifndef mingw32_HOST_OS + defcmd +#else + l <- catchDefaultIO Nothing $ withFile f ReadMode $ \h -> do + fileEncoding h + headMaybe . lines <$> hGetContents h + case l of + Just ('#':'!':rest) -> case words rest of + [] -> defcmd + (c:ps) -> do + let ps' = map Param ps ++ [File f] + -- If the command is not inPath, + -- take the base of it, and run eg "sh" + -- which in some cases on windows will work + -- despite it not being inPath. + ok <- inPath c + return (if ok then c else takeFileName c, ps') + _ -> defcmd +#endif + where + defcmd = return (f, []) diff --git a/doc/todo/refactor_shebang_handling_code_for_wider_use.mdwn b/doc/todo/refactor_shebang_handling_code_for_wider_use.mdwn index a0eec316b..c7f7ce6cc 100644 --- a/doc/todo/refactor_shebang_handling_code_for_wider_use.mdwn +++ b/doc/todo/refactor_shebang_handling_code_for_wider_use.mdwn @@ -5,3 +5,5 @@ When launching an external special remote, use the shebang handling code which c [joeyh] """Oh, git-annex already deals with this particular windows nonsense elsewhere. When it needs to run a git hook, it parses it for a shebang. Git for windows does the same. So, if you can please open a todo item in git-annex, I can refactor that existing code to be used in more places.""" + +> [[done]] --[[Joey]] |