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, Queue,
new, new,
addCommand, addCommand,
addCommandCond,
addUpdateIndex, addUpdateIndex,
size, size,
full, full,
@ -36,8 +37,11 @@ data Action
| CommandAction | CommandAction
{ getSubcommand :: String { getSubcommand :: String
, getParams :: [CommandParam] , 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. -} {- A key that can uniquely represent an action in a Map. -}
data ActionKey = UpdateIndexActionKey | CommandActionKey String data ActionKey = UpdateIndexActionKey | CommandActionKey String
@ -79,13 +83,19 @@ new lim = Queue 0 (fromMaybe defaultLimit lim) M.empty
- result. - result.
-} -}
addCommand :: String -> [CommandParam] -> [FilePath] -> Queue -> Repo -> IO Queue addCommand :: String -> [CommandParam] -> [FilePath] -> Queue -> Repo -> IO Queue
addCommand subcommand params files q repo = 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 updateQueue action different (length files) q repo
where where
action = CommandAction action = CommandAction
{ getSubcommand = subcommand { getSubcommand = subcommand
, getParams = params , getParams = params
, getFiles = map File files , getFiles = files
} }
different (CommandAction { getSubcommand = s }) = s /= subcommand different (CommandAction { getSubcommand = s }) = s /= subcommand
@ -157,17 +167,22 @@ runAction repo (UpdateIndexAction streamers) =
Git.UpdateIndex.streamUpdateIndex repo $ reverse streamers Git.UpdateIndex.streamUpdateIndex repo $ reverse streamers
runAction repo action@(CommandAction {}) = do runAction repo action@(CommandAction {}) = do
#ifndef mingw32_HOST_OS #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 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 hClose h
#else #else
-- Using xargs on Windows is problematic, so just run the command -- Using xargs on Windows is problematic, so just run the command
-- once per file (not as efficient.) -- once per file (not as efficient.)
if null (getFiles action) if null (getFiles action)
then void $ boolSystemEnv "git" gitparams (gitEnv repo) then void $ boolSystemEnv "git" gitparams (gitEnv repo)
else forM_ (getFiles action) $ \f -> else forM_ (getFiles action) $ \(f, check) ->
void $ boolSystemEnv "git" (gitparams ++ [f]) (gitEnv repo) whenM check $
void $ boolSystemEnv "git" (gitparams ++ [File f]) (gitEnv repo)
#endif #endif
where where
gitparams = gitCommandLine gitparams = gitCommandLine

View file

@ -27,19 +27,21 @@ data CommandParam
-- | Used to pass a list of CommandParams to a function that runs -- | Used to pass a list of CommandParams to a function that runs
-- a command and expects Strings. -} -- a command and expects Strings. -}
toCommand :: [CommandParam] -> [String] 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 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 -- '/' is explicitly included because it's an alternative
-- path separator on Windows. -- path separator on Windows.
pathseps = pathSeparator:"./" pathseps = pathSeparator:"./"
toCommand' (File s) = s
-- | Run a system command, and returns True or False if it succeeded or failed. -- | Run a system command, and returns True or False if it succeeded or failed.
-- --