fully working move --from --to (not release quality)

When the destination already has a copy, it behaves the same as
drop --from really, but display it as a move and implement it
reusing the factored out code from fromPerform.

(Note that willDropMakeItWorse never returns DropAllowed in that
situation, because it's told that dest has a copy. So numcopies is
always checked.)

And when only the source and not the local repo or destination have a
copy, do the full copy from source to local, then copy from local to
dest, then drop from local, then drop from source dance.

This is complicated by fromPerform being hardcoded to assume there is a
local copy, but the local copy has already been dropped. That's why
it uses cleanupfromsrc RemoveNever to avoid the code that makes that
assumption, and finishes with a call to dropfromsrc.

And, since the location log has not yet been updated, checking numcopies
was not working, until I added UnVerifiedRemote dest to the list of
things to check.

This is not yet quite mergeable though. There are two things in the
comment above fromToPerform that are not implemented yet: Checking the
location log before dropping the local copy, and locking the temporary
local copy for drop.

Sponsored-by: Dartmouth College's DANDI project
This commit is contained in:
Joey Hess 2023-01-23 15:36:06 -04:00
parent 1abd457e98
commit f5f799f17e
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38

View file

@ -247,43 +247,53 @@ fromOk src key
fromPerform :: Remote -> RemoveWhen -> Key -> AssociatedFile -> CommandPerform fromPerform :: Remote -> RemoveWhen -> Key -> AssociatedFile -> CommandPerform
fromPerform src removewhen key afile = do fromPerform src removewhen key afile = do
present <- inAnnex key present <- inAnnex key
fromPerform' present src removewhen key afile finish <- fromPerform' present True src key afile
finish removewhen
fromPerform' :: Bool -> Remote -> RemoveWhen -> Key -> AssociatedFile -> CommandPerform fromPerform' :: Bool -> Bool -> Remote -> Key -> AssociatedFile -> Annex (RemoveWhen -> CommandPerform)
fromPerform' present src removewhen key afile = do fromPerform' present updatelocationlog src key afile = do
showAction $ "from " ++ Remote.name src showAction $ "from " ++ Remote.name src
destuuid <- getUUID destuuid <- getUUID
logMove srcuuid destuuid present key $ \deststartedwithcopy -> logMove (Remote.uuid src) destuuid present key $ \deststartedwithcopy ->
if present if present
then dispatch removewhen deststartedwithcopy True then return $ finish deststartedwithcopy True
else dispatch removewhen deststartedwithcopy =<< get else do
got <- get
return $ finish deststartedwithcopy got
where where
get = notifyTransfer Download afile $ get = notifyTransfer Download afile $
logStatusAfter key . logdownload .
download src key afile stdRetry download src key afile stdRetry
dispatch _ deststartedwithcopy False = do logdownload a
| updatelocationlog = logStatusAfter key a
| otherwise = a
finish deststartedwithcopy False _ = do
logMoveCleanup deststartedwithcopy logMoveCleanup deststartedwithcopy
stop -- copy failed stop -- copy failed
dispatch RemoveNever deststartedwithcopy True = do finish deststartedwithcopy True RemoveNever = do
logMoveCleanup deststartedwithcopy logMoveCleanup deststartedwithcopy
next $ return True -- copy complete next $ return True -- copy complete
dispatch RemoveSafe deststartedwithcopy True = lockContentShared key $ \_lck -> do finish deststartedwithcopy True RemoveSafe = do
destuuid <- getUUID destuuid <- getUUID
willDropMakeItWorse srcuuid destuuid deststartedwithcopy key afile >>= \case lockContentShared key $ \_lck ->
DropAllowed -> dropremote deststartedwithcopy "moved" fromDrop src destuuid deststartedwithcopy key afile id
fromDrop :: Remote -> UUID -> DestStartedWithCopy -> Key -> AssociatedFile -> ([UnVerifiedCopy] -> [UnVerifiedCopy])-> CommandPerform
fromDrop src destuuid deststartedwithcopy key afile adjusttocheck =
willDropMakeItWorse (Remote.uuid src) destuuid deststartedwithcopy key afile >>= \case
DropAllowed -> dropremote "moved"
DropCheckNumCopies -> do DropCheckNumCopies -> do
(numcopies, mincopies) <- getSafestNumMinCopies afile key (numcopies, mincopies) <- getSafestNumMinCopies afile key
(tocheck, verified) <- verifiableCopies key [Remote.uuid src] (tocheck, verified) <- verifiableCopies key [Remote.uuid src]
verifyEnoughCopiesToDrop "" key Nothing numcopies mincopies [Remote.uuid src] verified verifyEnoughCopiesToDrop "" key Nothing numcopies mincopies [Remote.uuid src] verified
tocheck (dropremote deststartedwithcopy . showproof) (faileddropremote deststartedwithcopy) (adjusttocheck tocheck) (dropremote . showproof) faileddropremote
DropWorse -> faileddropremote deststartedwithcopy DropWorse -> faileddropremote
where
srcuuid = Remote.uuid src
showproof proof = "proof: " ++ show proof showproof proof = "proof: " ++ show proof
dropremote deststartedwithcopy reason = do dropremote reason = do
fastDebug "Command.Move" $ unwords fastDebug "Command.Move" $ unwords
[ "Dropping from remote" [ "Dropping from remote"
, show src , show src
@ -294,7 +304,7 @@ fromPerform' present src removewhen key afile = do
logMoveCleanup deststartedwithcopy logMoveCleanup deststartedwithcopy
next $ Command.Drop.cleanupRemote key src (Command.Drop.DroppingUnused False) ok next $ Command.Drop.cleanupRemote key src (Command.Drop.DroppingUnused False) ok
faileddropremote deststartedwithcopy = do faileddropremote = do
showLongNote "(Use --force to override this check, or adjust numcopies.)" showLongNote "(Use --force to override this check, or adjust numcopies.)"
showLongNote $ "Content not dropped from " ++ Remote.name src ++ "." showLongNote $ "Content not dropped from " ++ Remote.name src ++ "."
logMoveCleanup deststartedwithcopy logMoveCleanup deststartedwithcopy
@ -330,6 +340,8 @@ fromToStart removewhen afile key ai si src dest = do
fromToPerform src dest removewhen key afile fromToPerform src dest removewhen key afile
{- When there is a local copy, transfer it to the dest, and drop from the src. {- When there is a local copy, transfer it to the dest, and drop from the src.
-
- When the dest has a copy, drop it from the src.
- -
- Otherwise, download a copy from the dest, populating the local annex - Otherwise, download a copy from the dest, populating the local annex
- copy, but not updating location logs. Then transfer that to the dest, - copy, but not updating location logs. Then transfer that to the dest,
@ -358,32 +370,70 @@ fromToStart removewhen afile key ai si src dest = do
- downloading it (v10) or immediately after download (v9 or older). - downloading it (v10) or immediately after download (v9 or older).
-} -}
fromToPerform :: Remote -> Remote -> RemoveWhen -> Key -> AssociatedFile -> CommandPerform fromToPerform :: Remote -> Remote -> RemoveWhen -> Key -> AssociatedFile -> CommandPerform
fromToPerform src dest removewhen key afile = do fromToPerform src dest removewhen key afile = go =<< inAnnex key
present <- inAnnex key
if present
then gopresent
else do
showAction $ "from " ++ Remote.name src
downloadsrctotemp
sendtemptodest
dropfromsrc
showAction $ "to " ++ Remote.name dest
error "TODO"
where where
sendlocaltodest = error "TODO" go True = do
downloadsrctotemp = error "TODO"
sendtemptodest = error "TODO"
dropfromsrc = error "TODO"
gopresent = do
haskey <- Remote.hasKey dest key haskey <- Remote.hasKey dest key
toPerform dest RemoveNever key afile False haskey >>= \case -- Prepare to drop from src later. Doing this first
Just cleanup -> fromPerform' True src removewhen key afile >>= \case -- makes "from src" be shown consistently before
Just cleanup' -> return $ Just $ do -- "to dest"
ok <- cleanup dropsrc <- fromsrc True
ok' <- cleanup' combinecleanups
return (ok && ok') -- Send to dest, preserve local copy.
Nothing -> return $ Just cleanup (todest RemoveNever haskey)
(\senttodest -> if senttodest
then dropsrc removewhen
else stop
)
go False = do
haskey <- Remote.hasKey dest key
case haskey of
Left err -> do
showNote err
stop
Right True -> do
showAction $ "from " ++ Remote.name src
showAction $ "to " ++ Remote.name dest
-- Drop from src, checking copies including
-- the one already in dest.
dropfromsrc id
Right False -> do
-- Get local copy from src, defer dropping
-- from src until later.
cleanupfromsrc <- fromsrc False
combinecleanups
-- Send to dest and remove local copy.
(todest RemoveSafe haskey)
(\senttodest ->
-- Drop from src, checking
-- copies including dest.
combinecleanups
(cleanupfromsrc RemoveNever)
(\_ -> if senttodest
then dropfromsrc (\l -> UnVerifiedRemote dest : l)
else stop
)
)
fromsrc present = fromPerform' present False src key afile
todest removewhen' = toPerform dest removewhen' key afile False
dropfromsrc adjusttocheck =
logMove (Remote.uuid src) (Remote.uuid dest) True key $ \deststartedwithcopy ->
fromDrop src (Remote.uuid dest) deststartedwithcopy key afile adjusttocheck
combinecleanups a b = a >>= \case
Just cleanupa -> b True >>= \case
Just cleanupb -> return $ Just $ do
oka <- cleanupa
okb <- cleanupb
return (oka && okb)
Nothing -> return (Just cleanupa)
Nothing -> b False >>= \case
Just cleanupb -> return $ Just $ do
void cleanupb
return False
Nothing -> return Nothing Nothing -> return Nothing
{- The goal of this command is to allow the user maximum freedom to move {- The goal of this command is to allow the user maximum freedom to move
@ -395,9 +445,10 @@ fromToPerform src dest removewhen key afile = do
- repository reduces the number of copies, and should fail if - repository reduces the number of copies, and should fail if
- that would violate numcopies settings. - that would violate numcopies settings.
- -
- On the other hand, when the destination repository does not already - On the other hand, when the destination repository did not start
- have a copy of a file, it can be dropped without making numcopies - with a copy of a file, it can be dropped from the source without
- worse, so the move is allowed even if numcopies is not met. - making numcopies worse, so the move is allowed even if numcopies
- is not met.
- -
- Similarly, a file can move from an untrusted repository to another - Similarly, a file can move from an untrusted repository to another
- untrusted repository, even if that is the only copy of the file. - untrusted repository, even if that is the only copy of the file.