git-annex/Command/Mirror.hs
Joey Hess 3a14648142
dropping unused marks as dead
Dropping an object with drop --unused or dropunused will mark it as
dead, preventing fsck --all from complaining about it after it's been
dropped from all repositories.

If another repository still has a copy, it won't be treated as dead
until it's also dropped from there.

The drop has to use --unused, can't be --key or something else, because
this indicates that the user has recently ran git-annex unused. If it
checked the unused log on every drop, bad things would happen when the
unused log was out of date, eg a file used to be unused but then got
re-added. Marking such a file as dead could be confusing. When the user
uses --unused/dropunused, they must consider the unused information to be
up-to-date.

The particular workflow this enables is:

	git annex add foo
	git annex unannex foo
	git annex unused
	git annex drop --unused / dropunused
	git annex fsck --all # no warnings

The docs for git-annex unannex say to use git-annex unused and dropunused,
so the user should be pointed in this direction when they want to undo an
accidental add.

Sponsored-by: Brock Spratlen on Patreon
2021-06-25 15:22:26 -04:00

90 lines
2.8 KiB
Haskell

{- git-annex command
-
- Copyright 2013 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
module Command.Mirror where
import Command
import qualified Command.Move
import qualified Command.Drop
import qualified Command.Get
import qualified Remote
import Annex.Content
import Annex.NumCopies
import Types.Transfer
cmd :: Command
cmd = withGlobalOptions [jobsOption, jsonOptions, jsonProgressOption, annexedMatchingOptions] $
command "mirror" SectionCommon
"mirror content of files to/from another repository"
paramPaths (seek <--< optParser)
data MirrorOptions = MirrorOptions
{ mirrorFiles :: CmdParams
, fromToOptions :: FromToOptions
, keyOptions :: Maybe KeyOptions
}
optParser :: CmdParamsDesc -> Parser MirrorOptions
optParser desc = MirrorOptions
<$> cmdParams desc
<*> parseFromToOptions
<*> optional (parseKeyOptions <|> parseFailedTransfersOption)
instance DeferredParseClass MirrorOptions where
finishParse v = MirrorOptions
<$> pure (mirrorFiles v)
<*> finishParse (fromToOptions v)
<*> pure (keyOptions v)
seek :: MirrorOptions -> CommandSeek
seek o = startConcurrency stages $
withKeyOptions (keyOptions o) False seeker
(commandAction . startKey o (AssociatedFile Nothing))
(withFilesInGitAnnex ww seeker)
=<< workTreeItems ww (mirrorFiles o)
where
stages = case fromToOptions o of
FromRemote _ -> downloadStages
ToRemote _ -> commandStages
ww = WarnUnmatchLsFiles
seeker = AnnexedFileSeeker
{ startAction = start o
, checkContentPresent = Nothing
, usesLocationLog = True
}
start :: MirrorOptions -> SeekInput -> RawFilePath -> Key -> CommandStart
start o si file k = startKey o afile (si, k, ai)
where
afile = AssociatedFile (Just file)
ai = mkActionItem (k, afile)
startKey :: MirrorOptions -> AssociatedFile -> (SeekInput, Key, ActionItem) -> CommandStart
startKey o afile (si, key, ai) = case fromToOptions o of
ToRemote r -> checkFailedTransferDirection ai Upload $ ifM (inAnnex key)
( Command.Move.toStart Command.Move.RemoveNever afile key ai si =<< getParsed r
, do
(numcopies, mincopies) <- getSafestNumMinCopies afile key
Command.Drop.startRemote pcc afile ai si numcopies mincopies key (Command.Drop.DroppingUnused False)
=<< getParsed r
)
FromRemote r -> checkFailedTransferDirection ai Download $ do
haskey <- flip Remote.hasKey key =<< getParsed r
case haskey of
Left _ -> stop
Right True -> ifM (inAnnex key)
( stop
, Command.Get.start' (return True) Nothing key afile ai si
)
Right False -> ifM (inAnnex key)
( do
(numcopies, mincopies) <- getSafestNumMinCopies afile key
Command.Drop.startLocal pcc afile ai si numcopies mincopies key [] (Command.Drop.DroppingUnused False)
, stop
)
where
pcc = Command.Drop.PreferredContentChecked False