git-annex/Command/Move.hs

148 lines
4.5 KiB
Haskell
Raw Normal View History

{- git-annex command
-
- Copyright 2010 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Command.Move where
2011-10-05 20:02:51 +00:00
import Common.Annex
import Command
2010-11-11 22:54:52 +00:00
import qualified Command.Drop
import qualified Annex
2011-10-04 04:40:47 +00:00
import Annex.Content
import qualified Remote
import Annex.UUID
def :: [Command]
def = [dontCheck toOpt $ dontCheck fromOpt $
command "move" paramPaths seek
"move content of files to/from another repository"]
seek :: [CommandSeek]
seek = [withFilesInGit $ whenAnnexed $ start True]
2010-11-11 22:54:52 +00:00
2010-11-27 21:02:53 +00:00
{- Move (or copy) a file either --to or --from a repository.
-
- This only operates on the cached file content; it does not involve
- moving data in the key-value backend. -}
start :: Bool -> FilePath -> (Key, Backend Annex) -> CommandStart
start move file (key, _) = do
noAuto
to <- Annex.getState Annex.toremote
from <- Annex.getState Annex.fromremote
case (from, to) of
(Nothing, Nothing) -> error "specify either --from or --to"
(Nothing, Just name) -> do
dest <- Remote.byName name
2011-11-11 02:37:52 +00:00
toStart dest move file key
(Just name, Nothing) -> do
src <- Remote.byName name
2011-11-11 02:37:52 +00:00
fromStart src move file key
(_ , _) -> error "only one of --from or --to can be specified"
where
noAuto = when move $ whenM (Annex.getState Annex.auto) $ error
"--auto is not supported for move"
showMoveAction :: Bool -> FilePath -> Annex ()
showMoveAction True file = showStart "move" file
showMoveAction False file = showStart "copy" file
2010-11-27 21:02:53 +00:00
{- Moves (or copies) the content of an annexed file to a remote.
-
- If the remote already has the content, it is still removed from
- the current repository.
-
- Note that unlike drop, this does not honor annex.numcopies.
- A file's content can be moved even if there are insufficient copies to
- allow it to be dropped.
-}
2011-11-11 02:37:52 +00:00
toStart :: Remote.Remote Annex -> Bool -> FilePath -> Key -> CommandStart
toStart dest move file key = do
2011-10-11 18:43:45 +00:00
u <- getUUID
ishere <- inAnnex key
if not ishere || u == Remote.uuid dest
2011-05-15 06:02:46 +00:00
then stop -- not here, so nothing to do
else do
showMoveAction move file
2011-05-15 06:02:46 +00:00
next $ toPerform dest move key
toPerform :: Remote.Remote Annex -> Bool -> Key -> CommandPerform
toPerform dest move key = moveLock move key $ do
-- Checking the remote is expensive, so not done in the start step.
-- In fast mode, location tracking is assumed to be correct,
-- and an explicit check is not done, when copying. When moving,
-- it has to be done, to avoid inaverdent data loss.
fast <- Annex.getState Annex.fast
let fastcheck = fast && not move && not (Remote.hasKeyCheap dest)
isthere <- if fastcheck
then do
2011-06-23 17:39:04 +00:00
remotes <- Remote.keyPossibilities key
return $ Right $ dest `elem` remotes
else Remote.hasKey dest key
case isthere of
Left err -> do
showNote $ err
2011-05-15 06:02:46 +00:00
stop
Right False -> do
showAction $ "to " ++ Remote.name dest
ok <- Remote.storeKey dest key
2010-11-22 21:51:55 +00:00
if ok
then finish
else do
when fastcheck $
warning "This could have failed because --fast is enabled."
stop
Right True -> finish
where
finish = do
Remote.logStatus dest key True
if move
then do
whenM (inAnnex key) $ removeAnnex key
next $ Command.Drop.cleanupLocal key
else next $ return True
{- Moves (or copies) the content of an annexed file from a remote
- to the current repository.
-
- If the current repository already has the content, it is still removed
- from the remote.
-}
2011-11-11 02:37:52 +00:00
fromStart :: Remote.Remote Annex -> Bool -> FilePath -> Key -> CommandStart
fromStart src move file key
| move == True = go
| otherwise = do
ishere <- inAnnex key
2011-11-11 02:37:52 +00:00
if ishere then stop else go
where
2011-11-11 02:37:52 +00:00
go = do
u <- getUUID
remotes <- Remote.keyPossibilities key
if u == Remote.uuid src || not (any (== src) remotes)
then stop
else do
showMoveAction move file
next $ fromPerform src move key
fromPerform :: Remote.Remote Annex -> Bool -> Key -> CommandPerform
fromPerform src move key = moveLock move key $ do
ishere <- inAnnex key
2010-11-22 21:51:55 +00:00
if ishere
then handle move True
else do
showAction $ "from " ++ Remote.name src
ok <- getViaTmp key $ Remote.retrieveKeyFile src key
handle move ok
where
handle _ False = stop -- failed
handle False True = next $ return True -- copy complete
handle True True = do -- finish moving
ok <- Remote.removeKey src key
next $ Command.Drop.cleanupRemote key src ok
{- Locks a key in order for it to be moved.
- No lock is needed when a key is being copied. -}
moveLock :: Bool -> Key -> Annex a -> Annex a
moveLock True key a = lockContent key a
moveLock False _ a = a