be36e208c2
When a nonexistant file is passed to a command and --json-error-messages is enabled, output a JSON object indicating the problem. (But git ls-files --error-unmatch still displays errors about such files in some situations.) I don't like the duplication of the name of the command introduced by this, but I can't see a great way around it. One way would be to pass the Command instead. When json is not enabled, the stderr is unchanged. This is necessary because some commands like find have custom output. So dislaying "find foo not found" would be wrong. So had to complicate things with toplevelFileProblem having different output with and without json. When not using --json-error-messages but still using --json, it displays the error to stderr, but does display a json object without the error. It does have an errorid though. Unsure how useful that behavior is. Sponsored-by: Dartmouth College's Datalad project
95 lines
2.9 KiB
Haskell
95 lines
2.9 KiB
Haskell
{- git-annex command
|
|
-
|
|
- Copyright 2010-2023 Joey Hess <id@joeyh.name>
|
|
-
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
|
-}
|
|
|
|
module Command.Copy where
|
|
|
|
import Command
|
|
import qualified Command.Move
|
|
import qualified Remote
|
|
import Annex.Wanted
|
|
import Annex.NumCopies
|
|
|
|
cmd :: Command
|
|
cmd = withAnnexOptions [jobsOption, jsonOptions, jsonProgressOption, annexedMatchingOptions] $
|
|
command "copy" SectionCommon
|
|
"copy content of files to/from another repository"
|
|
paramPaths (seek <--< optParser)
|
|
|
|
data CopyOptions = CopyOptions
|
|
{ copyFiles :: CmdParams
|
|
, fromToOptions :: Maybe FromToHereOptions
|
|
, keyOptions :: Maybe KeyOptions
|
|
, autoMode :: Bool
|
|
, batchOption :: BatchMode
|
|
}
|
|
|
|
optParser :: CmdParamsDesc -> Parser CopyOptions
|
|
optParser desc = CopyOptions
|
|
<$> cmdParams desc
|
|
<*> parseFromToHereOptions
|
|
<*> optional (parseKeyOptions <|> parseFailedTransfersOption)
|
|
<*> parseAutoOption
|
|
<*> parseBatchOption True
|
|
|
|
instance DeferredParseClass CopyOptions where
|
|
finishParse v = CopyOptions
|
|
<$> pure (copyFiles v)
|
|
<*> maybe (pure Nothing) (Just <$$> finishParse)
|
|
(fromToOptions v)
|
|
<*> pure (keyOptions v)
|
|
<*> pure (autoMode v)
|
|
<*> pure (batchOption v)
|
|
|
|
seek :: CopyOptions -> CommandSeek
|
|
seek o = case fromToOptions o of
|
|
Just fto -> seek' o fto
|
|
Nothing -> giveup "Specify --from or --to"
|
|
|
|
seek' :: CopyOptions -> FromToHereOptions -> CommandSeek
|
|
seek' o fto = startConcurrency (Command.Move.stages fto) $ do
|
|
case batchOption o of
|
|
NoBatch -> withKeyOptions
|
|
(keyOptions o) (autoMode o) seeker
|
|
(commandAction . keyaction)
|
|
(withFilesInGitAnnex ww seeker)
|
|
=<< workTreeItems ww (copyFiles o)
|
|
Batch fmt -> batchOnly (keyOptions o) (copyFiles o) $
|
|
batchAnnexed fmt seeker keyaction
|
|
where
|
|
ww = WarnUnmatchLsFiles "copy"
|
|
|
|
seeker = AnnexedFileSeeker
|
|
{ startAction = start o fto
|
|
, checkContentPresent = case fto of
|
|
FromOrToRemote (FromRemote _) -> Just False
|
|
FromOrToRemote (ToRemote _) -> Just True
|
|
ToHere -> Just False
|
|
FromRemoteToRemote _ _ -> Just False
|
|
, usesLocationLog = True
|
|
}
|
|
keyaction = Command.Move.startKey fto Command.Move.RemoveNever
|
|
|
|
{- A copy is just a move that does not delete the source file.
|
|
- However, auto mode avoids unnecessary copies, and avoids getting or
|
|
- sending non-preferred content. -}
|
|
start :: CopyOptions -> FromToHereOptions -> SeekInput -> RawFilePath -> Key -> CommandStart
|
|
start o fto si file key = stopUnless shouldCopy $
|
|
Command.Move.start fto Command.Move.RemoveNever si file key
|
|
where
|
|
shouldCopy
|
|
| autoMode o = want <||> numCopiesCheck file key (<)
|
|
| otherwise = return True
|
|
want = case fto of
|
|
FromOrToRemote (ToRemote dest) ->
|
|
(Remote.uuid <$> getParsed dest) >>= checkwantsend
|
|
FromOrToRemote (FromRemote _) -> checkwantget
|
|
ToHere -> checkwantget
|
|
FromRemoteToRemote _ dest ->
|
|
(Remote.uuid <$> getParsed dest) >>= checkwantsend
|
|
|
|
checkwantsend = wantGetBy False (Just key) (AssociatedFile (Just file))
|
|
checkwantget = wantGet False (Just key) (AssociatedFile (Just file))
|