support conditionally excluding queued files

Switched code to use a for loop to avoid a filterM that would have
doubled the memory used.

This commit was supported by the NSF-funded DataLad project.
This commit is contained in:
Joey Hess 2018-08-16 14:28:05 -04:00
parent 82cfcfc838
commit 6a445dc086
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
2 changed files with 34 additions and 17 deletions

View file

@ -11,6 +11,7 @@ module Git.Queue (
Queue,
new,
addCommand,
addCommandCond,
addUpdateIndex,
size,
full,
@ -36,7 +37,10 @@ data Action
| CommandAction
{ getSubcommand :: String
, getParams :: [CommandParam]
, getFiles :: [CommandParam]
{- The IO action is run when constructing the action, and
- can return False if the file should not be included
- after all. -}
, getFiles :: [(FilePath, IO Bool)]
}
{- A key that can uniquely represent an action in a Map. -}
@ -80,12 +84,18 @@ new lim = Queue 0 (fromMaybe defaultLimit lim) M.empty
-}
addCommand :: String -> [CommandParam] -> [FilePath] -> Queue -> Repo -> IO Queue
addCommand subcommand params files q repo =
addCommandCond subcommand params files' q repo
where
files' = map (\f -> (f, return True)) files
addCommandCond :: String -> [CommandParam] -> [(FilePath, IO Bool)] -> Queue -> Repo -> IO Queue
addCommandCond subcommand params files q repo =
updateQueue action different (length files) q repo
where
action = CommandAction
{ getSubcommand = subcommand
, getParams = params
, getFiles = map File files
, getFiles = files
}
different (CommandAction { getSubcommand = s }) = s /= subcommand
@ -157,17 +167,22 @@ runAction repo (UpdateIndexAction streamers) =
Git.UpdateIndex.streamUpdateIndex repo $ reverse streamers
runAction repo action@(CommandAction {}) = do
#ifndef mingw32_HOST_OS
let p = (proc "xargs" $ "-0":"git":toCommand gitparams) { env = gitEnv repo }
let p = (proc "xargs" $ "-0":"git":toCommand gitparams)
{ env = gitEnv repo }
withHandle StdinHandle createProcessSuccess p $ \h -> do
hPutStr h $ intercalate "\0" $ toCommand $ getFiles action
forM_ (getFiles action) $ \(f, check) ->
whenM check $ do
hPutStr h (toCommand' (File f))
hPutStr h "\0"
hClose h
#else
-- Using xargs on Windows is problematic, so just run the command
-- once per file (not as efficient.)
if null (getFiles action)
then void $ boolSystemEnv "git" gitparams (gitEnv repo)
else forM_ (getFiles action) $ \f ->
void $ boolSystemEnv "git" (gitparams ++ [f]) (gitEnv repo)
else forM_ (getFiles action) $ \(f, check) ->
whenM check $
void $ boolSystemEnv "git" (gitparams ++ [File f]) (gitEnv repo)
#endif
where
gitparams = gitCommandLine

View file

@ -27,19 +27,21 @@ data CommandParam
-- | Used to pass a list of CommandParams to a function that runs
-- a command and expects Strings. -}
toCommand :: [CommandParam] -> [String]
toCommand = map unwrap
toCommand = map toCommand'
toCommand' :: CommandParam -> String
toCommand' (Param s) = s
-- Files that start with a non-alphanumeric that is not a path
-- separator are modified to avoid the command interpreting them as
-- options or other special constructs.
toCommand' (File s@(h:_))
| isAlphaNum h || h `elem` pathseps = s
| otherwise = "./" ++ s
where
unwrap (Param s) = s
-- Files that start with a non-alphanumeric that is not a path
-- separator are modified to avoid the command interpreting them as
-- options or other special constructs.
unwrap (File s@(h:_))
| isAlphaNum h || h `elem` pathseps = s
| otherwise = "./" ++ s
unwrap (File s) = s
-- '/' is explicitly included because it's an alternative
-- path separator on Windows.
pathseps = pathSeparator:"./"
toCommand' (File s) = s
-- | Run a system command, and returns True or False if it succeeded or failed.
--