2010-11-27 21:09:22 +00:00
|
|
|
{- git-annex command
|
|
|
|
-
|
2023-01-18 18:42:39 +00:00
|
|
|
- Copyright 2010-2023 Joey Hess <id@joeyh.name>
|
2010-11-27 21:09:22 +00:00
|
|
|
-
|
2019-03-13 19:48:14 +00:00
|
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
2010-11-27 21:09:22 +00:00
|
|
|
-}
|
|
|
|
|
|
|
|
module Command.Copy where
|
|
|
|
|
|
|
|
import Command
|
|
|
|
import qualified Command.Move
|
2012-01-06 08:02:35 +00:00
|
|
|
import qualified Remote
|
2012-10-08 20:06:56 +00:00
|
|
|
import Annex.Wanted
|
2015-04-30 18:02:56 +00:00
|
|
|
import Annex.NumCopies
|
2010-11-27 21:09:22 +00:00
|
|
|
|
2015-07-08 16:33:27 +00:00
|
|
|
cmd :: Command
|
2022-06-29 17:28:08 +00:00
|
|
|
cmd = withAnnexOptions [jobsOption, jsonOptions, jsonProgressOption, annexedMatchingOptions] $
|
2015-07-30 17:33:35 +00:00
|
|
|
command "copy" SectionCommon
|
|
|
|
"copy content of files to/from another repository"
|
|
|
|
paramPaths (seek <--< optParser)
|
2015-07-09 19:23:14 +00:00
|
|
|
|
|
|
|
data CopyOptions = CopyOptions
|
2018-04-09 18:38:46 +00:00
|
|
|
{ copyFiles :: CmdParams
|
2023-01-18 18:42:39 +00:00
|
|
|
, fromToOptions :: Maybe FromToHereOptions
|
2018-04-09 18:38:46 +00:00
|
|
|
, keyOptions :: Maybe KeyOptions
|
2015-07-09 19:23:14 +00:00
|
|
|
, autoMode :: Bool
|
2018-04-09 18:38:46 +00:00
|
|
|
, batchOption :: BatchMode
|
2015-07-09 19:23:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
optParser :: CmdParamsDesc -> Parser CopyOptions
|
|
|
|
optParser desc = CopyOptions
|
2018-04-09 18:38:46 +00:00
|
|
|
<$> cmdParams desc
|
|
|
|
<*> parseFromToHereOptions
|
|
|
|
<*> optional (parseKeyOptions <|> parseFailedTransfersOption)
|
2015-07-09 19:23:14 +00:00
|
|
|
<*> parseAutoOption
|
2021-08-25 18:20:33 +00:00
|
|
|
<*> parseBatchOption True
|
2015-07-09 19:23:14 +00:00
|
|
|
|
|
|
|
instance DeferredParseClass CopyOptions where
|
|
|
|
finishParse v = CopyOptions
|
2018-04-09 18:38:46 +00:00
|
|
|
<$> pure (copyFiles v)
|
2023-01-18 18:42:39 +00:00
|
|
|
<*> maybe (pure Nothing) (Just <$$> finishParse)
|
|
|
|
(fromToOptions v)
|
2018-04-09 18:38:46 +00:00
|
|
|
<*> pure (keyOptions v)
|
2015-07-09 19:23:14 +00:00
|
|
|
<*> pure (autoMode v)
|
2018-04-09 18:38:46 +00:00
|
|
|
<*> pure (batchOption v)
|
2015-07-09 19:23:14 +00:00
|
|
|
|
|
|
|
seek :: CopyOptions -> CommandSeek
|
2023-01-18 18:42:39 +00:00
|
|
|
seek o = case fromToOptions o of
|
|
|
|
Just fto -> seek' o fto
|
|
|
|
Nothing -> giveup "Specify --from or --to"
|
|
|
|
|
|
|
|
seek' :: CopyOptions -> FromToHereOptions -> CommandSeek
|
2023-01-24 18:03:26 +00:00
|
|
|
seek' o fto = startConcurrency (Command.Move.stages fto) $ do
|
2018-04-09 18:38:46 +00:00
|
|
|
case batchOption o of
|
2017-08-15 16:39:10 +00:00
|
|
|
NoBatch -> withKeyOptions
|
2020-07-24 16:05:28 +00:00
|
|
|
(keyOptions o) (autoMode o) seeker
|
2021-08-25 18:20:33 +00:00
|
|
|
(commandAction . keyaction)
|
2020-07-13 21:04:02 +00:00
|
|
|
(withFilesInGitAnnex ww seeker)
|
2020-05-28 19:55:17 +00:00
|
|
|
=<< workTreeItems ww (copyFiles o)
|
2022-01-26 16:59:55 +00:00
|
|
|
Batch fmt -> batchOnly (keyOptions o) (copyFiles o) $
|
|
|
|
batchAnnexed fmt seeker keyaction
|
2020-05-28 19:55:17 +00:00
|
|
|
where
|
2023-04-25 23:26:20 +00:00
|
|
|
ww = WarnUnmatchLsFiles "copy"
|
2020-07-22 18:23:28 +00:00
|
|
|
|
|
|
|
seeker = AnnexedFileSeeker
|
2023-12-06 17:04:32 +00:00
|
|
|
{ startAction = const $ start o fto
|
2023-01-18 18:42:39 +00:00
|
|
|
, checkContentPresent = case fto of
|
|
|
|
FromOrToRemote (FromRemote _) -> Just False
|
|
|
|
FromOrToRemote (ToRemote _) -> Just True
|
|
|
|
ToHere -> Just False
|
2023-11-17 20:30:20 +00:00
|
|
|
FromRemoteToRemote _ _ -> Nothing
|
copy/move --from-anywhere --to remote
Implementation was simple because it's equivilant to
--from=foo --to remote for each other remote, followed by
--to remote when there's a local copy.
(Or, in the edge case of --from-anywhere --to=here,
it's the same as --to=here.)
Note that, when the local repo does not have a copy,
fromToPerform gets it from a remote, sends it to the destination,
and drops the local copy. Another call to that for a second remote
will notice that the dest now has a copy, and simply drop from the
second remote, avoiding a second transfer.
Also note that, when numcopies doesn't allow dropping it from
everywhere, it will drop it from the cheapest remotes first
(maybe not ideal) up to more expensive remotes, and finally from the local
repo. So the local repo will generally end up holding a copy. Maybe not
ideal in all cases either, but it seems no worse to do that than to end up
with a copy undropped from a remote.
And I'm not entirely happy with the output, eg:
copy bigfile (from r3...) ok
copy bigfile ok
That makes sense if you think of the second line as being
the same as what is output by `git-annex copy bigfile --to bar`,
but it's less clear in this context. Maybe add "(from here...)"?
Also the --json output doesn't have a machine-readable field for
the "from" uuid, and maybe it should?
Sponsored-by: Dartmouth College's DANDI project
2023-11-30 20:32:32 +00:00
|
|
|
FromAnywhereToRemote _ -> Nothing
|
2020-07-24 16:56:02 +00:00
|
|
|
, usesLocationLog = True
|
2020-07-22 18:23:28 +00:00
|
|
|
}
|
2023-01-18 18:42:39 +00:00
|
|
|
keyaction = Command.Move.startKey fto Command.Move.RemoveNever
|
2011-09-15 19:27:45 +00:00
|
|
|
|
2012-10-08 20:06:56 +00:00
|
|
|
{- A copy is just a move that does not delete the source file.
|
2015-03-25 21:06:14 +00:00
|
|
|
- However, auto mode avoids unnecessary copies, and avoids getting or
|
2012-10-08 20:06:56 +00:00
|
|
|
- sending non-preferred content. -}
|
2023-01-18 18:42:39 +00:00
|
|
|
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
|
2012-11-12 05:05:04 +00:00
|
|
|
where
|
2015-03-25 21:06:14 +00:00
|
|
|
shouldCopy
|
2020-11-03 14:11:04 +00:00
|
|
|
| autoMode o = want <||> numCopiesCheck file key (<)
|
2015-03-25 21:06:14 +00:00
|
|
|
| otherwise = return True
|
2023-01-18 18:42:39 +00:00
|
|
|
want = case fto of
|
copy/move --from-anywhere --to remote
Implementation was simple because it's equivilant to
--from=foo --to remote for each other remote, followed by
--to remote when there's a local copy.
(Or, in the edge case of --from-anywhere --to=here,
it's the same as --to=here.)
Note that, when the local repo does not have a copy,
fromToPerform gets it from a remote, sends it to the destination,
and drops the local copy. Another call to that for a second remote
will notice that the dest now has a copy, and simply drop from the
second remote, avoiding a second transfer.
Also note that, when numcopies doesn't allow dropping it from
everywhere, it will drop it from the cheapest remotes first
(maybe not ideal) up to more expensive remotes, and finally from the local
repo. So the local repo will generally end up holding a copy. Maybe not
ideal in all cases either, but it seems no worse to do that than to end up
with a copy undropped from a remote.
And I'm not entirely happy with the output, eg:
copy bigfile (from r3...) ok
copy bigfile ok
That makes sense if you think of the second line as being
the same as what is output by `git-annex copy bigfile --to bar`,
but it's less clear in this context. Maybe add "(from here...)"?
Also the --json output doesn't have a machine-readable field for
the "from" uuid, and maybe it should?
Sponsored-by: Dartmouth College's DANDI project
2023-11-30 20:32:32 +00:00
|
|
|
FromOrToRemote (ToRemote dest) -> checkwantsend dest
|
2023-01-18 18:42:39 +00:00
|
|
|
FromOrToRemote (FromRemote _) -> checkwantget
|
|
|
|
ToHere -> checkwantget
|
copy/move --from-anywhere --to remote
Implementation was simple because it's equivilant to
--from=foo --to remote for each other remote, followed by
--to remote when there's a local copy.
(Or, in the edge case of --from-anywhere --to=here,
it's the same as --to=here.)
Note that, when the local repo does not have a copy,
fromToPerform gets it from a remote, sends it to the destination,
and drops the local copy. Another call to that for a second remote
will notice that the dest now has a copy, and simply drop from the
second remote, avoiding a second transfer.
Also note that, when numcopies doesn't allow dropping it from
everywhere, it will drop it from the cheapest remotes first
(maybe not ideal) up to more expensive remotes, and finally from the local
repo. So the local repo will generally end up holding a copy. Maybe not
ideal in all cases either, but it seems no worse to do that than to end up
with a copy undropped from a remote.
And I'm not entirely happy with the output, eg:
copy bigfile (from r3...) ok
copy bigfile ok
That makes sense if you think of the second line as being
the same as what is output by `git-annex copy bigfile --to bar`,
but it's less clear in this context. Maybe add "(from here...)"?
Also the --json output doesn't have a machine-readable field for
the "from" uuid, and maybe it should?
Sponsored-by: Dartmouth College's DANDI project
2023-11-30 20:32:32 +00:00
|
|
|
FromRemoteToRemote _ dest -> checkwantsend dest
|
|
|
|
FromAnywhereToRemote dest -> checkwantsend dest
|
|
|
|
|
|
|
|
checkwantsend dest =
|
|
|
|
(Remote.uuid <$> getParsed dest) >>=
|
|
|
|
wantGetBy False (Just key) (AssociatedFile (Just file))
|
move --to=here
* move --to=here moves from all reachable remotes to the local repository.
The output of move --from remote is changed slightly, when the remote and
local both have the content. It used to say:
move foo ok
Now:
move foo (from theremote...) ok
That was done so that, when move --to=here is used and the content is
locally present and also in several remotes, it's clear which remotes the
content gets dropped from.
Note that move --to=here will report an error if a non-reachable remote
contains the file, even if the local repository also contains the file. I
think that's reasonable; the user may be intending to move all other copies
of the file from remotes.
OTOH, if a copy of the file is believed to be present in some repository
that is not a configured remote, move --to=here does not report an error.
So a little bit inconsistent, but erroring in this case feels wrong.
copy --to=here came along for free, but it's basically the same behavior as
git-annex get, and probably with not as good messages in edge cases
(especially on failure), so I've not documented it.
This commit was sponsored by Anthony DeRobertis on Patreon.
2017-05-31 20:57:27 +00:00
|
|
|
checkwantget = wantGet False (Just key) (AssociatedFile (Just file))
|