a6c1d9752b
Allowing --from and --to as an alternative to --from or --to is hard to do with optparse-applicative! The obvious approach of (pfrom <|> pto <|> pfromandto) does not work when pfromandto uses the same option names as pfrom and pto do. It compiles but the generated parser does not work for all desired combinations. Instead, have to parse optionally from and optionally to. When neither is provided, the parser succeeds, but it's a result that can't be handled. So, have to giveup after option parsing. There does not seem to be a way to make an optparse-applicative Parser give up internally either. Also, need seek' because I first tried making fto be a where binding, but that resulted in a hang when git-annex move was run without --from or --to. I think because startConcurrency was not expecting the stages value to contain an exception and so ended up blocking. Sponsored-by: Dartmouth College's DANDI 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 commandStages $ 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
|
|
|
|
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))
|