Merge branch 'starting'
This commit is contained in:
commit
502ce3f243
85 changed files with 810 additions and 708 deletions
5
Annex.hs
5
Annex.hs
|
@ -142,7 +142,7 @@ data AnnexState = AnnexState
|
||||||
, tempurls :: M.Map Key URLString
|
, tempurls :: M.Map Key URLString
|
||||||
, existinghooks :: M.Map Git.Hook.Hook Bool
|
, existinghooks :: M.Map Git.Hook.Hook Bool
|
||||||
, desktopnotify :: DesktopNotify
|
, desktopnotify :: DesktopNotify
|
||||||
, workers :: WorkerPool AnnexState
|
, workers :: TMVar (WorkerPool AnnexState)
|
||||||
, activekeys :: TVar (M.Map Key ThreadId)
|
, activekeys :: TVar (M.Map Key ThreadId)
|
||||||
, activeremotes :: MVar (M.Map (Types.Remote.RemoteA Annex) Integer)
|
, activeremotes :: MVar (M.Map (Types.Remote.RemoteA Annex) Integer)
|
||||||
, keysdbhandle :: Maybe Keys.DbHandle
|
, keysdbhandle :: Maybe Keys.DbHandle
|
||||||
|
@ -155,6 +155,7 @@ newState :: GitConfig -> Git.Repo -> IO AnnexState
|
||||||
newState c r = do
|
newState c r = do
|
||||||
emptyactiveremotes <- newMVar M.empty
|
emptyactiveremotes <- newMVar M.empty
|
||||||
emptyactivekeys <- newTVarIO M.empty
|
emptyactivekeys <- newTVarIO M.empty
|
||||||
|
emptyworkerpool <- newTMVarIO UnallocatedWorkerPool
|
||||||
o <- newMessageState
|
o <- newMessageState
|
||||||
sc <- newTMVarIO False
|
sc <- newTMVarIO False
|
||||||
return $ AnnexState
|
return $ AnnexState
|
||||||
|
@ -199,7 +200,7 @@ newState c r = do
|
||||||
, tempurls = M.empty
|
, tempurls = M.empty
|
||||||
, existinghooks = M.empty
|
, existinghooks = M.empty
|
||||||
, desktopnotify = mempty
|
, desktopnotify = mempty
|
||||||
, workers = UnallocatedWorkerPool
|
, workers = emptyworkerpool
|
||||||
, activekeys = emptyactivekeys
|
, activekeys = emptyactivekeys
|
||||||
, activeremotes = emptyactiveremotes
|
, activeremotes = emptyactiveremotes
|
||||||
, keysdbhandle = Nothing
|
, keysdbhandle = Nothing
|
||||||
|
|
|
@ -11,7 +11,6 @@ import Annex
|
||||||
import Annex.Common
|
import Annex.Common
|
||||||
import Annex.Action
|
import Annex.Action
|
||||||
import qualified Annex.Queue
|
import qualified Annex.Queue
|
||||||
import Types.WorkerPool
|
|
||||||
|
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
|
||||||
|
@ -43,9 +42,8 @@ dupState :: Annex AnnexState
|
||||||
dupState = do
|
dupState = do
|
||||||
st <- Annex.getState id
|
st <- Annex.getState id
|
||||||
return $ st
|
return $ st
|
||||||
{ Annex.workers = UnallocatedWorkerPool
|
|
||||||
-- each thread has its own repoqueue
|
-- each thread has its own repoqueue
|
||||||
, Annex.repoqueue = Nothing
|
{ Annex.repoqueue = Nothing
|
||||||
-- avoid sharing eg, open file handles
|
-- avoid sharing eg, open file handles
|
||||||
, Annex.catfilehandles = M.empty
|
, Annex.catfilehandles = M.empty
|
||||||
, Annex.checkattrhandle = Nothing
|
, Annex.checkattrhandle = Nothing
|
||||||
|
|
|
@ -47,8 +47,8 @@ type Reason = String
|
||||||
- In direct mode, all associated files are checked, and only if all
|
- In direct mode, all associated files are checked, and only if all
|
||||||
- of them are unwanted are they dropped.
|
- of them are unwanted are they dropped.
|
||||||
-
|
-
|
||||||
- The runner is used to run commands, and so can be either callCommand
|
- The runner is used to run CommandStart sequentially, it's typically
|
||||||
- or commandAction.
|
- callCommandAction.
|
||||||
-}
|
-}
|
||||||
handleDropsFrom :: [UUID] -> [Remote] -> Reason -> Bool -> Key -> AssociatedFile -> [VerifiedCopy] -> (CommandStart -> CommandCleanup) -> Annex ()
|
handleDropsFrom :: [UUID] -> [Remote] -> Reason -> Bool -> Key -> AssociatedFile -> [VerifiedCopy] -> (CommandStart -> CommandCleanup) -> Annex ()
|
||||||
handleDropsFrom locs rs reason fromhere key afile preverified runner = do
|
handleDropsFrom locs rs reason fromhere key afile preverified runner = do
|
||||||
|
|
|
@ -326,11 +326,11 @@ downloadImport remote importtreeconfig importablecontents = do
|
||||||
(k:_) -> return $ Left $ Just (loc, k)
|
(k:_) -> return $ Left $ Just (loc, k)
|
||||||
[] -> do
|
[] -> do
|
||||||
job <- liftIO $ newEmptyTMVarIO
|
job <- liftIO $ newEmptyTMVarIO
|
||||||
let downloadaction = do
|
let ai = ActionItemOther (Just (fromImportLocation loc))
|
||||||
showStart ("import " ++ Remote.name remote) (fromImportLocation loc)
|
let downloadaction = starting ("import " ++ Remote.name remote) ai $ do
|
||||||
when oldversion $
|
when oldversion $
|
||||||
showNote "old version"
|
showNote "old version"
|
||||||
next $ tryNonAsync (download cidmap db i) >>= \case
|
tryNonAsync (download cidmap db i) >>= \case
|
||||||
Left e -> next $ do
|
Left e -> next $ do
|
||||||
warning (show e)
|
warning (show e)
|
||||||
liftIO $ atomically $
|
liftIO $ atomically $
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
git-annex (7.20190616) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
|
* When running multiple concurrent actions, the cleanup phase is run
|
||||||
|
in a separate queue than the main action queue. This can make some
|
||||||
|
commands faster, because less time is spent on bookkeeping in
|
||||||
|
between each file transfer.
|
||||||
|
|
||||||
|
-- Joey Hess <id@joeyh.name> Sat, 15 Jun 2019 12:38:25 -0400
|
||||||
|
|
||||||
git-annex (7.20190615) upstream; urgency=medium
|
git-annex (7.20190615) upstream; urgency=medium
|
||||||
|
|
||||||
* Fixed bug that caused git-annex to fail to add a file when another
|
* Fixed bug that caused git-annex to fail to add a file when another
|
||||||
|
|
|
@ -122,10 +122,8 @@ findCmd fuzzyok argv cmds
|
||||||
|
|
||||||
prepRunCommand :: Command -> GlobalSetter -> Annex ()
|
prepRunCommand :: Command -> GlobalSetter -> Annex ()
|
||||||
prepRunCommand cmd globalconfig = do
|
prepRunCommand cmd globalconfig = do
|
||||||
when (cmdnomessages cmd) $ do
|
when (cmdnomessages cmd) $
|
||||||
Annex.setOutput QuietOutput
|
Annex.setOutput QuietOutput
|
||||||
Annex.changeState $ \s -> s
|
|
||||||
{ Annex.output = (Annex.output s) { implicitMessages = False } }
|
|
||||||
getParsed globalconfig
|
getParsed globalconfig
|
||||||
whenM (annexDebug <$> Annex.getGitConfig) $
|
whenM (annexDebug <$> Annex.getGitConfig) $
|
||||||
liftIO enableDebugOutput
|
liftIO enableDebugOutput
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{- git-annex command-line actions
|
{- git-annex command-line actions and concurrency
|
||||||
-
|
-
|
||||||
- Copyright 2010-2017 Joey Hess <id@joeyh.name>
|
- Copyright 2010-2019 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU AGPL version 3 or higher.
|
- Licensed under the GNU AGPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
|
||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP, BangPatterns #-}
|
||||||
|
|
||||||
module CmdLine.Action where
|
module CmdLine.Action where
|
||||||
|
|
||||||
|
@ -22,9 +22,7 @@ import Remote.List
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
import Control.Concurrent.Async
|
import Control.Concurrent.Async
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
import Control.Exception (throwIO)
|
|
||||||
import GHC.Conc
|
import GHC.Conc
|
||||||
import Data.Either
|
|
||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
import qualified System.Console.Regions as Regions
|
import qualified System.Console.Regions as Regions
|
||||||
|
|
||||||
|
@ -43,130 +41,219 @@ performCommandAction Command { cmdcheck = c, cmdname = name } seek cont = do
|
||||||
showerrcount 0 = noop
|
showerrcount 0 = noop
|
||||||
showerrcount cnt = giveup $ name ++ ": " ++ show cnt ++ " failed"
|
showerrcount cnt = giveup $ name ++ ": " ++ show cnt ++ " failed"
|
||||||
|
|
||||||
|
commandActions :: [CommandStart] -> Annex ()
|
||||||
|
commandActions = mapM_ commandAction
|
||||||
|
|
||||||
{- Runs one of the actions needed to perform a command.
|
{- Runs one of the actions needed to perform a command.
|
||||||
- Individual actions can fail without stopping the whole command,
|
- Individual actions can fail without stopping the whole command,
|
||||||
- including by throwing non-async exceptions.
|
- including by throwing non-async exceptions.
|
||||||
-
|
-
|
||||||
- When concurrency is enabled, a thread is forked off to run the action
|
- When concurrency is enabled, a thread is forked off to run the action
|
||||||
- in the background, as soon as a free slot is available.
|
- in the background, as soon as a free worker slot is available.
|
||||||
|
|
||||||
- This should only be run in the seek stage.
|
- This should only be run in the seek stage.
|
||||||
-}
|
-}
|
||||||
commandAction :: CommandStart -> Annex ()
|
commandAction :: CommandStart -> Annex ()
|
||||||
commandAction a = Annex.getState Annex.concurrency >>= \case
|
commandAction start = Annex.getState Annex.concurrency >>= \case
|
||||||
NonConcurrent -> run
|
NonConcurrent -> void $ includeCommandAction start
|
||||||
Concurrent n -> runconcurrent n
|
Concurrent n -> runconcurrent n
|
||||||
ConcurrentPerCpu -> runconcurrent =<< liftIO getNumProcessors
|
ConcurrentPerCpu -> runconcurrent =<< liftIO getNumProcessors
|
||||||
where
|
where
|
||||||
run = void $ includeCommandAction a
|
|
||||||
|
|
||||||
runconcurrent n = do
|
runconcurrent n = do
|
||||||
ws <- liftIO . drainTo (n-1) =<< Annex.getState Annex.workers
|
tv <- Annex.getState Annex.workers
|
||||||
(st, ws') <- case ws of
|
workerst <- waitWorkerSlot n (== PerformStage) tv
|
||||||
UnallocatedWorkerPool -> do
|
aid <- liftIO $ async $ snd <$> Annex.run workerst
|
||||||
-- Generate the remote list now, to avoid
|
(concurrentjob workerst)
|
||||||
-- each thread generating it, which would
|
liftIO $ atomically $ do
|
||||||
-- be more expensive and could cause
|
pool <- takeTMVar tv
|
||||||
-- threads to contend over eg, calls to
|
let !pool' = addWorkerPool (ActiveWorker aid PerformStage) pool
|
||||||
-- setConfig.
|
putTMVar tv pool'
|
||||||
_ <- remoteList
|
void $ liftIO $ forkIO $ do
|
||||||
st <- dupState
|
-- accountCommandAction will usually catch
|
||||||
return (st, allocateWorkerPool st (n-1))
|
-- exceptions. Just in case, fall back to the
|
||||||
WorkerPool l -> findFreeSlot l
|
-- original workerst.
|
||||||
w <- liftIO $ async $ snd <$> Annex.run st
|
workerst' <- either (const workerst) id
|
||||||
(inOwnConsoleRegion (Annex.output st) run)
|
<$> waitCatch aid
|
||||||
Annex.changeState $ \s -> s
|
atomically $ do
|
||||||
{ Annex.workers = addWorkerPool ws' (Right w) }
|
pool <- takeTMVar tv
|
||||||
|
let !pool' = deactivateWorker pool aid workerst'
|
||||||
|
putTMVar tv pool'
|
||||||
|
|
||||||
commandActions :: [CommandStart] -> Annex ()
|
concurrentjob workerst = start >>= \case
|
||||||
commandActions = mapM_ commandAction
|
Nothing -> noop
|
||||||
|
Just (startmsg, perform) ->
|
||||||
|
concurrentjob' workerst startmsg perform
|
||||||
|
|
||||||
{- Waits for any forked off command actions to finish.
|
concurrentjob' workerst startmsg perform = case mkActionItem startmsg of
|
||||||
-
|
OnlyActionOn k _ -> ensureOnlyActionOn k $
|
||||||
- Merge together the cleanup actions of all the AnnexStates used by
|
-- If another job performed the same action while we
|
||||||
- threads, into the current Annex's state, so they'll run at shutdown.
|
-- waited, there may be nothing left to do, so re-run
|
||||||
-
|
-- the start stage to see if it still wants to do
|
||||||
- Also merge together the errcounters of the AnnexStates.
|
-- something.
|
||||||
|
start >>= \case
|
||||||
|
Just (startmsg', perform') ->
|
||||||
|
case mkActionItem startmsg' of
|
||||||
|
OnlyActionOn k' _ | k' /= k ->
|
||||||
|
concurrentjob' workerst startmsg' perform'
|
||||||
|
_ -> mkjob workerst startmsg' perform'
|
||||||
|
Nothing -> noop
|
||||||
|
_ -> mkjob workerst startmsg perform
|
||||||
|
|
||||||
|
mkjob workerst startmsg perform =
|
||||||
|
inOwnConsoleRegion (Annex.output workerst) $
|
||||||
|
void $ accountCommandAction startmsg $
|
||||||
|
performconcurrent startmsg perform
|
||||||
|
|
||||||
|
-- Like performCommandAction' but the worker thread's stage
|
||||||
|
-- is changed before starting the cleanup action.
|
||||||
|
performconcurrent startmsg perform = do
|
||||||
|
showStartMessage startmsg
|
||||||
|
perform >>= \case
|
||||||
|
Just cleanup -> do
|
||||||
|
changeStageTo CleanupStage
|
||||||
|
r <- cleanup
|
||||||
|
showEndMessage startmsg r
|
||||||
|
return r
|
||||||
|
Nothing -> do
|
||||||
|
showEndMessage startmsg False
|
||||||
|
return False
|
||||||
|
|
||||||
|
-- | Wait until there's an idle worker in the pool, remove it from the
|
||||||
|
-- pool, and return its state.
|
||||||
|
--
|
||||||
|
-- If the pool is unallocated, it will be allocated to the specified size.
|
||||||
|
waitWorkerSlot :: Int -> (WorkerStage -> Bool) -> TMVar (WorkerPool Annex.AnnexState) -> Annex (Annex.AnnexState)
|
||||||
|
waitWorkerSlot n wantstage tv =
|
||||||
|
join $ liftIO $ atomically $ waitWorkerSlot' wantstage tv >>= \case
|
||||||
|
Nothing -> return $ do
|
||||||
|
-- Generate the remote list now, to avoid
|
||||||
|
-- each thread generating it, which would
|
||||||
|
-- be more expensive and could cause
|
||||||
|
-- threads to contend over eg, calls to
|
||||||
|
-- setConfig.
|
||||||
|
_ <- remoteList
|
||||||
|
st <- dupState
|
||||||
|
liftIO $ atomically $ do
|
||||||
|
let (WorkerPool l) = allocateWorkerPool st (max n 1)
|
||||||
|
let (st', pool) = findidle st [] l
|
||||||
|
void $ swapTMVar tv pool
|
||||||
|
return st'
|
||||||
|
Just st -> return $ return st
|
||||||
|
where
|
||||||
|
findidle st _ [] = (st, WorkerPool [])
|
||||||
|
findidle _ c ((IdleWorker st stage):rest)
|
||||||
|
| wantstage stage = (st, WorkerPool (c ++ rest))
|
||||||
|
findidle st c (w:rest) = findidle st (w:c) rest
|
||||||
|
|
||||||
|
-- | STM action that waits until there's an idle worker in the worker pool.
|
||||||
|
--
|
||||||
|
-- If the worker pool is not already allocated, returns Nothing.
|
||||||
|
waitWorkerSlot' :: (WorkerStage -> Bool) -> TMVar (WorkerPool Annex.AnnexState) -> STM (Maybe (Annex.AnnexState))
|
||||||
|
waitWorkerSlot' wantstage tv =
|
||||||
|
takeTMVar tv >>= \case
|
||||||
|
UnallocatedWorkerPool -> do
|
||||||
|
putTMVar tv UnallocatedWorkerPool
|
||||||
|
return Nothing
|
||||||
|
WorkerPool l -> do
|
||||||
|
(st, pool') <- findidle [] l
|
||||||
|
putTMVar tv pool'
|
||||||
|
return $ Just st
|
||||||
|
where
|
||||||
|
findidle _ [] = retry
|
||||||
|
findidle c ((IdleWorker st stage):rest)
|
||||||
|
| wantstage stage = return (st, WorkerPool (c ++ rest))
|
||||||
|
findidle c (w:rest) = findidle (w:c) rest
|
||||||
|
|
||||||
|
{- Waits for all worker threads to finish and merges their AnnexStates
|
||||||
|
- back into the current Annex's state.
|
||||||
-}
|
-}
|
||||||
finishCommandActions :: Annex ()
|
finishCommandActions :: Annex ()
|
||||||
finishCommandActions = do
|
finishCommandActions = do
|
||||||
ws <- Annex.getState Annex.workers
|
tv <- Annex.getState Annex.workers
|
||||||
Annex.changeState $ \s -> s { Annex.workers = UnallocatedWorkerPool }
|
pool <- liftIO $ atomically $
|
||||||
ws' <- liftIO $ drainTo 0 ws
|
swapTMVar tv UnallocatedWorkerPool
|
||||||
forM_ (idleWorkers ws') mergeState
|
case pool of
|
||||||
|
UnallocatedWorkerPool -> noop
|
||||||
|
WorkerPool l -> forM_ (mapMaybe workerAsync l) $ \aid ->
|
||||||
|
liftIO (waitCatch aid) >>= \case
|
||||||
|
Left _ -> noop
|
||||||
|
Right st -> mergeState st
|
||||||
|
|
||||||
{- Wait for jobs from the WorkerPool to complete, until
|
{- Changes the current thread's stage in the worker pool.
|
||||||
- the number of running jobs is not larger than the specified number.
|
|
||||||
-
|
-
|
||||||
- If a job throws an exception, it is propigated, but first
|
- The pool needs to continue to contain the same number of worker threads
|
||||||
- all other jobs are waited for, to allow for a clean shutdown.
|
- for each stage. So, an idle worker with the desired stage is found in
|
||||||
|
- the pool (waiting if necessary for one to become idle), and the stages
|
||||||
|
- of it and the current thread are swapped.
|
||||||
-}
|
-}
|
||||||
drainTo :: Int -> WorkerPool t -> IO (WorkerPool t)
|
changeStageTo :: WorkerStage -> Annex ()
|
||||||
drainTo _ UnallocatedWorkerPool = pure UnallocatedWorkerPool
|
changeStageTo newstage = do
|
||||||
drainTo sz (WorkerPool l)
|
mytid <- liftIO myThreadId
|
||||||
| null as || sz >= length as = pure (WorkerPool l)
|
tv <- Annex.getState Annex.workers
|
||||||
| otherwise = do
|
liftIO $ atomically $ waitWorkerSlot' (== newstage) tv >>= \case
|
||||||
(done, ret) <- waitAnyCatch as
|
Just idlest -> do
|
||||||
let as' = filter (/= done) as
|
pool <- takeTMVar tv
|
||||||
case ret of
|
let pool' = case removeThreadIdWorkerPool mytid pool of
|
||||||
Left e -> do
|
Just ((myaid, oldstage), p) ->
|
||||||
void $ drainTo 0 $ WorkerPool $
|
addWorkerPool (IdleWorker idlest oldstage) $
|
||||||
map Left sts ++ map Right as'
|
addWorkerPool (ActiveWorker myaid newstage) p
|
||||||
throwIO e
|
Nothing -> pool
|
||||||
Right st -> do
|
putTMVar tv pool'
|
||||||
drainTo sz $ WorkerPool $
|
-- No worker pool is allocated, not running in concurrent
|
||||||
map Left (st:sts) ++ map Right as'
|
-- mode.
|
||||||
where
|
Nothing -> noop
|
||||||
(sts, as) = partitionEithers l
|
|
||||||
|
|
||||||
findFreeSlot :: [Worker Annex.AnnexState] -> Annex (Annex.AnnexState, WorkerPool Annex.AnnexState)
|
|
||||||
findFreeSlot = go []
|
|
||||||
where
|
|
||||||
go c [] = do
|
|
||||||
st <- dupState
|
|
||||||
return (st, WorkerPool c)
|
|
||||||
go c (Left st:rest) = return (st, WorkerPool (c ++ rest))
|
|
||||||
go c (v:rest) = go (v:c) rest
|
|
||||||
|
|
||||||
{- Like commandAction, but without the concurrency. -}
|
{- Like commandAction, but without the concurrency. -}
|
||||||
includeCommandAction :: CommandStart -> CommandCleanup
|
includeCommandAction :: CommandStart -> CommandCleanup
|
||||||
includeCommandAction a = account =<< tryNonAsync (callCommandAction a)
|
includeCommandAction start =
|
||||||
where
|
start >>= \case
|
||||||
account (Right True) = return True
|
Nothing -> return True
|
||||||
account (Right False) = incerr
|
Just (startmsg, perform) -> do
|
||||||
account (Left err) = case fromException err of
|
showStartMessage startmsg
|
||||||
|
accountCommandAction startmsg $
|
||||||
|
performCommandAction' startmsg perform
|
||||||
|
|
||||||
|
accountCommandAction :: StartMessage -> CommandCleanup -> CommandCleanup
|
||||||
|
accountCommandAction startmsg cleanup = tryNonAsync cleanup >>= \case
|
||||||
|
Right True -> return True
|
||||||
|
Right False -> incerr
|
||||||
|
Left err -> case fromException err of
|
||||||
Just exitcode -> liftIO $ exitWith exitcode
|
Just exitcode -> liftIO $ exitWith exitcode
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
toplevelWarning True (show err)
|
toplevelWarning True (show err)
|
||||||
implicitMessage showEndFail
|
showEndMessage startmsg False
|
||||||
incerr
|
incerr
|
||||||
|
where
|
||||||
incerr = do
|
incerr = do
|
||||||
Annex.incError
|
Annex.incError
|
||||||
return False
|
return False
|
||||||
|
|
||||||
{- Runs a single command action through the start, perform and cleanup
|
{- Runs a single command action through the start, perform and cleanup
|
||||||
- stages, without catching errors. Useful if one command wants to run
|
- stages, without catching errors and without incrementing error counter.
|
||||||
- part of another command. -}
|
- Useful if one command wants to run part of another command. -}
|
||||||
callCommandAction :: CommandStart -> CommandCleanup
|
callCommandAction :: CommandStart -> CommandCleanup
|
||||||
callCommandAction = fromMaybe True <$$> callCommandAction'
|
callCommandAction = fromMaybe True <$$> callCommandAction'
|
||||||
|
|
||||||
{- Like callCommandAction, but returns Nothing when the command did not
|
{- Like callCommandAction, but returns Nothing when the command did not
|
||||||
- perform any action. -}
|
- perform any action. -}
|
||||||
callCommandAction' :: CommandStart -> Annex (Maybe Bool)
|
callCommandAction' :: CommandStart -> Annex (Maybe Bool)
|
||||||
callCommandAction' a = callCommandActionQuiet a >>= \case
|
callCommandAction' start =
|
||||||
Nothing -> return Nothing
|
start >>= \case
|
||||||
Just r -> implicitMessage (showEndResult r) >> return (Just r)
|
Nothing -> return Nothing
|
||||||
|
Just (startmsg, perform) -> do
|
||||||
|
showStartMessage startmsg
|
||||||
|
Just <$> performCommandAction' startmsg perform
|
||||||
|
|
||||||
callCommandActionQuiet :: CommandStart -> Annex (Maybe Bool)
|
performCommandAction' :: StartMessage -> CommandPerform -> CommandCleanup
|
||||||
callCommandActionQuiet = start
|
performCommandAction' startmsg perform =
|
||||||
where
|
perform >>= \case
|
||||||
start = stage $ maybe skip perform
|
Nothing -> do
|
||||||
perform = stage $ maybe failure cleanup
|
showEndMessage startmsg False
|
||||||
cleanup = stage $ status
|
return False
|
||||||
stage = (=<<)
|
Just cleanup -> do
|
||||||
skip = return Nothing
|
r <- cleanup
|
||||||
failure = return (Just False)
|
showEndMessage startmsg r
|
||||||
status = return . Just
|
return r
|
||||||
|
|
||||||
{- Do concurrent output when that has been requested. -}
|
{- Do concurrent output when that has been requested. -}
|
||||||
allowConcurrentOutput :: Annex a -> Annex a
|
allowConcurrentOutput :: Annex a -> Annex a
|
||||||
|
@ -214,18 +301,12 @@ allowConcurrentOutput a = do
|
||||||
liftIO $ setNumCapabilities n
|
liftIO $ setNumCapabilities n
|
||||||
|
|
||||||
{- Ensures that only one thread processes a key at a time.
|
{- Ensures that only one thread processes a key at a time.
|
||||||
- Other threads will block until it's done. -}
|
- Other threads will block until it's done.
|
||||||
onlyActionOn :: Key -> CommandStart -> CommandStart
|
-
|
||||||
onlyActionOn k a = onlyActionOn' k run
|
- May be called repeatedly by the same thread without blocking. -}
|
||||||
where
|
ensureOnlyActionOn :: Key -> Annex a -> Annex a
|
||||||
-- Run whole action, not just start stage, so other threads
|
ensureOnlyActionOn k a =
|
||||||
-- block until it's done.
|
go =<< Annex.getState Annex.concurrency
|
||||||
run = callCommandActionQuiet a >>= \case
|
|
||||||
Nothing -> return Nothing
|
|
||||||
Just r' -> return $ Just $ return $ Just $ return r'
|
|
||||||
|
|
||||||
onlyActionOn' :: Key -> Annex a -> Annex a
|
|
||||||
onlyActionOn' k a = go =<< Annex.getState Annex.concurrency
|
|
||||||
where
|
where
|
||||||
go NonConcurrent = a
|
go NonConcurrent = a
|
||||||
go (Concurrent _) = goconcurrent
|
go (Concurrent _) = goconcurrent
|
||||||
|
@ -240,7 +321,7 @@ onlyActionOn' k a = go =<< Annex.getState Annex.concurrency
|
||||||
case M.lookup k m of
|
case M.lookup k m of
|
||||||
Just tid
|
Just tid
|
||||||
| tid /= mytid -> retry
|
| tid /= mytid -> retry
|
||||||
| otherwise -> return (return ())
|
| otherwise -> return $ return ()
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
writeTVar tv $! M.insert k mytid m
|
writeTVar tv $! M.insert k mytid m
|
||||||
return $ liftIO $ atomically $
|
return $ liftIO $ atomically $
|
||||||
|
|
|
@ -24,7 +24,6 @@ import qualified Limit
|
||||||
import CmdLine.GitAnnex.Options
|
import CmdLine.GitAnnex.Options
|
||||||
import Logs.Location
|
import Logs.Location
|
||||||
import Logs.Unused
|
import Logs.Unused
|
||||||
import Types.ActionItem
|
|
||||||
import Types.Transfer
|
import Types.Transfer
|
||||||
import Logs.Transfer
|
import Logs.Transfer
|
||||||
import Remote.List
|
import Remote.List
|
||||||
|
|
39
Command.hs
39
Command.hs
|
@ -1,6 +1,6 @@
|
||||||
{- git-annex command infrastructure
|
{- git-annex command infrastructure
|
||||||
-
|
-
|
||||||
- Copyright 2010-2016 Joey Hess <id@joeyh.name>
|
- Copyright 2010-2019 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU AGPL version 3 or higher.
|
- Licensed under the GNU AGPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
@ -22,14 +22,12 @@ import CmdLine.GlobalSetter as ReExported
|
||||||
import CmdLine.GitAnnex.Options as ReExported
|
import CmdLine.GitAnnex.Options as ReExported
|
||||||
import CmdLine.Batch as ReExported
|
import CmdLine.Batch as ReExported
|
||||||
import Options.Applicative as ReExported hiding (command)
|
import Options.Applicative as ReExported hiding (command)
|
||||||
import qualified Annex
|
|
||||||
import qualified Git
|
import qualified Git
|
||||||
import Annex.Init
|
import Annex.Init
|
||||||
import Config
|
import Config
|
||||||
import Utility.Daemon
|
import Utility.Daemon
|
||||||
import Types.Transfer
|
import Types.Transfer
|
||||||
import Types.ActionItem
|
import Types.ActionItem
|
||||||
import Types.Messages
|
|
||||||
|
|
||||||
{- Generates a normal Command -}
|
{- Generates a normal Command -}
|
||||||
command :: String -> CommandSection -> String -> CmdParamsDesc -> (CmdParamsDesc -> CommandParser) -> Command
|
command :: String -> CommandSection -> String -> CmdParamsDesc -> (CmdParamsDesc -> CommandParser) -> Command
|
||||||
|
@ -61,19 +59,11 @@ noCommit c = c { cmdnocommit = True }
|
||||||
- starting or stopping processing a file or other item. Unless --json mode
|
- starting or stopping processing a file or other item. Unless --json mode
|
||||||
- is enabled, this also enables quiet output mode, so only things
|
- is enabled, this also enables quiet output mode, so only things
|
||||||
- explicitly output by the command are shown and not progress messages
|
- explicitly output by the command are shown and not progress messages
|
||||||
- etc. -}
|
- etc.
|
||||||
|
-}
|
||||||
noMessages :: Command -> Command
|
noMessages :: Command -> Command
|
||||||
noMessages c = c { cmdnomessages = True }
|
noMessages c = c { cmdnomessages = True }
|
||||||
|
|
||||||
{- Undoes noMessages -}
|
|
||||||
allowMessages :: Annex ()
|
|
||||||
allowMessages = do
|
|
||||||
outputType <$> Annex.getState Annex.output >>= \case
|
|
||||||
QuietOutput -> Annex.setOutput NormalOutput
|
|
||||||
_ -> noop
|
|
||||||
Annex.changeState $ \s -> s
|
|
||||||
{ Annex.output = (Annex.output s) { implicitMessages = True } }
|
|
||||||
|
|
||||||
{- Adds a fallback action to a command, that will be run if it's used
|
{- Adds a fallback action to a command, that will be run if it's used
|
||||||
- outside a git repository. -}
|
- outside a git repository. -}
|
||||||
noRepo :: (String -> Parser (IO ())) -> Command -> Command
|
noRepo :: (String -> Parser (IO ())) -> Command -> Command
|
||||||
|
@ -83,11 +73,30 @@ noRepo a c = c { cmdnorepo = Just (a (cmdparamdesc c)) }
|
||||||
withGlobalOptions :: [[GlobalOption]] -> Command -> Command
|
withGlobalOptions :: [[GlobalOption]] -> Command -> Command
|
||||||
withGlobalOptions os c = c { cmdglobaloptions = cmdglobaloptions c ++ concat os }
|
withGlobalOptions os c = c { cmdglobaloptions = cmdglobaloptions c ++ concat os }
|
||||||
|
|
||||||
{- For start and perform stages to indicate what step to run next. -}
|
{- For start stage to indicate what will be done. -}
|
||||||
|
starting:: MkActionItem t => String -> t -> CommandPerform -> CommandStart
|
||||||
|
starting msg t a = next (StartMessage msg (mkActionItem t), a)
|
||||||
|
|
||||||
|
{- Use when noMessages was used but the command is going to output
|
||||||
|
- usual messages after all. -}
|
||||||
|
startingUsualMessages :: MkActionItem t => String -> t -> CommandPerform -> CommandStart
|
||||||
|
startingUsualMessages msg t a = next (StartUsualMessages msg (mkActionItem t), a)
|
||||||
|
|
||||||
|
{- When no message should be displayed at start/end, but messages can still
|
||||||
|
- be displayed when using eg includeCommandAction. -}
|
||||||
|
startingNoMessage :: MkActionItem t => t -> CommandPerform -> CommandStart
|
||||||
|
startingNoMessage t a = next (StartNoMessage (mkActionItem t), a)
|
||||||
|
|
||||||
|
{- For commands that do not display usual start or end messages,
|
||||||
|
- but have some other custom output. -}
|
||||||
|
startingCustomOutput :: MkActionItem t => t -> CommandPerform -> CommandStart
|
||||||
|
startingCustomOutput t a = next (CustomOutput (mkActionItem t), a)
|
||||||
|
|
||||||
|
{- For perform stage to indicate what step to run next. -}
|
||||||
next :: a -> Annex (Maybe a)
|
next :: a -> Annex (Maybe a)
|
||||||
next a = return $ Just a
|
next a = return $ Just a
|
||||||
|
|
||||||
{- Or to indicate nothing needs to be done. -}
|
{- For start and perform stage to indicate nothing needs to be done. -}
|
||||||
stop :: Annex (Maybe a)
|
stop :: Annex (Maybe a)
|
||||||
stop = return Nothing
|
stop = return Nothing
|
||||||
|
|
||||||
|
|
|
@ -78,9 +78,8 @@ seek o = allowConcurrentOutput $ do
|
||||||
|
|
||||||
{- Pass file off to git-add. -}
|
{- Pass file off to git-add. -}
|
||||||
startSmall :: FilePath -> CommandStart
|
startSmall :: FilePath -> CommandStart
|
||||||
startSmall file = do
|
startSmall file = starting "add" (ActionItemWorkTreeFile file) $
|
||||||
showStart "add" file
|
next $ addSmall file
|
||||||
next $ next $ addSmall file
|
|
||||||
|
|
||||||
addSmall :: FilePath -> Annex Bool
|
addSmall :: FilePath -> Annex Bool
|
||||||
addSmall file = do
|
addSmall file = do
|
||||||
|
@ -107,11 +106,11 @@ start file = do
|
||||||
Nothing -> stop
|
Nothing -> stop
|
||||||
Just s
|
Just s
|
||||||
| not (isRegularFile s) && not (isSymbolicLink s) -> stop
|
| not (isRegularFile s) && not (isSymbolicLink s) -> stop
|
||||||
| otherwise -> do
|
| otherwise ->
|
||||||
showStart "add" file
|
starting "add" (ActionItemWorkTreeFile file) $
|
||||||
next $ if isSymbolicLink s
|
if isSymbolicLink s
|
||||||
then next $ addFile file
|
then next $ addFile file
|
||||||
else perform file
|
else perform file
|
||||||
addpresent key = ifM versionSupportsUnlockedPointers
|
addpresent key = ifM versionSupportsUnlockedPointers
|
||||||
( liftIO (catchMaybeIO $ getSymbolicLinkStatus file) >>= \case
|
( liftIO (catchMaybeIO $ getSymbolicLinkStatus file) >>= \case
|
||||||
Just s | isSymbolicLink s -> fixuplink key
|
Just s | isSymbolicLink s -> fixuplink key
|
||||||
|
@ -124,18 +123,16 @@ start file = do
|
||||||
, fixuplink key
|
, fixuplink key
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fixuplink key = do
|
fixuplink key = starting "add" (ActionItemWorkTreeFile file) $ do
|
||||||
-- the annexed symlink is present but not yet added to git
|
-- the annexed symlink is present but not yet added to git
|
||||||
showStart "add" file
|
|
||||||
liftIO $ removeFile file
|
liftIO $ removeFile file
|
||||||
addLink file key Nothing
|
addLink file key Nothing
|
||||||
next $ next $
|
next $
|
||||||
cleanup key =<< inAnnex key
|
cleanup key =<< inAnnex key
|
||||||
fixuppointer key = do
|
fixuppointer key = starting "add" (ActionItemWorkTreeFile file) $ do
|
||||||
-- the pointer file is present, but not yet added to git
|
-- the pointer file is present, but not yet added to git
|
||||||
showStart "add" file
|
|
||||||
Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file)
|
Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file)
|
||||||
next $ next $ addFile file
|
next $ addFile file
|
||||||
|
|
||||||
perform :: FilePath -> CommandPerform
|
perform :: FilePath -> CommandPerform
|
||||||
perform file = withOtherTmp $ \tmpdir -> do
|
perform file = withOtherTmp $ \tmpdir -> do
|
||||||
|
|
|
@ -124,10 +124,9 @@ checkUrl r o u = do
|
||||||
(Remote.checkUrl r)
|
(Remote.checkUrl r)
|
||||||
where
|
where
|
||||||
|
|
||||||
go _ (Left e) = void $ commandAction $ do
|
go _ (Left e) = void $ commandAction $ startingAddUrl u o $ do
|
||||||
showStartAddUrl u o
|
|
||||||
warning (show e)
|
warning (show e)
|
||||||
next $ next $ return False
|
next $ return False
|
||||||
go deffile (Right (UrlContents sz mf)) = do
|
go deffile (Right (UrlContents sz mf)) = do
|
||||||
let f = adjustFile o (fromMaybe (maybe deffile fromSafeFilePath mf) (fileOption (downloadOptions o)))
|
let f = adjustFile o (fromMaybe (maybe deffile fromSafeFilePath mf) (fileOption (downloadOptions o)))
|
||||||
void $ commandAction $ startRemote r o f u sz
|
void $ commandAction $ startRemote r o f u sz
|
||||||
|
@ -151,10 +150,10 @@ startRemote :: Remote -> AddUrlOptions -> FilePath -> URLString -> Maybe Integer
|
||||||
startRemote r o file uri sz = do
|
startRemote r o file uri sz = do
|
||||||
pathmax <- liftIO $ fileNameLengthLimit "."
|
pathmax <- liftIO $ fileNameLengthLimit "."
|
||||||
let file' = joinPath $ map (truncateFilePath pathmax) $ splitDirectories file
|
let file' = joinPath $ map (truncateFilePath pathmax) $ splitDirectories file
|
||||||
showStartAddUrl uri o
|
startingAddUrl uri o $ do
|
||||||
showNote $ "from " ++ Remote.name r
|
showNote $ "from " ++ Remote.name r
|
||||||
showDestinationFile file'
|
showDestinationFile file'
|
||||||
next $ performRemote r o uri file' sz
|
performRemote r o uri file' sz
|
||||||
|
|
||||||
performRemote :: Remote -> AddUrlOptions -> URLString -> FilePath -> Maybe Integer -> CommandPerform
|
performRemote :: Remote -> AddUrlOptions -> URLString -> FilePath -> Maybe Integer -> CommandPerform
|
||||||
performRemote r o uri file sz = ifAnnexed file adduri geturi
|
performRemote r o uri file sz = ifAnnexed file adduri geturi
|
||||||
|
@ -194,8 +193,7 @@ startWeb o urlstring = go $ fromMaybe bad $ parseURI urlstring
|
||||||
where
|
where
|
||||||
bad = fromMaybe (giveup $ "bad url " ++ urlstring) $
|
bad = fromMaybe (giveup $ "bad url " ++ urlstring) $
|
||||||
Url.parseURIRelaxed $ urlstring
|
Url.parseURIRelaxed $ urlstring
|
||||||
go url = do
|
go url = startingAddUrl urlstring o $ do
|
||||||
showStartAddUrl urlstring o
|
|
||||||
pathmax <- liftIO $ fileNameLengthLimit "."
|
pathmax <- liftIO $ fileNameLengthLimit "."
|
||||||
urlinfo <- if relaxedOption (downloadOptions o)
|
urlinfo <- if relaxedOption (downloadOptions o)
|
||||||
then pure Url.assumeUrlExists
|
then pure Url.assumeUrlExists
|
||||||
|
@ -212,7 +210,7 @@ startWeb o urlstring = go $ fromMaybe bad $ parseURI urlstring
|
||||||
( pure $ url2file url (pathdepthOption o) pathmax
|
( pure $ url2file url (pathdepthOption o) pathmax
|
||||||
, pure f
|
, pure f
|
||||||
)
|
)
|
||||||
next $ performWeb o urlstring file urlinfo
|
performWeb o urlstring file urlinfo
|
||||||
|
|
||||||
performWeb :: AddUrlOptions -> URLString -> FilePath -> Url.UrlInfo -> CommandPerform
|
performWeb :: AddUrlOptions -> URLString -> FilePath -> Url.UrlInfo -> CommandPerform
|
||||||
performWeb o url file urlinfo = ifAnnexed file addurl geturl
|
performWeb o url file urlinfo = ifAnnexed file addurl geturl
|
||||||
|
@ -323,12 +321,12 @@ downloadWeb o url urlinfo file =
|
||||||
{- The destination file is not known at start time unless the user provided
|
{- The destination file is not known at start time unless the user provided
|
||||||
- a filename. It's not displayed then for output consistency,
|
- a filename. It's not displayed then for output consistency,
|
||||||
- but is added to the json when available. -}
|
- but is added to the json when available. -}
|
||||||
showStartAddUrl :: URLString -> AddUrlOptions -> Annex ()
|
startingAddUrl :: URLString -> AddUrlOptions -> CommandPerform -> CommandStart
|
||||||
showStartAddUrl url o = do
|
startingAddUrl url o p = starting "addurl" (ActionItemOther (Just url)) $ do
|
||||||
showStart' "addurl" (Just url)
|
|
||||||
case fileOption (downloadOptions o) of
|
case fileOption (downloadOptions o) of
|
||||||
Nothing -> noop
|
Nothing -> noop
|
||||||
Just file -> maybeShowJSON $ JSONChunk [("file", file)]
|
Just file -> maybeShowJSON $ JSONChunk [("file", file)]
|
||||||
|
p
|
||||||
|
|
||||||
showDestinationFile :: FilePath -> Annex ()
|
showDestinationFile :: FilePath -> Annex ()
|
||||||
showDestinationFile file = do
|
showDestinationFile file = do
|
||||||
|
|
|
@ -47,5 +47,5 @@ seek = commandAction . start
|
||||||
start :: Adjustment -> CommandStart
|
start :: Adjustment -> CommandStart
|
||||||
start adj = do
|
start adj = do
|
||||||
checkVersionSupported
|
checkVersionSupported
|
||||||
showStart' "adjust" Nothing
|
starting "adjust" (ActionItemOther Nothing) $
|
||||||
next $ next $ enterAdjustedBranch adj
|
next $ enterAdjustedBranch adj
|
||||||
|
|
|
@ -20,10 +20,10 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withNothing (commandAction start)
|
seek = withNothing (commandAction start)
|
||||||
|
|
||||||
start :: CommandStart
|
start :: CommandStart
|
||||||
start = next $ next $ do
|
start = starting "commit" (ActionItemOther (Just "git-annex")) $ do
|
||||||
Annex.Branch.commit =<< Annex.Branch.commitMessage
|
Annex.Branch.commit =<< Annex.Branch.commitMessage
|
||||||
_ <- runhook <=< inRepo $ Git.hookPath "annex-content"
|
_ <- runhook <=< inRepo $ Git.hookPath "annex-content"
|
||||||
return True
|
next $ return True
|
||||||
where
|
where
|
||||||
runhook (Just hook) = liftIO $ boolSystem hook []
|
runhook (Just hook) = liftIO $ boolSystem hook []
|
||||||
runhook Nothing = return True
|
runhook Nothing = return True
|
||||||
|
|
|
@ -48,23 +48,19 @@ optParser _ = setconfig <|> getconfig <|> unsetconfig
|
||||||
)
|
)
|
||||||
|
|
||||||
seek :: Action -> CommandSeek
|
seek :: Action -> CommandSeek
|
||||||
seek (SetConfig name val) = commandAction $ do
|
seek (SetConfig name val) = commandAction $
|
||||||
allowMessages
|
startingUsualMessages name (ActionItemOther (Just val)) $ do
|
||||||
showStart' name (Just val)
|
|
||||||
next $ next $ do
|
|
||||||
setGlobalConfig name val
|
setGlobalConfig name val
|
||||||
setConfig (ConfigKey name) val
|
setConfig (ConfigKey name) val
|
||||||
return True
|
next $ return True
|
||||||
seek (UnsetConfig name) = commandAction $ do
|
seek (UnsetConfig name) = commandAction $
|
||||||
allowMessages
|
startingUsualMessages name (ActionItemOther (Just "unset")) $do
|
||||||
showStart' name (Just "unset")
|
|
||||||
next $ next $ do
|
|
||||||
unsetGlobalConfig name
|
unsetGlobalConfig name
|
||||||
unsetConfig (ConfigKey name)
|
unsetConfig (ConfigKey name)
|
||||||
return True
|
next $ return True
|
||||||
seek (GetConfig name) = commandAction $
|
seek (GetConfig name) = commandAction $
|
||||||
getGlobalConfig name >>= \case
|
startingCustomOutput (ActionItemOther Nothing) $ do
|
||||||
Nothing -> stop
|
getGlobalConfig name >>= \case
|
||||||
Just v -> do
|
Nothing -> return ()
|
||||||
liftIO $ putStrLn v
|
Just v -> liftIO $ putStrLn v
|
||||||
stop
|
next $ return True
|
||||||
|
|
|
@ -32,10 +32,9 @@ seek (DeadRemotes rs) = trustCommand "dead" DeadTrusted rs
|
||||||
seek (DeadKeys ks) = commandActions $ map startKey ks
|
seek (DeadKeys ks) = commandActions $ map startKey ks
|
||||||
|
|
||||||
startKey :: Key -> CommandStart
|
startKey :: Key -> CommandStart
|
||||||
startKey key = do
|
startKey key = starting "dead" (mkActionItem key) $
|
||||||
showStart' "dead" (Just $ serializeKey key)
|
|
||||||
keyLocations key >>= \case
|
keyLocations key >>= \case
|
||||||
[] -> next $ performKey key
|
[] -> performKey key
|
||||||
_ -> giveup "This key is still known to be present in some locations; not marking as dead."
|
_ -> giveup "This key is still known to be present in some locations; not marking as dead."
|
||||||
|
|
||||||
performKey :: Key -> CommandPerform
|
performKey :: Key -> CommandPerform
|
||||||
|
|
|
@ -22,9 +22,9 @@ seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start (name:description) | not (null description) = do
|
start (name:description) | not (null description) = do
|
||||||
showStart' "describe" (Just name)
|
|
||||||
u <- Remote.nameToUUID name
|
u <- Remote.nameToUUID name
|
||||||
next $ perform u $ unwords description
|
starting "describe" (ActionItemOther (Just name)) $
|
||||||
|
perform u $ unwords description
|
||||||
start _ = giveup "Specify a repository and a description."
|
start _ = giveup "Specify a repository and a description."
|
||||||
|
|
||||||
perform :: UUID -> String -> CommandPerform
|
perform :: UUID -> String -> CommandPerform
|
||||||
|
|
|
@ -25,44 +25,38 @@ seek = withNothing (commandAction start)
|
||||||
|
|
||||||
start :: CommandStart
|
start :: CommandStart
|
||||||
start = ifM versionSupportsDirectMode
|
start = ifM versionSupportsDirectMode
|
||||||
( ifM isDirect ( stop , next perform )
|
( ifM isDirect
|
||||||
|
( stop
|
||||||
|
, starting "direct" (ActionItemOther Nothing)
|
||||||
|
perform
|
||||||
|
)
|
||||||
, giveup "Direct mode is not supported by this repository version. Use git-annex unlock instead."
|
, giveup "Direct mode is not supported by this repository version. Use git-annex unlock instead."
|
||||||
)
|
)
|
||||||
|
|
||||||
perform :: CommandPerform
|
perform :: CommandPerform
|
||||||
perform = do
|
perform = do
|
||||||
showStart' "commit" Nothing
|
|
||||||
showOutput
|
showOutput
|
||||||
_ <- inRepo $ Git.Branch.commitCommand Git.Branch.ManualCommit
|
_ <- inRepo $ Git.Branch.commitCommand Git.Branch.ManualCommit
|
||||||
[ Param "-a"
|
[ Param "-a"
|
||||||
, Param "-m"
|
, Param "-m"
|
||||||
, Param "commit before switching to direct mode"
|
, Param "commit before switching to direct mode"
|
||||||
]
|
]
|
||||||
showEndOk
|
|
||||||
|
|
||||||
top <- fromRepo Git.repoPath
|
top <- fromRepo Git.repoPath
|
||||||
(l, clean) <- inRepo $ Git.LsFiles.inRepo [top]
|
(l, clean) <- inRepo $ Git.LsFiles.inRepo [top]
|
||||||
forM_ l go
|
forM_ l go
|
||||||
void $ liftIO clean
|
void $ liftIO clean
|
||||||
next cleanup
|
next $ return True
|
||||||
where
|
where
|
||||||
go = whenAnnexed $ \f k -> do
|
go = whenAnnexed $ \f k -> do
|
||||||
toDirectGen k f >>= \case
|
toDirectGen k f >>= \case
|
||||||
Nothing -> noop
|
Nothing -> noop
|
||||||
Just a -> do
|
Just a -> tryNonAsync a >>= \case
|
||||||
showStart "direct" f
|
Left e -> warnlocked f e
|
||||||
tryNonAsync a >>= \case
|
Right _ -> return ()
|
||||||
Left e -> warnlocked e
|
|
||||||
Right _ -> showEndOk
|
|
||||||
return Nothing
|
return Nothing
|
||||||
|
|
||||||
warnlocked :: SomeException -> Annex ()
|
warnlocked :: FilePath -> SomeException -> Annex ()
|
||||||
warnlocked e = do
|
warnlocked f e = do
|
||||||
warning $ show e
|
warning $ f ++ ": " ++ show e
|
||||||
warning "leaving this file as-is; correct this problem and run git annex fsck on it"
|
warning "leaving this file as-is; correct this problem and run git annex fsck on it"
|
||||||
|
|
||||||
cleanup :: CommandCleanup
|
|
||||||
cleanup = do
|
|
||||||
showStart' "direct" Nothing
|
|
||||||
setDirect True
|
|
||||||
return True
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ start o file key = start' o key afile ai
|
||||||
ai = mkActionItem (key, afile)
|
ai = mkActionItem (key, afile)
|
||||||
|
|
||||||
start' :: DropOptions -> Key -> AssociatedFile -> ActionItem -> CommandStart
|
start' :: DropOptions -> Key -> AssociatedFile -> ActionItem -> CommandStart
|
||||||
start' o key afile ai = onlyActionOn key $ do
|
start' o key afile ai = do
|
||||||
from <- maybe (pure Nothing) (Just <$$> getParsed) (dropFrom o)
|
from <- maybe (pure Nothing) (Just <$$> getParsed) (dropFrom o)
|
||||||
checkDropAuto (autoMode o) from afile key $ \numcopies ->
|
checkDropAuto (autoMode o) from afile key $ \numcopies ->
|
||||||
stopUnless (want from) $
|
stopUnless (want from) $
|
||||||
|
@ -89,14 +89,15 @@ startKeys :: DropOptions -> (Key, ActionItem) -> CommandStart
|
||||||
startKeys o (key, ai) = start' o key (AssociatedFile Nothing) ai
|
startKeys o (key, ai) = start' o key (AssociatedFile Nothing) ai
|
||||||
|
|
||||||
startLocal :: AssociatedFile -> ActionItem -> NumCopies -> Key -> [VerifiedCopy] -> CommandStart
|
startLocal :: AssociatedFile -> ActionItem -> NumCopies -> Key -> [VerifiedCopy] -> CommandStart
|
||||||
startLocal afile ai numcopies key preverified = stopUnless (inAnnex key) $ do
|
startLocal afile ai numcopies key preverified =
|
||||||
showStartKey "drop" key ai
|
stopUnless (inAnnex key) $
|
||||||
next $ performLocal key afile numcopies preverified
|
starting "drop" (OnlyActionOn key ai) $
|
||||||
|
performLocal key afile numcopies preverified
|
||||||
|
|
||||||
startRemote :: AssociatedFile -> ActionItem -> NumCopies -> Key -> Remote -> CommandStart
|
startRemote :: AssociatedFile -> ActionItem -> NumCopies -> Key -> Remote -> CommandStart
|
||||||
startRemote afile ai numcopies key remote = do
|
startRemote afile ai numcopies key remote =
|
||||||
showStartKey ("drop " ++ Remote.name remote) key ai
|
starting ("drop " ++ Remote.name remote) (OnlyActionOn key ai) $
|
||||||
next $ performRemote key afile numcopies remote
|
performRemote key afile numcopies remote
|
||||||
|
|
||||||
performLocal :: Key -> AssociatedFile -> NumCopies -> [VerifiedCopy] -> CommandPerform
|
performLocal :: Key -> AssociatedFile -> NumCopies -> [VerifiedCopy] -> CommandPerform
|
||||||
performLocal key afile numcopies preverified = lockContentForRemoval key $ \contentlock -> do
|
performLocal key afile numcopies preverified = lockContentForRemoval key $ \contentlock -> do
|
||||||
|
|
|
@ -41,9 +41,8 @@ seek o = do
|
||||||
parsekey = maybe (Left "bad key") Right . deserializeKey
|
parsekey = maybe (Left "bad key") Right . deserializeKey
|
||||||
|
|
||||||
start :: Key -> CommandStart
|
start :: Key -> CommandStart
|
||||||
start key = do
|
start key = starting "dropkey" (mkActionItem key) $
|
||||||
showStartKey "dropkey" key (mkActionItem key)
|
perform key
|
||||||
next $ perform key
|
|
||||||
|
|
||||||
perform :: Key -> CommandPerform
|
perform :: Key -> CommandPerform
|
||||||
perform key = ifM (inAnnex key)
|
perform key = ifM (inAnnex key)
|
||||||
|
|
|
@ -54,13 +54,11 @@ start (name:rest) = go =<< filter matchingname <$> Annex.getGitRemotes
|
||||||
-- the remote uuid.
|
-- the remote uuid.
|
||||||
startNormalRemote :: Git.RemoteName -> [String] -> Git.Repo -> CommandStart
|
startNormalRemote :: Git.RemoteName -> [String] -> Git.Repo -> CommandStart
|
||||||
startNormalRemote name restparams r
|
startNormalRemote name restparams r
|
||||||
| null restparams = do
|
| null restparams = starting "enableremote" (ActionItemOther (Just name)) $ do
|
||||||
showStart' "enableremote" (Just name)
|
setRemoteIgnore r False
|
||||||
next $ next $ do
|
r' <- Remote.Git.configRead False r
|
||||||
setRemoteIgnore r False
|
u <- getRepoUUID r'
|
||||||
r' <- Remote.Git.configRead False r
|
next $ return $ u /= NoUUID
|
||||||
u <- getRepoUUID r'
|
|
||||||
return $ u /= NoUUID
|
|
||||||
| otherwise = giveup $
|
| otherwise = giveup $
|
||||||
"That is a normal git remote; passing these parameters does not make sense: " ++ unwords restparams
|
"That is a normal git remote; passing these parameters does not make sense: " ++ unwords restparams
|
||||||
|
|
||||||
|
@ -73,14 +71,14 @@ startSpecialRemote name config Nothing = do
|
||||||
startSpecialRemote name config $
|
startSpecialRemote name config $
|
||||||
Just (u, fromMaybe M.empty (M.lookup u confm))
|
Just (u, fromMaybe M.empty (M.lookup u confm))
|
||||||
_ -> unknownNameError "Unknown remote name."
|
_ -> unknownNameError "Unknown remote name."
|
||||||
startSpecialRemote name config (Just (u, c)) = do
|
startSpecialRemote name config (Just (u, c)) =
|
||||||
let fullconfig = config `M.union` c
|
starting "enableremote" (ActionItemOther (Just name)) $ do
|
||||||
t <- either giveup return (Annex.SpecialRemote.findType fullconfig)
|
let fullconfig = config `M.union` c
|
||||||
showStart' "enableremote" (Just name)
|
t <- either giveup return (Annex.SpecialRemote.findType fullconfig)
|
||||||
gc <- maybe (liftIO dummyRemoteGitConfig)
|
gc <- maybe (liftIO dummyRemoteGitConfig)
|
||||||
(return . Remote.gitconfig)
|
(return . Remote.gitconfig)
|
||||||
=<< Remote.byUUID u
|
=<< Remote.byUUID u
|
||||||
next $ performSpecialRemote t u c fullconfig gc
|
performSpecialRemote t u c fullconfig gc
|
||||||
|
|
||||||
performSpecialRemote :: RemoteType -> UUID -> R.RemoteConfig -> R.RemoteConfig -> RemoteGitConfig -> CommandPerform
|
performSpecialRemote :: RemoteType -> UUID -> R.RemoteConfig -> R.RemoteConfig -> RemoteGitConfig -> CommandPerform
|
||||||
performSpecialRemote t u oldc c gc = do
|
performSpecialRemote t u oldc c gc = do
|
||||||
|
|
|
@ -51,15 +51,14 @@ start os = do
|
||||||
then case readish =<< headMaybe os of
|
then case readish =<< headMaybe os of
|
||||||
Nothing -> giveup "Need user-id parameter."
|
Nothing -> giveup "Need user-id parameter."
|
||||||
Just userid -> go uuid userid
|
Just userid -> go uuid userid
|
||||||
else do
|
else starting "enable-tor" (ActionItemOther Nothing) $ do
|
||||||
showStart' "enable-tor" Nothing
|
|
||||||
gitannex <- liftIO readProgramFile
|
gitannex <- liftIO readProgramFile
|
||||||
let ps = [Param (cmdname cmd), Param (show curruserid)]
|
let ps = [Param (cmdname cmd), Param (show curruserid)]
|
||||||
sucommand <- liftIO $ mkSuCommand gitannex ps
|
sucommand <- liftIO $ mkSuCommand gitannex ps
|
||||||
maybe noop showLongNote
|
maybe noop showLongNote
|
||||||
(describePasswordPrompt' sucommand)
|
(describePasswordPrompt' sucommand)
|
||||||
ifM (liftIO $ runSuCommand sucommand)
|
ifM (liftIO $ runSuCommand sucommand)
|
||||||
( next $ next checkHiddenService
|
( next checkHiddenService
|
||||||
, giveup $ unwords $
|
, giveup $ unwords $
|
||||||
[ "Failed to run as root:" , gitannex ] ++ toCommand ps
|
[ "Failed to run as root:" , gitannex ] ++ toCommand ps
|
||||||
)
|
)
|
||||||
|
|
|
@ -58,16 +58,18 @@ seek o = do
|
||||||
start :: Expire -> Bool -> Log Activity -> UUIDDescMap -> UUID -> CommandStart
|
start :: Expire -> Bool -> Log Activity -> UUIDDescMap -> UUID -> CommandStart
|
||||||
start (Expire expire) noact actlog descs u =
|
start (Expire expire) noact actlog descs u =
|
||||||
case lastact of
|
case lastact of
|
||||||
Just ent | notexpired ent -> checktrust (== DeadTrusted) $ do
|
Just ent | notexpired ent -> checktrust (== DeadTrusted) $
|
||||||
showStart' "unexpire" (Just desc)
|
starting "unexpire" (ActionItemOther (Just desc)) $ do
|
||||||
showNote =<< whenactive
|
showNote =<< whenactive
|
||||||
unless noact $
|
unless noact $
|
||||||
trustSet u SemiTrusted
|
trustSet u SemiTrusted
|
||||||
_ -> checktrust (/= DeadTrusted) $ do
|
next $ return True
|
||||||
showStart' "expire" (Just desc)
|
_ -> checktrust (/= DeadTrusted) $
|
||||||
showNote =<< whenactive
|
starting "expire" (ActionItemOther (Just desc)) $ do
|
||||||
unless noact $
|
showNote =<< whenactive
|
||||||
trustSet u DeadTrusted
|
unless noact $
|
||||||
|
trustSet u DeadTrusted
|
||||||
|
next $ return True
|
||||||
where
|
where
|
||||||
lastact = changed <$> M.lookup u actlog
|
lastact = changed <$> M.lookup u actlog
|
||||||
whenactive = case lastact of
|
whenactive = case lastact of
|
||||||
|
@ -83,12 +85,7 @@ start (Expire expire) noact actlog descs u =
|
||||||
_ -> True
|
_ -> True
|
||||||
lookupexpire = headMaybe $ catMaybes $
|
lookupexpire = headMaybe $ catMaybes $
|
||||||
map (`M.lookup` expire) [Just u, Nothing]
|
map (`M.lookup` expire) [Just u, Nothing]
|
||||||
checktrust want a = ifM (want <$> lookupTrust u)
|
checktrust want = stopUnless (want <$> lookupTrust u)
|
||||||
( do
|
|
||||||
void a
|
|
||||||
next $ next $ return True
|
|
||||||
, stop
|
|
||||||
)
|
|
||||||
|
|
||||||
data Expire = Expire (M.Map (Maybe UUID) (Maybe POSIXTime))
|
data Expire = Expire (M.Map (Maybe UUID) (Maybe POSIXTime))
|
||||||
|
|
||||||
|
|
|
@ -249,14 +249,14 @@ fillExport r db (PreferredFiltered newtree) mtbcommitsha = do
|
||||||
startExport :: Remote -> ExportHandle -> MVar FileUploaded -> MVar AllFilled -> Git.LsTree.TreeItem -> CommandStart
|
startExport :: Remote -> ExportHandle -> MVar FileUploaded -> MVar AllFilled -> Git.LsTree.TreeItem -> CommandStart
|
||||||
startExport r db cvar allfilledvar ti = do
|
startExport r db cvar allfilledvar ti = do
|
||||||
ek <- exportKey (Git.LsTree.sha ti)
|
ek <- exportKey (Git.LsTree.sha ti)
|
||||||
stopUnless (notrecordedpresent ek) $ do
|
stopUnless (notrecordedpresent ek) $
|
||||||
showStart ("export " ++ name r) f
|
starting ("export " ++ name r) (ActionItemOther (Just f)) $
|
||||||
ifM (either (const False) id <$> tryNonAsync (checkPresentExport (exportActions r) (asKey ek) loc))
|
ifM (either (const False) id <$> tryNonAsync (checkPresentExport (exportActions r) (asKey ek) loc))
|
||||||
( next $ next $ cleanupExport r db ek loc False
|
( next $ cleanupExport r db ek loc False
|
||||||
, do
|
, do
|
||||||
liftIO $ modifyMVar_ cvar (pure . const (FileUploaded True))
|
liftIO $ modifyMVar_ cvar (pure . const (FileUploaded True))
|
||||||
next $ performExport r db ek af (Git.LsTree.sha ti) loc allfilledvar
|
performExport r db ek af (Git.LsTree.sha ti) loc allfilledvar
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
loc = mkExportLocation f
|
loc = mkExportLocation f
|
||||||
f = getTopFilePath (Git.LsTree.file ti)
|
f = getTopFilePath (Git.LsTree.file ti)
|
||||||
|
@ -313,17 +313,15 @@ startUnexport r db f shas = do
|
||||||
eks <- forM (filter (/= nullSha) shas) exportKey
|
eks <- forM (filter (/= nullSha) shas) exportKey
|
||||||
if null eks
|
if null eks
|
||||||
then stop
|
then stop
|
||||||
else do
|
else starting ("unexport " ++ name r) (ActionItemOther (Just f')) $
|
||||||
showStart ("unexport " ++ name r) f'
|
performUnexport r db eks loc
|
||||||
next $ performUnexport r db eks loc
|
|
||||||
where
|
where
|
||||||
loc = mkExportLocation f'
|
loc = mkExportLocation f'
|
||||||
f' = getTopFilePath f
|
f' = getTopFilePath f
|
||||||
|
|
||||||
startUnexport' :: Remote -> ExportHandle -> TopFilePath -> ExportKey -> CommandStart
|
startUnexport' :: Remote -> ExportHandle -> TopFilePath -> ExportKey -> CommandStart
|
||||||
startUnexport' r db f ek = do
|
startUnexport' r db f ek = starting ("unexport " ++ name r) (ActionItemOther (Just f')) $
|
||||||
showStart ("unexport " ++ name r) f'
|
performUnexport r db [ek] loc
|
||||||
next $ performUnexport r db [ek] loc
|
|
||||||
where
|
where
|
||||||
loc = mkExportLocation f'
|
loc = mkExportLocation f'
|
||||||
f' = getTopFilePath f
|
f' = getTopFilePath f
|
||||||
|
@ -365,17 +363,17 @@ startRecoverIncomplete r db sha oldf
|
||||||
| otherwise = do
|
| otherwise = do
|
||||||
ek <- exportKey sha
|
ek <- exportKey sha
|
||||||
let loc = exportTempName ek
|
let loc = exportTempName ek
|
||||||
showStart ("unexport " ++ name r) (fromExportLocation loc)
|
starting ("unexport " ++ name r) (ActionItemOther (Just (fromExportLocation loc))) $ do
|
||||||
liftIO $ removeExportedLocation db (asKey ek) oldloc
|
liftIO $ removeExportedLocation db (asKey ek) oldloc
|
||||||
next $ performUnexport r db [ek] loc
|
performUnexport r db [ek] loc
|
||||||
where
|
where
|
||||||
oldloc = mkExportLocation oldf'
|
oldloc = mkExportLocation oldf'
|
||||||
oldf' = getTopFilePath oldf
|
oldf' = getTopFilePath oldf
|
||||||
|
|
||||||
startMoveToTempName :: Remote -> ExportHandle -> TopFilePath -> ExportKey -> CommandStart
|
startMoveToTempName :: Remote -> ExportHandle -> TopFilePath -> ExportKey -> CommandStart
|
||||||
startMoveToTempName r db f ek = do
|
startMoveToTempName r db f ek = starting ("rename " ++ name r)
|
||||||
showStart ("rename " ++ name r) (f' ++ " -> " ++ fromExportLocation tmploc)
|
(ActionItemOther $ Just $ f' ++ " -> " ++ fromExportLocation tmploc)
|
||||||
next $ performRename r db ek loc tmploc
|
(performRename r db ek loc tmploc)
|
||||||
where
|
where
|
||||||
loc = mkExportLocation f'
|
loc = mkExportLocation f'
|
||||||
f' = getTopFilePath f
|
f' = getTopFilePath f
|
||||||
|
@ -384,9 +382,9 @@ startMoveToTempName r db f ek = do
|
||||||
startMoveFromTempName :: Remote -> ExportHandle -> ExportKey -> TopFilePath -> CommandStart
|
startMoveFromTempName :: Remote -> ExportHandle -> ExportKey -> TopFilePath -> CommandStart
|
||||||
startMoveFromTempName r db ek f = do
|
startMoveFromTempName r db ek f = do
|
||||||
let tmploc = exportTempName ek
|
let tmploc = exportTempName ek
|
||||||
stopUnless (liftIO $ elem tmploc <$> getExportedLocation db (asKey ek)) $ do
|
stopUnless (liftIO $ elem tmploc <$> getExportedLocation db (asKey ek)) $
|
||||||
showStart ("rename " ++ name r) (fromExportLocation tmploc ++ " -> " ++ f')
|
starting ("rename " ++ name r) (ActionItemOther (Just (fromExportLocation tmploc ++ " -> " ++ f'))) $
|
||||||
next $ performRename r db ek tmploc loc
|
performRename r db ek tmploc loc
|
||||||
where
|
where
|
||||||
loc = mkExportLocation f'
|
loc = mkExportLocation f'
|
||||||
f' = getTopFilePath f
|
f' = getTopFilePath f
|
||||||
|
|
|
@ -14,7 +14,6 @@ import Command
|
||||||
import Annex.Content
|
import Annex.Content
|
||||||
import Limit
|
import Limit
|
||||||
import Types.Key
|
import Types.Key
|
||||||
import Types.ActionItem
|
|
||||||
import Git.FilePath
|
import Git.FilePath
|
||||||
import qualified Utility.Format
|
import qualified Utility.Format
|
||||||
import Utility.DataUnits
|
import Utility.DataUnits
|
||||||
|
@ -65,12 +64,11 @@ seek o = case batchOption o of
|
||||||
-- only files inAnnex are shown, unless the user has requested
|
-- only files inAnnex are shown, unless the user has requested
|
||||||
-- others via a limit
|
-- others via a limit
|
||||||
start :: FindOptions -> FilePath -> Key -> CommandStart
|
start :: FindOptions -> FilePath -> Key -> CommandStart
|
||||||
start o file key = ifM (limited <||> inAnnex key)
|
start o file key =
|
||||||
( do
|
stopUnless (limited <||> inAnnex key) $
|
||||||
showFormatted (formatOption o) file $ ("file", file) : keyVars key
|
startingCustomOutput key $ do
|
||||||
next $ next $ return True
|
showFormatted (formatOption o) file $ ("file", file) : keyVars key
|
||||||
, stop
|
next $ return True
|
||||||
)
|
|
||||||
|
|
||||||
startKeys :: FindOptions -> (Key, ActionItem) -> CommandStart
|
startKeys :: FindOptions -> (Key, ActionItem) -> CommandStart
|
||||||
startKeys o (key, ActionItemBranchFilePath (BranchFilePath _ topf) _) =
|
startKeys o (key, ActionItemBranchFilePath (BranchFilePath _ topf) _) =
|
||||||
|
|
|
@ -54,9 +54,7 @@ start fixwhat file key = do
|
||||||
FixAll -> fixthin
|
FixAll -> fixthin
|
||||||
FixSymlinks -> stop
|
FixSymlinks -> stop
|
||||||
where
|
where
|
||||||
fixby a = do
|
fixby = starting "fix" (mkActionItem (key, file))
|
||||||
showStart "fix" file
|
|
||||||
next a
|
|
||||||
fixthin = do
|
fixthin = do
|
||||||
obj <- calcRepo $ gitAnnexLocation key
|
obj <- calcRepo $ gitAnnexLocation key
|
||||||
stopUnless (isUnmodified key file <&&> isUnmodified key obj) $ do
|
stopUnless (isUnmodified key file <&&> isUnmodified key obj) $ do
|
||||||
|
|
|
@ -33,14 +33,13 @@ seek :: ForgetOptions -> CommandSeek
|
||||||
seek = commandAction . start
|
seek = commandAction . start
|
||||||
|
|
||||||
start :: ForgetOptions -> CommandStart
|
start :: ForgetOptions -> CommandStart
|
||||||
start o = do
|
start o = starting "forget" (ActionItemOther (Just "git-annex")) $ do
|
||||||
showStart' "forget" (Just "git-annex")
|
|
||||||
c <- liftIO currentVectorClock
|
c <- liftIO currentVectorClock
|
||||||
let basets = addTransition c ForgetGitHistory noTransitions
|
let basets = addTransition c ForgetGitHistory noTransitions
|
||||||
let ts = if dropDead o
|
let ts = if dropDead o
|
||||||
then addTransition c ForgetDeadRemotes basets
|
then addTransition c ForgetDeadRemotes basets
|
||||||
else basets
|
else basets
|
||||||
next $ perform ts =<< Annex.getState Annex.force
|
perform ts =<< Annex.getState Annex.force
|
||||||
|
|
||||||
perform :: Transitions -> Bool -> CommandPerform
|
perform :: Transitions -> Bool -> CommandPerform
|
||||||
perform ts True = do
|
perform ts True = do
|
||||||
|
|
|
@ -51,9 +51,8 @@ seekBatch fmt = batchInput fmt parse commandAction
|
||||||
in if not (null keyname) && not (null file)
|
in if not (null keyname) && not (null file)
|
||||||
then Right $ go file (mkKey keyname)
|
then Right $ go file (mkKey keyname)
|
||||||
else Left "Expected pairs of key and filename"
|
else Left "Expected pairs of key and filename"
|
||||||
go file key = do
|
go file key = starting "fromkey" (mkActionItem (key, file)) $
|
||||||
showStart "fromkey" file
|
perform key file
|
||||||
next $ perform key file
|
|
||||||
|
|
||||||
start :: Bool -> (String, FilePath) -> CommandStart
|
start :: Bool -> (String, FilePath) -> CommandStart
|
||||||
start force (keyname, file) = do
|
start force (keyname, file) = do
|
||||||
|
@ -62,8 +61,8 @@ start force (keyname, file) = do
|
||||||
inbackend <- inAnnex key
|
inbackend <- inAnnex key
|
||||||
unless inbackend $ giveup $
|
unless inbackend $ giveup $
|
||||||
"key ("++ keyname ++") is not present in backend (use --force to override this sanity check)"
|
"key ("++ keyname ++") is not present in backend (use --force to override this sanity check)"
|
||||||
showStart "fromkey" file
|
starting "fromkey" (mkActionItem (key, file)) $
|
||||||
next $ perform key file
|
perform key file
|
||||||
|
|
||||||
-- From user input to a Key.
|
-- From user input to a Key.
|
||||||
-- User can input either a serialized key, or an url.
|
-- User can input either a serialized key, or an url.
|
||||||
|
|
|
@ -586,16 +586,12 @@ badContentRemote remote localcopy key = do
|
||||||
(_, False) -> "failed to drop from" ++ Remote.name remote
|
(_, False) -> "failed to drop from" ++ Remote.name remote
|
||||||
|
|
||||||
runFsck :: Incremental -> ActionItem -> Key -> Annex Bool -> CommandStart
|
runFsck :: Incremental -> ActionItem -> Key -> Annex Bool -> CommandStart
|
||||||
runFsck inc ai key a = ifM (needFsck inc key)
|
runFsck inc ai key a = stopUnless (needFsck inc key) $
|
||||||
( do
|
starting "fsck" ai $ do
|
||||||
showStartKey "fsck" key ai
|
ok <- a
|
||||||
next $ do
|
when ok $
|
||||||
ok <- a
|
recordFsckTime inc key
|
||||||
when ok $
|
next $ return ok
|
||||||
recordFsckTime inc key
|
|
||||||
next $ return ok
|
|
||||||
, stop
|
|
||||||
)
|
|
||||||
|
|
||||||
{- Check if a key needs to be fscked, with support for incremental fscks. -}
|
{- Check if a key needs to be fscked, with support for incremental fscks. -}
|
||||||
needFsck :: Incremental -> Key -> Annex Bool
|
needFsck :: Incremental -> Key -> Annex Bool
|
||||||
|
|
|
@ -22,7 +22,7 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withStrings (commandAction . start)
|
seek = withStrings (commandAction . start)
|
||||||
|
|
||||||
start :: String -> CommandStart
|
start :: String -> CommandStart
|
||||||
start gcryptid = next $ next $ do
|
start gcryptid = starting "gcryptsetup" (ActionItemOther Nothing) $ do
|
||||||
u <- getUUID
|
u <- getUUID
|
||||||
when (u /= NoUUID) $
|
when (u /= NoUUID) $
|
||||||
giveup "gcryptsetup refusing to run; this repository already has a git-annex uuid!"
|
giveup "gcryptsetup refusing to run; this repository already has a git-annex uuid!"
|
||||||
|
@ -34,6 +34,6 @@ start gcryptid = next $ next $ do
|
||||||
then if Git.repoIsLocalBare g
|
then if Git.repoIsLocalBare g
|
||||||
then do
|
then do
|
||||||
void $ Remote.GCrypt.setupRepo gcryptid g
|
void $ Remote.GCrypt.setupRepo gcryptid g
|
||||||
return True
|
next $ return True
|
||||||
else giveup "cannot use gcrypt in a non-bare repository"
|
else giveup "cannot use gcrypt in a non-bare repository"
|
||||||
else giveup "gcryptsetup uuid mismatch"
|
else giveup "gcryptsetup uuid mismatch"
|
||||||
|
|
|
@ -63,7 +63,7 @@ startKeys from (key, ai) = checkFailedTransferDirection ai Download $
|
||||||
start' (return True) from key (AssociatedFile Nothing) ai
|
start' (return True) from key (AssociatedFile Nothing) ai
|
||||||
|
|
||||||
start' :: Annex Bool -> Maybe Remote -> Key -> AssociatedFile -> ActionItem -> CommandStart
|
start' :: Annex Bool -> Maybe Remote -> Key -> AssociatedFile -> ActionItem -> CommandStart
|
||||||
start' expensivecheck from key afile ai = onlyActionOn key $
|
start' expensivecheck from key afile ai =
|
||||||
stopUnless (not <$> inAnnex key) $ stopUnless expensivecheck $
|
stopUnless (not <$> inAnnex key) $ stopUnless expensivecheck $
|
||||||
case from of
|
case from of
|
||||||
Nothing -> go $ perform key afile
|
Nothing -> go $ perform key afile
|
||||||
|
@ -71,9 +71,7 @@ start' expensivecheck from key afile ai = onlyActionOn key $
|
||||||
stopUnless (Command.Move.fromOk src key) $
|
stopUnless (Command.Move.fromOk src key) $
|
||||||
go $ Command.Move.fromPerform src Command.Move.RemoveNever key afile
|
go $ Command.Move.fromPerform src Command.Move.RemoveNever key afile
|
||||||
where
|
where
|
||||||
go a = do
|
go = starting "get" (OnlyActionOn key ai)
|
||||||
showStartKey "get" key ai
|
|
||||||
next a
|
|
||||||
|
|
||||||
perform :: Key -> AssociatedFile -> CommandPerform
|
perform :: Key -> AssociatedFile -> CommandPerform
|
||||||
perform key afile = stopUnless (getKey key afile) $
|
perform key afile = stopUnless (getKey key afile) $
|
||||||
|
|
|
@ -23,14 +23,15 @@ seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start (name:g:[]) = do
|
start (name:g:[]) = do
|
||||||
allowMessages
|
|
||||||
showStart' "group" (Just name)
|
|
||||||
u <- Remote.nameToUUID name
|
u <- Remote.nameToUUID name
|
||||||
next $ setGroup u (toGroup g)
|
startingUsualMessages "group" (ActionItemOther (Just name)) $
|
||||||
|
setGroup u (toGroup g)
|
||||||
start (name:[]) = do
|
start (name:[]) = do
|
||||||
u <- Remote.nameToUUID name
|
u <- Remote.nameToUUID name
|
||||||
liftIO . putStrLn . unwords . map fmt . S.toList =<< lookupGroups u
|
startingCustomOutput (ActionItemOther Nothing) $ do
|
||||||
stop
|
liftIO . putStrLn . unwords . map fmt . S.toList
|
||||||
|
=<< lookupGroups u
|
||||||
|
next $ return True
|
||||||
where
|
where
|
||||||
fmt (Group g) = decodeBS g
|
fmt (Group g) = decodeBS g
|
||||||
start _ = giveup "Specify a repository and a group."
|
start _ = giveup "Specify a repository and a group."
|
||||||
|
|
|
@ -22,9 +22,8 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withWords (commandAction . start)
|
seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start (g:[]) = next $ performGet groupPreferredContentMapRaw (toGroup g)
|
start (g:[]) = startingCustomOutput (ActionItemOther Nothing) $
|
||||||
start (g:expr:[]) = do
|
performGet groupPreferredContentMapRaw (toGroup g)
|
||||||
allowMessages
|
start (g:expr:[]) = startingUsualMessages "groupwanted" (ActionItemOther (Just g)) $
|
||||||
showStart' "groupwanted" (Just g)
|
performSet groupPreferredContentSet expr (toGroup g)
|
||||||
next $ performSet groupPreferredContentSet expr (toGroup g)
|
|
||||||
start _ = giveup "Specify a group."
|
start _ = giveup "Specify a group."
|
||||||
|
|
|
@ -117,9 +117,8 @@ seek o@(RemoteImportOptions {}) = allowConcurrentOutput $ do
|
||||||
startLocal :: GetFileMatcher -> DuplicateMode -> (FilePath, FilePath) -> CommandStart
|
startLocal :: GetFileMatcher -> DuplicateMode -> (FilePath, FilePath) -> CommandStart
|
||||||
startLocal largematcher mode (srcfile, destfile) =
|
startLocal largematcher mode (srcfile, destfile) =
|
||||||
ifM (liftIO $ isRegularFile <$> getSymbolicLinkStatus srcfile)
|
ifM (liftIO $ isRegularFile <$> getSymbolicLinkStatus srcfile)
|
||||||
( do
|
( starting "import" (ActionItemWorkTreeFile destfile)
|
||||||
showStart "import" destfile
|
pickaction
|
||||||
next pickaction
|
|
||||||
, stop
|
, stop
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
@ -280,7 +279,8 @@ seekRemote remote branch msubdir = do
|
||||||
, ". Re-run command to resume import."
|
, ". Re-run command to resume import."
|
||||||
]
|
]
|
||||||
Just imported -> void $
|
Just imported -> void $
|
||||||
includeCommandAction $ commitimport imported
|
includeCommandAction $
|
||||||
|
commitimport imported
|
||||||
where
|
where
|
||||||
importmessage = "import from " ++ Remote.name remote
|
importmessage = "import from " ++ Remote.name remote
|
||||||
|
|
||||||
|
@ -289,9 +289,8 @@ seekRemote remote branch msubdir = do
|
||||||
fromtrackingbranch a = inRepo $ a (fromRemoteTrackingBranch tb)
|
fromtrackingbranch a = inRepo $ a (fromRemoteTrackingBranch tb)
|
||||||
|
|
||||||
listContents :: Remote -> TVar (Maybe (ImportableContents (ContentIdentifier, Remote.ByteSize))) -> CommandStart
|
listContents :: Remote -> TVar (Maybe (ImportableContents (ContentIdentifier, Remote.ByteSize))) -> CommandStart
|
||||||
listContents remote tvar = do
|
listContents remote tvar = starting "list" (ActionItemOther (Just (Remote.name remote))) $
|
||||||
showStart' "list" (Just (Remote.name remote))
|
listImportableContents remote >>= \case
|
||||||
next $ listImportableContents remote >>= \case
|
|
||||||
Nothing -> giveup $ "Unable to list contents of " ++ Remote.name remote
|
Nothing -> giveup $ "Unable to list contents of " ++ Remote.name remote
|
||||||
Just importable -> do
|
Just importable -> do
|
||||||
importable' <- makeImportMatcher remote >>= \case
|
importable' <- makeImportMatcher remote >>= \case
|
||||||
|
@ -302,9 +301,8 @@ listContents remote tvar = do
|
||||||
return True
|
return True
|
||||||
|
|
||||||
commitRemote :: Remote -> Branch -> RemoteTrackingBranch -> Maybe Sha -> ImportTreeConfig -> ImportCommitConfig -> ImportableContents Key -> CommandStart
|
commitRemote :: Remote -> Branch -> RemoteTrackingBranch -> Maybe Sha -> ImportTreeConfig -> ImportCommitConfig -> ImportableContents Key -> CommandStart
|
||||||
commitRemote remote branch tb trackingcommit importtreeconfig importcommitconfig importable = do
|
commitRemote remote branch tb trackingcommit importtreeconfig importcommitconfig importable =
|
||||||
showStart' "update" (Just $ fromRef $ fromRemoteTrackingBranch tb)
|
starting "update" (ActionItemOther (Just $ fromRef $ fromRemoteTrackingBranch tb)) $ do
|
||||||
next $ do
|
|
||||||
importcommit <- buildImportCommit remote importtreeconfig importcommitconfig importable
|
importcommit <- buildImportCommit remote importtreeconfig importcommitconfig importable
|
||||||
next $ updateremotetrackingbranch importcommit
|
next $ updateremotetrackingbranch importcommit
|
||||||
|
|
||||||
|
|
|
@ -66,32 +66,27 @@ optParser desc = ImportFeedOptions
|
||||||
seek :: ImportFeedOptions -> CommandSeek
|
seek :: ImportFeedOptions -> CommandSeek
|
||||||
seek o = do
|
seek o = do
|
||||||
cache <- getCache (templateOption o)
|
cache <- getCache (templateOption o)
|
||||||
withStrings (commandAction . start o cache) (feedUrls o)
|
forM_ (feedUrls o) (getFeed o cache)
|
||||||
|
|
||||||
start :: ImportFeedOptions -> Cache -> URLString -> CommandStart
|
getFeed :: ImportFeedOptions -> Cache -> URLString -> CommandSeek
|
||||||
start opts cache url = do
|
getFeed opts cache url = do
|
||||||
showStart' "importfeed" (Just url)
|
showStart "importfeed" url
|
||||||
next $ perform opts cache url
|
downloadFeed url >>= \case
|
||||||
|
Nothing -> showEndResult =<< feedProblem url
|
||||||
perform :: ImportFeedOptions -> Cache -> URLString -> CommandPerform
|
"downloading the feed failed"
|
||||||
perform opts cache url = go =<< downloadFeed url
|
Just feedcontent -> case parseFeedString feedcontent of
|
||||||
where
|
Nothing -> showEndResult =<< feedProblem url
|
||||||
go Nothing = next $ feedProblem url "downloading the feed failed"
|
"parsing the feed failed"
|
||||||
go (Just feedcontent) = case parseFeedString feedcontent of
|
Just f -> case findDownloads url f of
|
||||||
Nothing -> next $ feedProblem url "parsing the feed failed"
|
[] -> showEndResult =<< feedProblem url
|
||||||
Just f -> case findDownloads url f of
|
"bad feed content; no enclosures to download"
|
||||||
[] -> next $
|
l -> do
|
||||||
feedProblem url "bad feed content; no enclosures to download"
|
showEndOk
|
||||||
l -> do
|
ifM (and <$> mapM (performDownload opts cache) l)
|
||||||
showOutput
|
( clearFeedProblem url
|
||||||
ok <- and <$> mapM (performDownload opts cache) l
|
, void $ feedProblem url
|
||||||
next $ cleanup url ok
|
"problem downloading some item(s) from feed"
|
||||||
|
)
|
||||||
cleanup :: URLString -> Bool -> CommandCleanup
|
|
||||||
cleanup url True = do
|
|
||||||
clearFeedProblem url
|
|
||||||
return True
|
|
||||||
cleanup url False = feedProblem url "problem downloading some item(s) from feed"
|
|
||||||
|
|
||||||
data ToDownload = ToDownload
|
data ToDownload = ToDownload
|
||||||
{ feed :: Feed
|
{ feed :: Feed
|
||||||
|
|
|
@ -36,20 +36,19 @@ start = ifM isDirect
|
||||||
giveup "Git is configured to not use symlinks, so you must use direct mode."
|
giveup "Git is configured to not use symlinks, so you must use direct mode."
|
||||||
whenM probeCrippledFileSystem $
|
whenM probeCrippledFileSystem $
|
||||||
giveup "This repository seems to be on a crippled filesystem, you must use direct mode."
|
giveup "This repository seems to be on a crippled filesystem, you must use direct mode."
|
||||||
next perform
|
starting "indirect" (ActionItemOther Nothing)
|
||||||
|
perform
|
||||||
, stop
|
, stop
|
||||||
)
|
)
|
||||||
|
|
||||||
perform :: CommandPerform
|
perform :: CommandPerform
|
||||||
perform = do
|
perform = do
|
||||||
showStart' "commit" Nothing
|
|
||||||
whenM stageDirect $ do
|
whenM stageDirect $ do
|
||||||
showOutput
|
showOutput
|
||||||
void $ inRepo $ Git.Branch.commitCommand Git.Branch.ManualCommit
|
void $ inRepo $ Git.Branch.commitCommand Git.Branch.ManualCommit
|
||||||
[ Param "-m"
|
[ Param "-m"
|
||||||
, Param "commit before switching to indirect mode"
|
, Param "commit before switching to indirect mode"
|
||||||
]
|
]
|
||||||
showEndOk
|
|
||||||
|
|
||||||
-- Note that we set indirect mode early, so that we can use
|
-- Note that we set indirect mode early, so that we can use
|
||||||
-- moveAnnex in indirect mode.
|
-- moveAnnex in indirect mode.
|
||||||
|
@ -59,7 +58,7 @@ perform = do
|
||||||
(l, clean) <- inRepo $ Git.LsFiles.stagedOthersDetails [top]
|
(l, clean) <- inRepo $ Git.LsFiles.stagedOthersDetails [top]
|
||||||
forM_ l go
|
forM_ l go
|
||||||
void $ liftIO clean
|
void $ liftIO clean
|
||||||
next cleanup
|
next $ return True
|
||||||
where
|
where
|
||||||
{- Walk tree from top and move all present direct mode files into
|
{- Walk tree from top and move all present direct mode files into
|
||||||
- the annex, replacing with symlinks. Also delete direct mode
|
- the annex, replacing with symlinks. Also delete direct mode
|
||||||
|
@ -80,7 +79,6 @@ perform = do
|
||||||
go _ = noop
|
go _ = noop
|
||||||
|
|
||||||
fromdirect f k = do
|
fromdirect f k = do
|
||||||
showStart "indirect" f
|
|
||||||
removeInodeCache k
|
removeInodeCache k
|
||||||
removeAssociatedFiles k
|
removeAssociatedFiles k
|
||||||
whenM (liftIO $ not . isSymbolicLink <$> getSymbolicLinkStatus f) $ do
|
whenM (liftIO $ not . isSymbolicLink <$> getSymbolicLinkStatus f) $ do
|
||||||
|
@ -92,14 +90,7 @@ perform = do
|
||||||
Right False -> warnlocked "Failed to move file to annex"
|
Right False -> warnlocked "Failed to move file to annex"
|
||||||
Left e -> catchNonAsync (restoreFile f k e) $
|
Left e -> catchNonAsync (restoreFile f k e) $
|
||||||
warnlocked . show
|
warnlocked . show
|
||||||
showEndOk
|
|
||||||
|
|
||||||
warnlocked msg = do
|
warnlocked msg = do
|
||||||
warning msg
|
warning msg
|
||||||
warning "leaving this file as-is; correct this problem and run git annex add on it"
|
warning "leaving this file as-is; correct this problem and run git annex add on it"
|
||||||
|
|
||||||
cleanup :: CommandCleanup
|
|
||||||
cleanup = do
|
|
||||||
showStart' "indirect" Nothing
|
|
||||||
showEndOk
|
|
||||||
return True
|
|
||||||
|
|
|
@ -46,9 +46,8 @@ seek :: InitOptions -> CommandSeek
|
||||||
seek = commandAction . start
|
seek = commandAction . start
|
||||||
|
|
||||||
start :: InitOptions -> CommandStart
|
start :: InitOptions -> CommandStart
|
||||||
start os = do
|
start os = starting "init" (ActionItemOther (Just $ initDesc os)) $
|
||||||
showStart' "init" (Just $ initDesc os)
|
perform os
|
||||||
next $ perform os
|
|
||||||
|
|
||||||
perform :: InitOptions -> CommandPerform
|
perform :: InitOptions -> CommandPerform
|
||||||
perform os = do
|
perform os = do
|
||||||
|
|
|
@ -37,9 +37,8 @@ start (name:ws) = ifM (isJust <$> findExisting name)
|
||||||
, do
|
, do
|
||||||
let c = newConfig name
|
let c = newConfig name
|
||||||
t <- either giveup return (findType config)
|
t <- either giveup return (findType config)
|
||||||
|
starting "initremote" (ActionItemOther (Just name)) $
|
||||||
showStart' "initremote" (Just name)
|
perform t name $ M.union config c
|
||||||
next $ perform t name $ M.union config c
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
|
@ -45,17 +45,11 @@ seek o = do
|
||||||
start :: S.Set Key -> FilePath -> Key -> CommandStart
|
start :: S.Set Key -> FilePath -> Key -> CommandStart
|
||||||
start s _file k
|
start s _file k
|
||||||
| S.member k s = start' k
|
| S.member k s = start' k
|
||||||
| otherwise = notInprogress
|
| otherwise = stop
|
||||||
|
|
||||||
start' :: Key -> CommandStart
|
start' :: Key -> CommandStart
|
||||||
start' k = do
|
start' k = startingCustomOutput k $ do
|
||||||
tmpf <- fromRepo $ gitAnnexTmpObjectLocation k
|
tmpf <- fromRepo $ gitAnnexTmpObjectLocation k
|
||||||
ifM (liftIO $ doesFileExist tmpf)
|
whenM (liftIO $ doesFileExist tmpf) $
|
||||||
( next $ next $ do
|
liftIO $ putStrLn tmpf
|
||||||
liftIO $ putStrLn tmpf
|
next $ return True
|
||||||
return True
|
|
||||||
, notInprogress
|
|
||||||
)
|
|
||||||
|
|
||||||
notInprogress :: CommandStart
|
|
||||||
notInprogress = stop
|
|
||||||
|
|
|
@ -41,8 +41,7 @@ seek ps = do
|
||||||
startNew :: FilePath -> Key -> CommandStart
|
startNew :: FilePath -> Key -> CommandStart
|
||||||
startNew file key = ifM (isJust <$> isAnnexLink file)
|
startNew file key = ifM (isJust <$> isAnnexLink file)
|
||||||
( stop
|
( stop
|
||||||
, do
|
, starting "lock" (mkActionItem (key, file)) $
|
||||||
showStart "lock" file
|
|
||||||
go =<< liftIO (isPointerFile file)
|
go =<< liftIO (isPointerFile file)
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
@ -57,7 +56,7 @@ startNew file key = ifM (isJust <$> isAnnexLink file)
|
||||||
, errorModified
|
, errorModified
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
cont = next $ performNew file key
|
cont = performNew file key
|
||||||
|
|
||||||
performNew :: FilePath -> Key -> CommandPerform
|
performNew :: FilePath -> Key -> CommandPerform
|
||||||
performNew file key = do
|
performNew file key = do
|
||||||
|
@ -106,10 +105,10 @@ cleanupNew file key = do
|
||||||
|
|
||||||
startOld :: FilePath -> CommandStart
|
startOld :: FilePath -> CommandStart
|
||||||
startOld file = do
|
startOld file = do
|
||||||
showStart "lock" file
|
|
||||||
unlessM (Annex.getState Annex.force)
|
unlessM (Annex.getState Annex.force)
|
||||||
errorModified
|
errorModified
|
||||||
next $ performOld file
|
starting "lock" (ActionItemWorkTreeFile file) $
|
||||||
|
performOld file
|
||||||
|
|
||||||
performOld :: FilePath -> CommandPerform
|
performOld :: FilePath -> CommandPerform
|
||||||
performOld file = do
|
performOld file = do
|
||||||
|
|
|
@ -40,7 +40,7 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withNothing (commandAction start)
|
seek = withNothing (commandAction start)
|
||||||
|
|
||||||
start :: CommandStart
|
start :: CommandStart
|
||||||
start = do
|
start = startingNoMessage (ActionItemOther Nothing) $ do
|
||||||
rs <- combineSame <$> (spider =<< gitRepo)
|
rs <- combineSame <$> (spider =<< gitRepo)
|
||||||
|
|
||||||
umap <- uuidDescMap
|
umap <- uuidDescMap
|
||||||
|
@ -49,7 +49,7 @@ start = do
|
||||||
file <- (</>) <$> fromRepo gitAnnexDir <*> pure "map.dot"
|
file <- (</>) <$> fromRepo gitAnnexDir <*> pure "map.dot"
|
||||||
|
|
||||||
liftIO $ writeFile file (drawMap rs trustmap umap)
|
liftIO $ writeFile file (drawMap rs trustmap umap)
|
||||||
next $ next $
|
next $
|
||||||
ifM (Annex.getState Annex.fast)
|
ifM (Annex.getState Annex.fast)
|
||||||
( runViewer file []
|
( runViewer file []
|
||||||
, runViewer file
|
, runViewer file
|
||||||
|
|
|
@ -23,13 +23,11 @@ seek _ = do
|
||||||
commandAction mergeSynced
|
commandAction mergeSynced
|
||||||
|
|
||||||
mergeBranch :: CommandStart
|
mergeBranch :: CommandStart
|
||||||
mergeBranch = do
|
mergeBranch = starting "merge" (ActionItemOther (Just "git-annex")) $ do
|
||||||
showStart' "merge" (Just "git-annex")
|
Annex.Branch.update
|
||||||
next $ do
|
-- commit explicitly, in case no remote branches were merged
|
||||||
Annex.Branch.update
|
Annex.Branch.commit =<< Annex.Branch.commitMessage
|
||||||
-- commit explicitly, in case no remote branches were merged
|
next $ return True
|
||||||
Annex.Branch.commit =<< Annex.Branch.commitMessage
|
|
||||||
next $ return True
|
|
||||||
|
|
||||||
mergeSynced :: CommandStart
|
mergeSynced :: CommandStart
|
||||||
mergeSynced = do
|
mergeSynced = do
|
||||||
|
|
|
@ -99,14 +99,13 @@ start c o file k = startKeys c o (k, mkActionItem (k, afile))
|
||||||
|
|
||||||
startKeys :: VectorClock -> MetaDataOptions -> (Key, ActionItem) -> CommandStart
|
startKeys :: VectorClock -> MetaDataOptions -> (Key, ActionItem) -> CommandStart
|
||||||
startKeys c o (k, ai) = case getSet o of
|
startKeys c o (k, ai) = case getSet o of
|
||||||
Get f -> do
|
Get f -> startingCustomOutput k $ do
|
||||||
l <- S.toList . currentMetaDataValues f <$> getCurrentMetaData k
|
l <- S.toList . currentMetaDataValues f <$> getCurrentMetaData k
|
||||||
liftIO $ forM_ l $
|
liftIO $ forM_ l $
|
||||||
B8.putStrLn . fromMetaValue
|
B8.putStrLn . fromMetaValue
|
||||||
stop
|
next $ return True
|
||||||
_ -> do
|
_ -> starting "metadata" ai $
|
||||||
showStartKey "metadata" k ai
|
perform c o k
|
||||||
next $ perform c o k
|
|
||||||
|
|
||||||
perform :: VectorClock -> MetaDataOptions -> Key -> CommandPerform
|
perform :: VectorClock -> MetaDataOptions -> Key -> CommandPerform
|
||||||
perform c o k = case getSet o of
|
perform c o k = case getSet o of
|
||||||
|
@ -168,8 +167,7 @@ startBatch (i, (MetaData m)) = case i of
|
||||||
Nothing -> giveup $ "not an annexed file: " ++ f
|
Nothing -> giveup $ "not an annexed file: " ++ f
|
||||||
Right k -> go k (mkActionItem k)
|
Right k -> go k (mkActionItem k)
|
||||||
where
|
where
|
||||||
go k ai = do
|
go k ai = starting "metadata" ai $ do
|
||||||
showStartKey "metadata" k ai
|
|
||||||
let o = MetaDataOptions
|
let o = MetaDataOptions
|
||||||
{ forFiles = []
|
{ forFiles = []
|
||||||
, getSet = if MetaData m == emptyMetaData
|
, getSet = if MetaData m == emptyMetaData
|
||||||
|
@ -187,7 +185,7 @@ startBatch (i, (MetaData m)) = case i of
|
||||||
-- probably less expensive than cleaner methods,
|
-- probably less expensive than cleaner methods,
|
||||||
-- such as taking from a list of increasing timestamps.
|
-- such as taking from a list of increasing timestamps.
|
||||||
liftIO $ threadDelay 1
|
liftIO $ threadDelay 1
|
||||||
next $ perform t o k
|
perform t o k
|
||||||
mkModMeta (f, s)
|
mkModMeta (f, s)
|
||||||
| S.null s = DelMeta f Nothing
|
| S.null s = DelMeta f Nothing
|
||||||
| otherwise = SetMeta f s
|
| otherwise = SetMeta f s
|
||||||
|
|
|
@ -38,9 +38,8 @@ start file key = do
|
||||||
newbackend <- maybe defaultBackend return
|
newbackend <- maybe defaultBackend return
|
||||||
=<< chooseBackend file
|
=<< chooseBackend file
|
||||||
if (newbackend /= oldbackend || upgradableKey oldbackend key || forced) && exists
|
if (newbackend /= oldbackend || upgradableKey oldbackend key || forced) && exists
|
||||||
then do
|
then starting "migrate" (mkActionItem (key, file)) $
|
||||||
showStart "migrate" file
|
perform file key oldbackend newbackend
|
||||||
next $ perform file key oldbackend newbackend
|
|
||||||
else stop
|
else stop
|
||||||
|
|
||||||
{- Checks if a key is upgradable to a newer representation.
|
{- Checks if a key is upgradable to a newer representation.
|
||||||
|
|
|
@ -54,7 +54,7 @@ start o file k = startKey o afile (k, ai)
|
||||||
ai = mkActionItem (k, afile)
|
ai = mkActionItem (k, afile)
|
||||||
|
|
||||||
startKey :: MirrorOptions -> AssociatedFile -> (Key, ActionItem) -> CommandStart
|
startKey :: MirrorOptions -> AssociatedFile -> (Key, ActionItem) -> CommandStart
|
||||||
startKey o afile (key, ai) = onlyActionOn key $ case fromToOptions o of
|
startKey o afile (key, ai) = case fromToOptions o of
|
||||||
ToRemote r -> checkFailedTransferDirection ai Upload $ ifM (inAnnex key)
|
ToRemote r -> checkFailedTransferDirection ai Upload $ ifM (inAnnex key)
|
||||||
( Command.Move.toStart Command.Move.RemoveNever afile key ai =<< getParsed r
|
( Command.Move.toStart Command.Move.RemoveNever afile key ai =<< getParsed r
|
||||||
, do
|
, do
|
||||||
|
|
|
@ -74,7 +74,7 @@ startKey fromto removewhen =
|
||||||
uncurry $ start' fromto removewhen (AssociatedFile Nothing)
|
uncurry $ start' fromto removewhen (AssociatedFile Nothing)
|
||||||
|
|
||||||
start' :: FromToHereOptions -> RemoveWhen -> AssociatedFile -> Key -> ActionItem -> CommandStart
|
start' :: FromToHereOptions -> RemoveWhen -> AssociatedFile -> Key -> ActionItem -> CommandStart
|
||||||
start' fromto removewhen afile key ai = onlyActionOn key $
|
start' fromto removewhen afile key ai =
|
||||||
case fromto of
|
case fromto of
|
||||||
Right (FromRemote src) ->
|
Right (FromRemote src) ->
|
||||||
checkFailedTransferDirection ai Download $
|
checkFailedTransferDirection ai Download $
|
||||||
|
@ -86,9 +86,9 @@ start' fromto removewhen afile key ai = onlyActionOn key $
|
||||||
checkFailedTransferDirection ai Download $
|
checkFailedTransferDirection ai Download $
|
||||||
toHereStart removewhen afile key ai
|
toHereStart removewhen afile key ai
|
||||||
|
|
||||||
showMoveAction :: RemoveWhen -> Key -> ActionItem -> Annex ()
|
describeMoveAction :: RemoveWhen -> String
|
||||||
showMoveAction RemoveNever = showStartKey "copy"
|
describeMoveAction RemoveNever = "copy"
|
||||||
showMoveAction _ = showStartKey "move"
|
describeMoveAction _ = "move"
|
||||||
|
|
||||||
toStart :: RemoveWhen -> AssociatedFile -> Key -> ActionItem -> Remote -> CommandStart
|
toStart :: RemoveWhen -> AssociatedFile -> Key -> ActionItem -> Remote -> CommandStart
|
||||||
toStart removewhen afile key ai dest = do
|
toStart removewhen afile key ai dest = do
|
||||||
|
@ -108,9 +108,9 @@ toStart' dest removewhen afile key ai = do
|
||||||
)
|
)
|
||||||
else go False (Remote.hasKey dest key)
|
else go False (Remote.hasKey dest key)
|
||||||
where
|
where
|
||||||
go fastcheck isthere = do
|
go fastcheck isthere =
|
||||||
showMoveAction removewhen key ai
|
starting (describeMoveAction removewhen) (OnlyActionOn key ai) $
|
||||||
next $ toPerform dest removewhen key afile fastcheck =<< isthere
|
toPerform dest removewhen key afile fastcheck =<< isthere
|
||||||
|
|
||||||
expectedPresent :: Remote -> Key -> Annex Bool
|
expectedPresent :: Remote -> Key -> Annex Bool
|
||||||
expectedPresent dest key = do
|
expectedPresent dest key = do
|
||||||
|
@ -182,9 +182,9 @@ fromStart removewhen afile key ai src = case removewhen of
|
||||||
RemoveNever -> stopUnless (not <$> inAnnex key) go
|
RemoveNever -> stopUnless (not <$> inAnnex key) go
|
||||||
RemoveSafe -> go
|
RemoveSafe -> go
|
||||||
where
|
where
|
||||||
go = stopUnless (fromOk src key) $ do
|
go = stopUnless (fromOk src key) $
|
||||||
showMoveAction removewhen key ai
|
starting (describeMoveAction removewhen) (OnlyActionOn key ai) $
|
||||||
next $ fromPerform src removewhen key afile
|
fromPerform src removewhen key afile
|
||||||
|
|
||||||
fromOk :: Remote -> Key -> Annex Bool
|
fromOk :: Remote -> Key -> Annex Bool
|
||||||
fromOk src key
|
fromOk src key
|
||||||
|
@ -247,13 +247,13 @@ toHereStart removewhen afile key ai = case removewhen of
|
||||||
RemoveNever -> stopUnless (not <$> inAnnex key) go
|
RemoveNever -> stopUnless (not <$> inAnnex key) go
|
||||||
RemoveSafe -> go
|
RemoveSafe -> go
|
||||||
where
|
where
|
||||||
go = do
|
go = startingNoMessage (OnlyActionOn key ai) $ do
|
||||||
rs <- Remote.keyPossibilities key
|
rs <- Remote.keyPossibilities key
|
||||||
forM_ rs $ \r ->
|
forM_ rs $ \r ->
|
||||||
includeCommandAction $ do
|
includeCommandAction $
|
||||||
showMoveAction removewhen key ai
|
starting (describeMoveAction removewhen) ai $
|
||||||
next $ fromPerform r removewhen key afile
|
fromPerform r removewhen key afile
|
||||||
stop
|
next $ return True
|
||||||
|
|
||||||
{- 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
|
||||||
- files as they like, while avoiding making bad situations any worse
|
- files as they like, while avoiding making bad situations any worse
|
||||||
|
|
|
@ -79,8 +79,7 @@ seek (MultiCastOptions Receive ups []) = commandAction $ receive ups
|
||||||
seek (MultiCastOptions Receive _ _) = giveup "Cannot specify list of files with --receive; this receives whatever files the sender chooses to send."
|
seek (MultiCastOptions Receive _ _) = giveup "Cannot specify list of files with --receive; this receives whatever files the sender chooses to send."
|
||||||
|
|
||||||
genAddress :: CommandStart
|
genAddress :: CommandStart
|
||||||
genAddress = do
|
genAddress = starting "gen-address" (ActionItemOther Nothing) $ do
|
||||||
showStart' "gen-address" Nothing
|
|
||||||
k <- uftpKey
|
k <- uftpKey
|
||||||
(s, ok) <- case k of
|
(s, ok) <- case k of
|
||||||
KeyContainer s -> liftIO $ genkey (Param s)
|
KeyContainer s -> liftIO $ genkey (Param s)
|
||||||
|
@ -91,7 +90,7 @@ genAddress = do
|
||||||
case (ok, parseFingerprint s) of
|
case (ok, parseFingerprint s) of
|
||||||
(False, _) -> giveup $ "uftp_keymgt failed: " ++ s
|
(False, _) -> giveup $ "uftp_keymgt failed: " ++ s
|
||||||
(_, Nothing) -> giveup $ "Failed to find fingerprint in uftp_keymgt output: " ++ s
|
(_, Nothing) -> giveup $ "Failed to find fingerprint in uftp_keymgt output: " ++ s
|
||||||
(True, Just fp) -> next $ next $ do
|
(True, Just fp) -> next $ do
|
||||||
recordFingerprint fp =<< getUUID
|
recordFingerprint fp =<< getUUID
|
||||||
return True
|
return True
|
||||||
where
|
where
|
||||||
|
@ -123,7 +122,7 @@ parseFingerprint = Fingerprint <$$> lastMaybe . filter isfingerprint . words
|
||||||
in length os == 20
|
in length os == 20
|
||||||
|
|
||||||
send :: [CommandParam] -> [FilePath] -> CommandStart
|
send :: [CommandParam] -> [FilePath] -> CommandStart
|
||||||
send ups fs = withTmpFile "send" $ \t h -> do
|
send ups fs = do
|
||||||
-- Need to be able to send files with the names of git-annex
|
-- Need to be able to send files with the names of git-annex
|
||||||
-- keys, and uftp does not allow renaming the files that are sent.
|
-- keys, and uftp does not allow renaming the files that are sent.
|
||||||
-- In a direct mode repository, the annex objects do not have
|
-- In a direct mode repository, the annex objects do not have
|
||||||
|
@ -131,47 +130,43 @@ send ups fs = withTmpFile "send" $ \t h -> do
|
||||||
-- expensive.
|
-- expensive.
|
||||||
whenM isDirect $
|
whenM isDirect $
|
||||||
giveup "Sorry, multicast send cannot be done from a direct mode repository."
|
giveup "Sorry, multicast send cannot be done from a direct mode repository."
|
||||||
|
starting "sending files" (ActionItemOther Nothing) $
|
||||||
|
withTmpFile "send" $ \t h -> do
|
||||||
|
fs' <- seekHelper LsFiles.inRepo =<< workTreeItems fs
|
||||||
|
matcher <- Limit.getMatcher
|
||||||
|
let addlist f o = whenM (matcher $ MatchingFile $ FileInfo f f) $
|
||||||
|
liftIO $ hPutStrLn h o
|
||||||
|
forM_ fs' $ \f -> do
|
||||||
|
mk <- lookupFile f
|
||||||
|
case mk of
|
||||||
|
Nothing -> noop
|
||||||
|
Just k -> withObjectLoc k (addlist f) (const noop)
|
||||||
|
liftIO $ hClose h
|
||||||
|
|
||||||
showStart' "generating file list" Nothing
|
serverkey <- uftpKey
|
||||||
fs' <- seekHelper LsFiles.inRepo =<< workTreeItems fs
|
u <- getUUID
|
||||||
matcher <- Limit.getMatcher
|
withAuthList $ \authlist -> do
|
||||||
let addlist f o = whenM (matcher $ MatchingFile $ FileInfo f f) $
|
let ps =
|
||||||
liftIO $ hPutStrLn h o
|
-- Force client authentication.
|
||||||
forM_ fs' $ \f -> do
|
[ Param "-c"
|
||||||
mk <- lookupFile f
|
, Param "-Y", Param "aes256-cbc"
|
||||||
case mk of
|
, Param "-h", Param "sha512"
|
||||||
Nothing -> noop
|
-- Picked ecdh_ecdsa for perfect forward secrecy,
|
||||||
Just k -> withObjectLoc k (addlist f) (const noop)
|
-- and because a EC key exchange algorithm is
|
||||||
liftIO $ hClose h
|
-- needed since all keys are EC.
|
||||||
showEndOk
|
, Param "-e", Param "ecdh_ecdsa"
|
||||||
|
, Param "-k", uftpKeyParam serverkey
|
||||||
showStart' "sending files" Nothing
|
, Param "-U", Param (uftpUID u)
|
||||||
showOutput
|
-- only allow clients on the authlist
|
||||||
serverkey <- uftpKey
|
, Param "-H", Param ("@"++authlist)
|
||||||
u <- getUUID
|
-- pass in list of files to send
|
||||||
withAuthList $ \authlist -> do
|
, Param "-i", File t
|
||||||
let ps =
|
] ++ ups
|
||||||
-- Force client authentication.
|
liftIO (boolSystem "uftp" ps) >>= showEndResult
|
||||||
[ Param "-c"
|
next $ return True
|
||||||
, Param "-Y", Param "aes256-cbc"
|
|
||||||
, Param "-h", Param "sha512"
|
|
||||||
-- Picked ecdh_ecdsa for perfect forward secrecy,
|
|
||||||
-- and because a EC key exchange algorithm is
|
|
||||||
-- needed since all keys are EC.
|
|
||||||
, Param "-e", Param "ecdh_ecdsa"
|
|
||||||
, Param "-k", uftpKeyParam serverkey
|
|
||||||
, Param "-U", Param (uftpUID u)
|
|
||||||
-- only allow clients on the authlist
|
|
||||||
, Param "-H", Param ("@"++authlist)
|
|
||||||
-- pass in list of files to send
|
|
||||||
, Param "-i", File t
|
|
||||||
] ++ ups
|
|
||||||
liftIO (boolSystem "uftp" ps) >>= showEndResult
|
|
||||||
stop
|
|
||||||
|
|
||||||
receive :: [CommandParam] -> CommandStart
|
receive :: [CommandParam] -> CommandStart
|
||||||
receive ups = do
|
receive ups = starting "receiving multicast files" (ActionItemOther Nothing) $ do
|
||||||
showStart' "receiving multicast files" Nothing
|
|
||||||
showNote "Will continue to run until stopped by ctrl-c"
|
showNote "Will continue to run until stopped by ctrl-c"
|
||||||
|
|
||||||
showOutput
|
showOutput
|
||||||
|
@ -204,7 +199,7 @@ receive ups = do
|
||||||
`after` boolSystemEnv "uftpd" ps (Just environ)
|
`after` boolSystemEnv "uftpd" ps (Just environ)
|
||||||
mapM_ storeReceived . lines =<< liftIO (hGetContents statush)
|
mapM_ storeReceived . lines =<< liftIO (hGetContents statush)
|
||||||
showEndResult =<< liftIO (wait runner)
|
showEndResult =<< liftIO (wait runner)
|
||||||
stop
|
next $ return True
|
||||||
|
|
||||||
storeReceived :: FilePath -> Annex ()
|
storeReceived :: FilePath -> Annex ()
|
||||||
storeReceived f = do
|
storeReceived f = do
|
||||||
|
|
|
@ -33,7 +33,7 @@ start [s] = case readish s of
|
||||||
start _ = giveup "Specify a single number."
|
start _ = giveup "Specify a single number."
|
||||||
|
|
||||||
startGet :: CommandStart
|
startGet :: CommandStart
|
||||||
startGet = next $ next $ do
|
startGet = startingCustomOutput (ActionItemOther Nothing) $ next $ do
|
||||||
v <- getGlobalNumCopies
|
v <- getGlobalNumCopies
|
||||||
case v of
|
case v of
|
||||||
Just n -> liftIO $ putStrLn $ show $ fromNumCopies n
|
Just n -> liftIO $ putStrLn $ show $ fromNumCopies n
|
||||||
|
@ -46,9 +46,6 @@ startGet = next $ next $ do
|
||||||
return True
|
return True
|
||||||
|
|
||||||
startSet :: Int -> CommandStart
|
startSet :: Int -> CommandStart
|
||||||
startSet n = do
|
startSet n = startingUsualMessages "numcopies" (ActionItemOther (Just $ show n)) $ do
|
||||||
allowMessages
|
setGlobalNumCopies $ NumCopies n
|
||||||
showStart' "numcopies" (Just $ show n)
|
next $ return True
|
||||||
next $ next $ do
|
|
||||||
setGlobalNumCopies $ NumCopies n
|
|
||||||
return True
|
|
||||||
|
|
|
@ -96,9 +96,8 @@ genAddresses addrs = do
|
||||||
|
|
||||||
-- Address is read from stdin, to avoid leaking it in shell history.
|
-- Address is read from stdin, to avoid leaking it in shell history.
|
||||||
linkRemote :: RemoteName -> CommandStart
|
linkRemote :: RemoteName -> CommandStart
|
||||||
linkRemote remotename = do
|
linkRemote remotename = starting "p2p link" (ActionItemOther (Just remotename)) $
|
||||||
showStart' "p2p link" (Just remotename)
|
next promptaddr
|
||||||
next $ next promptaddr
|
|
||||||
where
|
where
|
||||||
promptaddr = do
|
promptaddr = do
|
||||||
liftIO $ putStrLn ""
|
liftIO $ putStrLn ""
|
||||||
|
@ -122,12 +121,11 @@ linkRemote remotename = do
|
||||||
|
|
||||||
startPairing :: RemoteName -> [P2PAddress] -> CommandStart
|
startPairing :: RemoteName -> [P2PAddress] -> CommandStart
|
||||||
startPairing _ [] = giveup "No P2P networks are currrently available."
|
startPairing _ [] = giveup "No P2P networks are currrently available."
|
||||||
startPairing remotename addrs = do
|
startPairing remotename addrs = ifM (liftIO Wormhole.isInstalled)
|
||||||
showStart' "p2p pair" (Just remotename)
|
( starting "p2p pair" (ActionItemOther (Just remotename)) $
|
||||||
ifM (liftIO Wormhole.isInstalled)
|
performPairing remotename addrs
|
||||||
( next $ performPairing remotename addrs
|
, giveup "Magic Wormhole is not installed, and is needed for pairing. Install it from your distribution or from https://github.com/warner/magic-wormhole/"
|
||||||
, giveup "Magic Wormhole is not installed, and is needed for pairing. Install it from your distribution or from https://github.com/warner/magic-wormhole/"
|
)
|
||||||
)
|
|
||||||
|
|
||||||
performPairing :: RemoteName -> [P2PAddress] -> CommandPerform
|
performPairing :: RemoteName -> [P2PAddress] -> CommandPerform
|
||||||
performPairing remotename addrs = do
|
performPairing remotename addrs = do
|
||||||
|
|
|
@ -27,7 +27,7 @@ seek [u] = commandAction $ start $ toUUID u
|
||||||
seek _ = giveup "missing UUID parameter"
|
seek _ = giveup "missing UUID parameter"
|
||||||
|
|
||||||
start :: UUID -> CommandStart
|
start :: UUID -> CommandStart
|
||||||
start theiruuid = do
|
start theiruuid = startingCustomOutput (ActionItemOther Nothing) $ do
|
||||||
servermode <- liftIO $ do
|
servermode <- liftIO $ do
|
||||||
ro <- Checks.checkEnvSet Checks.readOnlyEnv
|
ro <- Checks.checkEnvSet Checks.readOnlyEnv
|
||||||
ao <- Checks.checkEnvSet Checks.appendOnlyEnv
|
ao <- Checks.checkEnvSet Checks.appendOnlyEnv
|
||||||
|
@ -47,4 +47,4 @@ start theiruuid = do
|
||||||
Left (ProtoFailureIOError e) | isEOFError e -> done
|
Left (ProtoFailureIOError e) | isEOFError e -> done
|
||||||
Left e -> giveup (describeProtoFailure e)
|
Left e -> giveup (describeProtoFailure e)
|
||||||
where
|
where
|
||||||
done = next $ next $ return True
|
done = next $ return True
|
||||||
|
|
|
@ -84,23 +84,22 @@ seek ps = lockPreCommitHook $ ifM isDirect
|
||||||
|
|
||||||
|
|
||||||
startInjectUnlocked :: FilePath -> CommandStart
|
startInjectUnlocked :: FilePath -> CommandStart
|
||||||
startInjectUnlocked f = next $ do
|
startInjectUnlocked f = startingCustomOutput (ActionItemOther Nothing) $ do
|
||||||
unlessM (callCommandAction $ Command.Add.start f) $
|
unlessM (callCommandAction $ Command.Add.start f) $
|
||||||
error $ "failed to add " ++ f ++ "; canceling commit"
|
error $ "failed to add " ++ f ++ "; canceling commit"
|
||||||
next $ return True
|
next $ return True
|
||||||
|
|
||||||
startDirect :: [String] -> CommandStart
|
startDirect :: [String] -> CommandStart
|
||||||
startDirect _ = next $ next preCommitDirect
|
startDirect _ = startingCustomOutput (ActionItemOther Nothing) $
|
||||||
|
next preCommitDirect
|
||||||
|
|
||||||
addViewMetaData :: View -> ViewedFile -> Key -> CommandStart
|
addViewMetaData :: View -> ViewedFile -> Key -> CommandStart
|
||||||
addViewMetaData v f k = do
|
addViewMetaData v f k = starting "metadata" (mkActionItem (k, f)) $
|
||||||
showStart "metadata" f
|
next $ changeMetaData k $ fromView v f
|
||||||
next $ next $ changeMetaData k $ fromView v f
|
|
||||||
|
|
||||||
removeViewMetaData :: View -> ViewedFile -> Key -> CommandStart
|
removeViewMetaData :: View -> ViewedFile -> Key -> CommandStart
|
||||||
removeViewMetaData v f k = do
|
removeViewMetaData v f k = starting "metadata" (mkActionItem (k, f)) $
|
||||||
showStart "metadata" f
|
next $ changeMetaData k $ unsetMetaData $ fromView v f
|
||||||
next $ next $ changeMetaData k $ unsetMetaData $ fromView v f
|
|
||||||
|
|
||||||
changeMetaData :: Key -> MetaData -> CommandCleanup
|
changeMetaData :: Key -> MetaData -> CommandCleanup
|
||||||
changeMetaData k metadata = do
|
changeMetaData k metadata = do
|
||||||
|
|
|
@ -60,9 +60,8 @@ start (file, newkey) = ifAnnexed file go stop
|
||||||
where
|
where
|
||||||
go oldkey
|
go oldkey
|
||||||
| oldkey == newkey = stop
|
| oldkey == newkey = stop
|
||||||
| otherwise = do
|
| otherwise = starting "rekey" (ActionItemWorkTreeFile file) $
|
||||||
showStart "rekey" file
|
perform file oldkey newkey
|
||||||
next $ perform file oldkey newkey
|
|
||||||
|
|
||||||
perform :: FilePath -> Key -> Key -> CommandPerform
|
perform :: FilePath -> Key -> Key -> CommandPerform
|
||||||
perform file oldkey newkey = do
|
perform file oldkey newkey = do
|
||||||
|
|
|
@ -39,16 +39,16 @@ seek o = case (batchOption o, keyUrlPairs o) of
|
||||||
(NoBatch, ps) -> withWords (commandAction . start) ps
|
(NoBatch, ps) -> withWords (commandAction . start) ps
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start (keyname:url:[]) = do
|
start (keyname:url:[]) =
|
||||||
let key = mkKey keyname
|
starting "registerurl" (ActionItemOther (Just url)) $ do
|
||||||
showStart' "registerurl" (Just url)
|
let key = mkKey keyname
|
||||||
next $ perform key url
|
perform key url
|
||||||
start _ = giveup "specify a key and an url"
|
start _ = giveup "specify a key and an url"
|
||||||
|
|
||||||
startMass :: BatchFormat -> CommandStart
|
startMass :: BatchFormat -> CommandStart
|
||||||
startMass fmt = do
|
startMass fmt =
|
||||||
showStart' "registerurl" (Just "stdin")
|
starting "registerurl" (ActionItemOther (Just "stdin")) $
|
||||||
next (massAdd fmt)
|
massAdd fmt
|
||||||
|
|
||||||
massAdd :: BatchFormat -> CommandPerform
|
massAdd :: BatchFormat -> CommandPerform
|
||||||
massAdd fmt = go True =<< map (separate (== ' ')) <$> batchLines fmt
|
massAdd fmt = go True =<< map (separate (== ' ')) <$> batchLines fmt
|
||||||
|
|
|
@ -24,9 +24,8 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withWords (commandAction . start)
|
seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start ws = do
|
start ws = starting "reinit" (ActionItemOther (Just s)) $
|
||||||
showStart' "reinit" (Just s)
|
perform s
|
||||||
next $ perform s
|
|
||||||
where
|
where
|
||||||
s = unwords ws
|
s = unwords ws
|
||||||
|
|
||||||
|
|
|
@ -41,28 +41,27 @@ seek os
|
||||||
startSrcDest :: [FilePath] -> CommandStart
|
startSrcDest :: [FilePath] -> CommandStart
|
||||||
startSrcDest (src:dest:[])
|
startSrcDest (src:dest:[])
|
||||||
| src == dest = stop
|
| src == dest = stop
|
||||||
| otherwise = notAnnexed src $ do
|
| otherwise = notAnnexed src $ ifAnnexed dest go stop
|
||||||
showStart "reinject" dest
|
|
||||||
next $ ifAnnexed dest go stop
|
|
||||||
where
|
where
|
||||||
go key = ifM (verifyKeyContent RetrievalAllKeysSecure DefaultVerify UnVerified key src)
|
go key = starting "reinject" (ActionItemOther (Just src)) $
|
||||||
( perform src key
|
ifM (verifyKeyContent RetrievalAllKeysSecure DefaultVerify UnVerified key src)
|
||||||
, giveup $ src ++ " does not have expected content of " ++ dest
|
( perform src key
|
||||||
)
|
, giveup $ src ++ " does not have expected content of " ++ dest
|
||||||
|
)
|
||||||
startSrcDest _ = giveup "specify a src file and a dest file"
|
startSrcDest _ = giveup "specify a src file and a dest file"
|
||||||
|
|
||||||
startKnown :: FilePath -> CommandStart
|
startKnown :: FilePath -> CommandStart
|
||||||
startKnown src = notAnnexed src $ do
|
startKnown src = notAnnexed src $
|
||||||
showStart "reinject" src
|
starting "reinject" (ActionItemOther (Just src)) $ do
|
||||||
mkb <- genKey (KeySource src src Nothing) Nothing
|
mkb <- genKey (KeySource src src Nothing) Nothing
|
||||||
case mkb of
|
case mkb of
|
||||||
Nothing -> error "Failed to generate key"
|
Nothing -> error "Failed to generate key"
|
||||||
Just (key, _) -> ifM (isKnownKey key)
|
Just (key, _) -> ifM (isKnownKey key)
|
||||||
( next $ perform src key
|
( perform src key
|
||||||
, do
|
, do
|
||||||
warning "Not known content; skipping"
|
warning "Not known content; skipping"
|
||||||
next $ next $ return True
|
next $ return True
|
||||||
)
|
)
|
||||||
|
|
||||||
notAnnexed :: FilePath -> CommandStart -> CommandStart
|
notAnnexed :: FilePath -> CommandStart -> CommandStart
|
||||||
notAnnexed src = ifAnnexed src $
|
notAnnexed src = ifAnnexed src $
|
||||||
|
|
|
@ -40,9 +40,8 @@ start (oldname:newname:[]) = Annex.SpecialRemote.findExisting oldname >>= \case
|
||||||
Nothing -> giveup "That is not a special remote."
|
Nothing -> giveup "That is not a special remote."
|
||||||
Just cfg -> go u cfg
|
Just cfg -> go u cfg
|
||||||
where
|
where
|
||||||
go u cfg = do
|
go u cfg = starting "rename" (ActionItemOther Nothing) $
|
||||||
showStart' "rename" Nothing
|
perform u cfg newname
|
||||||
next $ perform u cfg newname
|
|
||||||
start _ = giveup "Specify an old name (or uuid or description) and a new name."
|
start _ = giveup "Specify an old name (or uuid or description) and a new name."
|
||||||
|
|
||||||
perform :: UUID -> R.RemoteConfig -> String -> CommandPerform
|
perform :: UUID -> R.RemoteConfig -> String -> CommandPerform
|
||||||
|
|
|
@ -25,7 +25,8 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withNothing (commandAction start)
|
seek = withNothing (commandAction start)
|
||||||
|
|
||||||
start :: CommandStart
|
start :: CommandStart
|
||||||
start = next $ next $ runRepair =<< Annex.getState Annex.force
|
start = starting "repair" (ActionItemOther Nothing) $
|
||||||
|
next $ runRepair =<< Annex.getState Annex.force
|
||||||
|
|
||||||
runRepair :: Bool -> Annex Bool
|
runRepair :: Bool -> Annex Bool
|
||||||
runRepair forced = do
|
runRepair forced = do
|
||||||
|
|
|
@ -22,8 +22,7 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withNothing (commandAction start)
|
seek = withNothing (commandAction start)
|
||||||
|
|
||||||
start :: CommandStart
|
start :: CommandStart
|
||||||
start = do
|
start = starting "resolvemerge" (ActionItemOther Nothing) $ do
|
||||||
showStart' "resolvemerge" Nothing
|
|
||||||
us <- fromMaybe nobranch <$> inRepo Git.Branch.current
|
us <- fromMaybe nobranch <$> inRepo Git.Branch.current
|
||||||
d <- fromRepo Git.localGitDir
|
d <- fromRepo Git.localGitDir
|
||||||
let merge_head = d </> "MERGE_HEAD"
|
let merge_head = d </> "MERGE_HEAD"
|
||||||
|
@ -32,7 +31,7 @@ start = do
|
||||||
ifM (resolveMerge (Just us) them False)
|
ifM (resolveMerge (Just us) them False)
|
||||||
( do
|
( do
|
||||||
void $ commitResolvedMerge Git.Branch.ManualCommit
|
void $ commitResolvedMerge Git.Branch.ManualCommit
|
||||||
next $ next $ return True
|
next $ return True
|
||||||
, giveup "Merge conflict could not be automatically resolved."
|
, giveup "Merge conflict could not be automatically resolved."
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
|
@ -42,9 +42,9 @@ batchParser s = case separate (== ' ') (reverse s) of
|
||||||
| otherwise -> Right (reverse rf, reverse ru)
|
| otherwise -> Right (reverse rf, reverse ru)
|
||||||
|
|
||||||
start :: (FilePath, URLString) -> CommandStart
|
start :: (FilePath, URLString) -> CommandStart
|
||||||
start (file, url) = flip whenAnnexed file $ \_ key -> do
|
start (file, url) = flip whenAnnexed file $ \_ key ->
|
||||||
showStart "rmurl" file
|
starting "rmurl" (mkActionItem (key, AssociatedFile (Just file))) $
|
||||||
next $ next $ cleanup url key
|
next $ cleanup url key
|
||||||
|
|
||||||
cleanup :: String -> Key -> CommandCleanup
|
cleanup :: String -> Key -> CommandCleanup
|
||||||
cleanup url key = do
|
cleanup url key = do
|
||||||
|
|
|
@ -25,16 +25,15 @@ seek = withWords (commandAction . start)
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start = parse
|
start = parse
|
||||||
where
|
where
|
||||||
parse (name:[]) = go name performGet
|
parse (name:[]) = do
|
||||||
parse (name:expr:[]) = go name $ \uuid -> do
|
|
||||||
allowMessages
|
|
||||||
showStart' "schedule" (Just name)
|
|
||||||
performSet expr uuid
|
|
||||||
parse _ = giveup "Specify a repository."
|
|
||||||
|
|
||||||
go name a = do
|
|
||||||
u <- Remote.nameToUUID name
|
u <- Remote.nameToUUID name
|
||||||
next $ a u
|
startingCustomOutput (ActionItemOther Nothing) $
|
||||||
|
performGet u
|
||||||
|
parse (name:expr:[]) = do
|
||||||
|
u <- Remote.nameToUUID name
|
||||||
|
startingUsualMessages "schedule" (ActionItemOther (Just name)) $
|
||||||
|
performSet expr u
|
||||||
|
parse _ = giveup "Specify a repository."
|
||||||
|
|
||||||
performGet :: UUID -> CommandPerform
|
performGet :: UUID -> CommandPerform
|
||||||
performGet uuid = do
|
performGet uuid = do
|
||||||
|
|
|
@ -20,9 +20,8 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withWords (commandAction . start)
|
seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start (keyname:file:[]) = do
|
start (keyname:file:[]) = starting "setkey" (ActionItemOther (Just file)) $
|
||||||
showStart "setkey" file
|
perform file (mkKey keyname)
|
||||||
next $ perform file (mkKey keyname)
|
|
||||||
start _ = giveup "specify a key and a content file"
|
start _ = giveup "specify a key and a content file"
|
||||||
|
|
||||||
mkKey :: String -> Key
|
mkKey :: String -> Key
|
||||||
|
|
|
@ -47,9 +47,8 @@ parseKeyStatus (ks:us:vs:[]) = do
|
||||||
parseKeyStatus _ = Left "Bad input. Expected: key uuid value"
|
parseKeyStatus _ = Left "Bad input. Expected: key uuid value"
|
||||||
|
|
||||||
start :: KeyStatus -> CommandStart
|
start :: KeyStatus -> CommandStart
|
||||||
start (KeyStatus k u s) = do
|
start (KeyStatus k u s) = starting "setpresentkey" (mkActionItem k) $
|
||||||
showStartKey "setpresentkey" k (mkActionItem k)
|
perform k u s
|
||||||
next $ perform k u s
|
|
||||||
|
|
||||||
perform :: Key -> UUID -> LogStatus -> CommandPerform
|
perform :: Key -> UUID -> LogStatus -> CommandPerform
|
||||||
perform k u s = next $ do
|
perform k u s = next $ do
|
||||||
|
|
|
@ -280,11 +280,10 @@ syncRemotes' ps available =
|
||||||
fastest = fromMaybe [] . headMaybe . Remote.byCost
|
fastest = fromMaybe [] . headMaybe . Remote.byCost
|
||||||
|
|
||||||
commit :: SyncOptions -> CommandStart
|
commit :: SyncOptions -> CommandStart
|
||||||
commit o = stopUnless shouldcommit $ next $ next $ do
|
commit o = stopUnless shouldcommit $ starting "commit" (ActionItemOther Nothing) $ do
|
||||||
commitmessage <- maybe commitMsg return (messageOption o)
|
commitmessage <- maybe commitMsg return (messageOption o)
|
||||||
showStart' "commit" Nothing
|
|
||||||
Annex.Branch.commit =<< Annex.Branch.commitMessage
|
Annex.Branch.commit =<< Annex.Branch.commitMessage
|
||||||
ifM isDirect
|
next $ ifM isDirect
|
||||||
( do
|
( do
|
||||||
void stageDirect
|
void stageDirect
|
||||||
void preCommitDirect
|
void preCommitDirect
|
||||||
|
@ -321,20 +320,19 @@ commitStaged commitmode commitmessage = do
|
||||||
|
|
||||||
mergeLocal :: [Git.Merge.MergeConfig] -> ResolveMergeOverride -> CurrBranch -> CommandStart
|
mergeLocal :: [Git.Merge.MergeConfig] -> ResolveMergeOverride -> CurrBranch -> CommandStart
|
||||||
mergeLocal mergeconfig resolvemergeoverride currbranch@(Just _, _) =
|
mergeLocal mergeconfig resolvemergeoverride currbranch@(Just _, _) =
|
||||||
go =<< needMerge currbranch
|
needMerge currbranch >>= \case
|
||||||
where
|
Nothing -> stop
|
||||||
go Nothing = stop
|
Just syncbranch ->
|
||||||
go (Just syncbranch) = do
|
starting "merge" (ActionItemOther (Just $ Git.Ref.describe syncbranch)) $
|
||||||
showStart' "merge" (Just $ Git.Ref.describe syncbranch)
|
next $ merge currbranch mergeconfig resolvemergeoverride Git.Branch.ManualCommit syncbranch
|
||||||
next $ next $ merge currbranch mergeconfig resolvemergeoverride Git.Branch.ManualCommit syncbranch
|
|
||||||
mergeLocal _ _ (Nothing, madj) = do
|
mergeLocal _ _ (Nothing, madj) = do
|
||||||
b <- inRepo Git.Branch.currentUnsafe
|
b <- inRepo Git.Branch.currentUnsafe
|
||||||
ifM (isJust <$> needMerge (b, madj))
|
needMerge (b, madj) >>= \case
|
||||||
( do
|
Nothing -> stop
|
||||||
warning $ "There are no commits yet in the currently checked out branch, so cannot merge any remote changes into it."
|
Just syncbranch ->
|
||||||
next $ next $ return False
|
starting "merge" (ActionItemOther (Just $ Git.Ref.describe syncbranch)) $ do
|
||||||
, stop
|
warning $ "There are no commits yet in the currently checked out branch, so cannot merge any remote changes into it."
|
||||||
)
|
next $ return False
|
||||||
|
|
||||||
-- Returns the branch that should be merged, if any.
|
-- Returns the branch that should be merged, if any.
|
||||||
needMerge :: CurrBranch -> Annex (Maybe Git.Branch)
|
needMerge :: CurrBranch -> Annex (Maybe Git.Branch)
|
||||||
|
@ -395,12 +393,13 @@ updateBranch syncbranch updateto g =
|
||||||
] g
|
] g
|
||||||
|
|
||||||
pullRemote :: SyncOptions -> [Git.Merge.MergeConfig] -> Remote -> CurrBranch -> CommandStart
|
pullRemote :: SyncOptions -> [Git.Merge.MergeConfig] -> Remote -> CurrBranch -> CommandStart
|
||||||
pullRemote o mergeconfig remote branch = stopUnless (pure $ pullOption o && wantpull) $ do
|
pullRemote o mergeconfig remote branch = stopUnless (pure $ pullOption o && wantpull) $
|
||||||
showStart' "pull" (Just (Remote.name remote))
|
starting "pull" (ActionItemOther (Just (Remote.name remote))) $ do
|
||||||
next $ do
|
|
||||||
showOutput
|
showOutput
|
||||||
stopUnless fetch $
|
ifM fetch
|
||||||
next $ mergeRemote remote branch mergeconfig (resolveMergeOverride o)
|
( next $ mergeRemote remote branch mergeconfig (resolveMergeOverride o)
|
||||||
|
, next $ return True
|
||||||
|
)
|
||||||
where
|
where
|
||||||
fetch = do
|
fetch = do
|
||||||
repo <- Remote.getRepo remote
|
repo <- Remote.getRepo remote
|
||||||
|
@ -451,9 +450,8 @@ mergeRemote remote currbranch mergeconfig resolvemergeoverride = ifM isBareRepo
|
||||||
|
|
||||||
pushRemote :: SyncOptions -> Remote -> CurrBranch -> CommandStart
|
pushRemote :: SyncOptions -> Remote -> CurrBranch -> CommandStart
|
||||||
pushRemote _o _remote (Nothing, _) = stop
|
pushRemote _o _remote (Nothing, _) = stop
|
||||||
pushRemote o remote (Just branch, _) = stopUnless (pure (pushOption o) <&&> needpush) $ do
|
pushRemote o remote (Just branch, _) = stopUnless (pure (pushOption o) <&&> needpush) $
|
||||||
showStart' "push" (Just (Remote.name remote))
|
starting "push" (ActionItemOther (Just (Remote.name remote))) $ next $ do
|
||||||
next $ next $ do
|
|
||||||
repo <- Remote.getRepo remote
|
repo <- Remote.getRepo remote
|
||||||
showOutput
|
showOutput
|
||||||
ok <- inRepoWithSshOptionsTo repo gc $
|
ok <- inRepoWithSshOptionsTo repo gc $
|
||||||
|
@ -628,10 +626,14 @@ seekSyncContent o rs currbranch = do
|
||||||
|
|
||||||
gokey mvar bloom (k, _) = go (Left bloom) mvar (AssociatedFile Nothing) k
|
gokey mvar bloom (k, _) = go (Left bloom) mvar (AssociatedFile Nothing) k
|
||||||
|
|
||||||
go ebloom mvar af k = commandAction $ do
|
go ebloom mvar af k = do
|
||||||
whenM (syncFile ebloom rs af k) $
|
-- Run syncFile as a command action so file transfers run
|
||||||
void $ liftIO $ tryPutMVar mvar ()
|
-- concurrently.
|
||||||
return Nothing
|
let ai = OnlyActionOn k (ActionItemKey k)
|
||||||
|
commandAction $ startingNoMessage ai $ do
|
||||||
|
whenM (syncFile ebloom rs af k) $
|
||||||
|
void $ liftIO $ tryPutMVar mvar ()
|
||||||
|
next $ return True
|
||||||
|
|
||||||
{- If it's preferred content, and we don't have it, get it from one of the
|
{- If it's preferred content, and we don't have it, get it from one of the
|
||||||
- listed remotes (preferring the cheaper earlier ones).
|
- listed remotes (preferring the cheaper earlier ones).
|
||||||
|
@ -647,7 +649,7 @@ seekSyncContent o rs currbranch = do
|
||||||
- Returns True if any file transfers were made.
|
- Returns True if any file transfers were made.
|
||||||
-}
|
-}
|
||||||
syncFile :: Either (Maybe (Bloom Key)) (Key -> Annex ()) -> [Remote] -> AssociatedFile -> Key -> Annex Bool
|
syncFile :: Either (Maybe (Bloom Key)) (Key -> Annex ()) -> [Remote] -> AssociatedFile -> Key -> Annex Bool
|
||||||
syncFile ebloom rs af k = onlyActionOn' k $ do
|
syncFile ebloom rs af k = do
|
||||||
inhere <- inAnnex k
|
inhere <- inAnnex k
|
||||||
locs <- map Remote.uuid <$> Remote.keyPossibilities k
|
locs <- map Remote.uuid <$> Remote.keyPossibilities k
|
||||||
let (have, lack) = partition (\r -> Remote.uuid r `elem` locs) rs
|
let (have, lack) = partition (\r -> Remote.uuid r `elem` locs) rs
|
||||||
|
@ -689,9 +691,8 @@ syncFile ebloom rs af k = onlyActionOn' k $ do
|
||||||
( return [ get have ]
|
( return [ get have ]
|
||||||
, return []
|
, return []
|
||||||
)
|
)
|
||||||
get have = includeCommandAction $ do
|
get have = includeCommandAction $ starting "get" ai $
|
||||||
showStartKey "get" k ai
|
next $ getKey' k af have
|
||||||
next $ next $ getKey' k af have
|
|
||||||
|
|
||||||
wantput r
|
wantput r
|
||||||
| Remote.readonly r || remoteAnnexReadOnly (Remote.gitconfig r) = return False
|
| Remote.readonly r || remoteAnnexReadOnly (Remote.gitconfig r) = return False
|
||||||
|
@ -764,24 +765,23 @@ seekExportContent o rs (currbranch, _) = or <$> forM rs go
|
||||||
|
|
||||||
cleanupLocal :: CurrBranch -> CommandStart
|
cleanupLocal :: CurrBranch -> CommandStart
|
||||||
cleanupLocal (Nothing, _) = stop
|
cleanupLocal (Nothing, _) = stop
|
||||||
cleanupLocal (Just currb, _) = do
|
cleanupLocal (Just currb, _) =
|
||||||
showStart' "cleanup" (Just "local")
|
starting "cleanup" (ActionItemOther (Just "local")) $
|
||||||
next $ next $ do
|
next $ do
|
||||||
delbranch $ syncBranch currb
|
delbranch $ syncBranch currb
|
||||||
delbranch $ syncBranch $ Git.Ref.base $ Annex.Branch.name
|
delbranch $ syncBranch $ Git.Ref.base $ Annex.Branch.name
|
||||||
mapM_ (\(s,r) -> inRepo $ Git.Ref.delete s r)
|
mapM_ (\(s,r) -> inRepo $ Git.Ref.delete s r)
|
||||||
=<< listTaggedBranches
|
=<< listTaggedBranches
|
||||||
return True
|
return True
|
||||||
where
|
where
|
||||||
delbranch b = whenM (inRepo $ Git.Ref.exists $ Git.Ref.branchRef b) $
|
delbranch b = whenM (inRepo $ Git.Ref.exists $ Git.Ref.branchRef b) $
|
||||||
inRepo $ Git.Branch.delete b
|
inRepo $ Git.Branch.delete b
|
||||||
|
|
||||||
cleanupRemote :: Remote -> CurrBranch -> CommandStart
|
cleanupRemote :: Remote -> CurrBranch -> CommandStart
|
||||||
cleanupRemote _ (Nothing, _) = stop
|
cleanupRemote _ (Nothing, _) = stop
|
||||||
cleanupRemote remote (Just b, _) = do
|
cleanupRemote remote (Just b, _) =
|
||||||
showStart' "cleanup" (Just (Remote.name remote))
|
starting "cleanup" (ActionItemOther (Just (Remote.name remote))) $
|
||||||
next $ next $
|
next $ inRepo $ Git.Command.runBool
|
||||||
inRepo $ Git.Command.runBool
|
|
||||||
[ Param "push"
|
[ Param "push"
|
||||||
, Param "--quiet"
|
, Param "--quiet"
|
||||||
, Param "--delete"
|
, Param "--delete"
|
||||||
|
|
|
@ -66,8 +66,7 @@ seek :: TestRemoteOptions -> CommandSeek
|
||||||
seek = commandAction . start
|
seek = commandAction . start
|
||||||
|
|
||||||
start :: TestRemoteOptions -> CommandStart
|
start :: TestRemoteOptions -> CommandStart
|
||||||
start o = do
|
start o = starting "testremote" (ActionItemOther (Just (testRemote o))) $ do
|
||||||
showStart' "testremote" (Just (testRemote o))
|
|
||||||
fast <- Annex.getState Annex.fast
|
fast <- Annex.getState Annex.fast
|
||||||
r <- either giveup disableExportTree =<< Remote.byName' (testRemote o)
|
r <- either giveup disableExportTree =<< Remote.byName' (testRemote o)
|
||||||
ks <- case testReadonlyFile o of
|
ks <- case testReadonlyFile o of
|
||||||
|
@ -89,7 +88,7 @@ start o = do
|
||||||
exportr <- if Remote.readonly r'
|
exportr <- if Remote.readonly r'
|
||||||
then return Nothing
|
then return Nothing
|
||||||
else exportTreeVariant r'
|
else exportTreeVariant r'
|
||||||
next $ perform rs unavailrs exportr ks
|
perform rs unavailrs exportr ks
|
||||||
where
|
where
|
||||||
basesz = fromInteger $ sizeOption o
|
basesz = fromInteger $ sizeOption o
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,9 @@ seek :: TransferKeyOptions -> CommandSeek
|
||||||
seek o = withKeys (commandAction . start o) (keyOptions o)
|
seek o = withKeys (commandAction . start o) (keyOptions o)
|
||||||
|
|
||||||
start :: TransferKeyOptions -> Key -> CommandStart
|
start :: TransferKeyOptions -> Key -> CommandStart
|
||||||
start o key = case fromToOptions o of
|
start o key = startingCustomOutput key $ case fromToOptions o of
|
||||||
ToRemote dest -> next $ toPerform key (fileOption o) =<< getParsed dest
|
ToRemote dest -> toPerform key (fileOption o) =<< getParsed dest
|
||||||
FromRemote src -> next $ fromPerform key (fileOption o) =<< getParsed src
|
FromRemote src -> fromPerform key (fileOption o) =<< getParsed src
|
||||||
|
|
||||||
toPerform :: Key -> AssociatedFile -> Remote -> CommandPerform
|
toPerform :: Key -> AssociatedFile -> Remote -> CommandPerform
|
||||||
toPerform key file remote = go Upload file $
|
toPerform key file remote = go Upload file $
|
||||||
|
|
|
@ -27,9 +27,8 @@ trustCommand c level = withWords (commandAction . start)
|
||||||
where
|
where
|
||||||
start ws = do
|
start ws = do
|
||||||
let name = unwords ws
|
let name = unwords ws
|
||||||
showStart' c (Just name)
|
|
||||||
u <- Remote.nameToUUID name
|
u <- Remote.nameToUUID name
|
||||||
next $ perform u
|
starting c (ActionItemOther (Just name)) (perform u)
|
||||||
perform uuid = do
|
perform uuid = do
|
||||||
trustSet uuid level
|
trustSet uuid level
|
||||||
when (level == DeadTrusted) $
|
when (level == DeadTrusted) $
|
||||||
|
|
|
@ -66,12 +66,12 @@ wrapUnannex a = ifM (versionSupportsUnlockedPointers <||> isDirect)
|
||||||
)
|
)
|
||||||
|
|
||||||
start :: FilePath -> Key -> CommandStart
|
start :: FilePath -> Key -> CommandStart
|
||||||
start file key = stopUnless (inAnnex key) $ do
|
start file key = stopUnless (inAnnex key) $
|
||||||
showStart "unannex" file
|
starting "unannex" (mkActionItem (key, file)) $
|
||||||
next $ ifM isDirect
|
ifM isDirect
|
||||||
( performDirect file key
|
( performDirect file key
|
||||||
, performIndirect file key
|
, performIndirect file key
|
||||||
)
|
)
|
||||||
|
|
||||||
performIndirect :: FilePath -> Key -> CommandPerform
|
performIndirect :: FilePath -> Key -> CommandPerform
|
||||||
performIndirect file key = do
|
performIndirect file key = do
|
||||||
|
|
|
@ -46,9 +46,8 @@ seek ps = do
|
||||||
withStrings (commandAction . start) ps
|
withStrings (commandAction . start) ps
|
||||||
|
|
||||||
start :: FilePath -> CommandStart
|
start :: FilePath -> CommandStart
|
||||||
start p = do
|
start p = starting "undo" (ActionItemOther (Just p)) $
|
||||||
showStart "undo" p
|
perform p
|
||||||
next $ perform p
|
|
||||||
|
|
||||||
perform :: FilePath -> CommandPerform
|
perform :: FilePath -> CommandPerform
|
||||||
perform p = do
|
perform p = do
|
||||||
|
|
|
@ -23,9 +23,9 @@ seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start (name:g:[]) = do
|
start (name:g:[]) = do
|
||||||
showStart' "ungroup" (Just name)
|
|
||||||
u <- Remote.nameToUUID name
|
u <- Remote.nameToUUID name
|
||||||
next $ perform u (toGroup g)
|
starting "ungroup" (ActionItemOther (Just name)) $
|
||||||
|
perform u (toGroup g)
|
||||||
start _ = giveup "Specify a repository and a group."
|
start _ = giveup "Specify a repository and a group."
|
||||||
|
|
||||||
perform :: UUID -> Group -> CommandPerform
|
perform :: UUID -> Group -> CommandPerform
|
||||||
|
|
|
@ -37,11 +37,10 @@ seek ps = withFilesInGit (commandAction . whenAnnexed start) =<< workTreeItems p
|
||||||
- to a pointer. -}
|
- to a pointer. -}
|
||||||
start :: FilePath -> Key -> CommandStart
|
start :: FilePath -> Key -> CommandStart
|
||||||
start file key = ifM (isJust <$> isAnnexLink file)
|
start file key = ifM (isJust <$> isAnnexLink file)
|
||||||
( do
|
( starting "unlock" (mkActionItem (key, AssociatedFile (Just file))) $
|
||||||
showStart "unlock" file
|
|
||||||
ifM versionSupportsUnlockedPointers
|
ifM versionSupportsUnlockedPointers
|
||||||
( next $ performNew file key
|
( performNew file key
|
||||||
, startOld file key
|
, performOld file key
|
||||||
)
|
)
|
||||||
, stop
|
, stop
|
||||||
)
|
)
|
||||||
|
@ -67,22 +66,22 @@ cleanupNew dest key destmode = do
|
||||||
Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath dest)
|
Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath dest)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
startOld :: FilePath -> Key -> CommandStart
|
performOld :: FilePath -> Key -> CommandPerform
|
||||||
startOld file key =
|
performOld file key =
|
||||||
ifM (inAnnex key)
|
ifM (inAnnex key)
|
||||||
( ifM (isJust <$> catKeyFileHEAD file)
|
( ifM (isJust <$> catKeyFileHEAD file)
|
||||||
( next $ performOld file key
|
( performOld' file key
|
||||||
, do
|
, do
|
||||||
warning "this has not yet been committed to git; cannot unlock it"
|
warning "this has not yet been committed to git; cannot unlock it"
|
||||||
next $ next $ return False
|
next $ return False
|
||||||
)
|
)
|
||||||
, do
|
, do
|
||||||
warning "content not present; cannot unlock"
|
warning "content not present; cannot unlock"
|
||||||
next $ next $ return False
|
next $ return False
|
||||||
)
|
)
|
||||||
|
|
||||||
performOld :: FilePath -> Key -> CommandPerform
|
performOld' :: FilePath -> Key -> CommandPerform
|
||||||
performOld dest key = ifM (checkDiskSpace Nothing key 0 True)
|
performOld' dest key = ifM (checkDiskSpace Nothing key 0 True)
|
||||||
( do
|
( do
|
||||||
src <- calcRepo $ gitAnnexLocation key
|
src <- calcRepo $ gitAnnexLocation key
|
||||||
tmpdest <- fromRepo $ gitAnnexTmpObjectLocation key
|
tmpdest <- fromRepo $ gitAnnexTmpObjectLocation key
|
||||||
|
|
|
@ -70,8 +70,7 @@ start o = do
|
||||||
Just "." -> (".", checkUnused refspec)
|
Just "." -> (".", checkUnused refspec)
|
||||||
Just "here" -> (".", checkUnused refspec)
|
Just "here" -> (".", checkUnused refspec)
|
||||||
Just n -> (n, checkRemoteUnused n refspec)
|
Just n -> (n, checkRemoteUnused n refspec)
|
||||||
showStart' "unused" (Just name)
|
starting "unused" (ActionItemOther (Just name)) perform
|
||||||
next perform
|
|
||||||
|
|
||||||
checkUnused :: RefSpec -> CommandPerform
|
checkUnused :: RefSpec -> CommandPerform
|
||||||
checkUnused refspec = chain 0
|
checkUnused refspec = chain 0
|
||||||
|
@ -335,6 +334,6 @@ startUnused message unused badunused tmpunused maps n = search
|
||||||
search ((m, a):rest) =
|
search ((m, a):rest) =
|
||||||
case M.lookup n m of
|
case M.lookup n m of
|
||||||
Nothing -> search rest
|
Nothing -> search rest
|
||||||
Just key -> do
|
Just key -> starting message
|
||||||
showStart' message (Just $ show n)
|
(ActionItemOther $ Just $ show n)
|
||||||
next $ a key
|
(a key)
|
||||||
|
|
|
@ -22,9 +22,8 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withNothing (commandAction start)
|
seek = withNothing (commandAction start)
|
||||||
|
|
||||||
start :: CommandStart
|
start :: CommandStart
|
||||||
start = do
|
start = starting "upgrade" (ActionItemOther Nothing) $ do
|
||||||
showStart' "upgrade" Nothing
|
|
||||||
whenM (isNothing <$> getVersion) $ do
|
whenM (isNothing <$> getVersion) $ do
|
||||||
initialize Nothing Nothing
|
initialize Nothing Nothing
|
||||||
r <- upgrade False latestVersion
|
r <- upgrade False latestVersion
|
||||||
next $ next $ return r
|
next $ return r
|
||||||
|
|
|
@ -22,16 +22,15 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withWords (commandAction . start)
|
seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start params = do
|
start params = starting "vadd" (ActionItemOther Nothing) $
|
||||||
showStart' "vadd" Nothing
|
|
||||||
withCurrentView $ \view -> do
|
withCurrentView $ \view -> do
|
||||||
let (view', change) = refineView view $
|
let (view', change) = refineView view $
|
||||||
map parseViewParam $ reverse params
|
map parseViewParam $ reverse params
|
||||||
case change of
|
case change of
|
||||||
Unchanged -> do
|
Unchanged -> do
|
||||||
showNote "unchanged"
|
showNote "unchanged"
|
||||||
next $ next $ return True
|
next $ return True
|
||||||
Narrowing -> next $ next $ do
|
Narrowing -> next $ do
|
||||||
if visibleViewSize view' == visibleViewSize view
|
if visibleViewSize view' == visibleViewSize view
|
||||||
then giveup "That would not add an additional level of directory structure to the view. To filter the view, use vfilter instead of vadd."
|
then giveup "That would not add an additional level of directory structure to the view. To filter the view, use vfilter instead of vadd."
|
||||||
else checkoutViewBranch view' narrowView
|
else checkoutViewBranch view' narrowView
|
||||||
|
|
|
@ -26,14 +26,13 @@ start ::CommandStart
|
||||||
start = go =<< currentView
|
start = go =<< currentView
|
||||||
where
|
where
|
||||||
go Nothing = giveup "Not in a view."
|
go Nothing = giveup "Not in a view."
|
||||||
go (Just v) = do
|
go (Just v) = starting "vcycle" (ActionItemOther Nothing) $ do
|
||||||
showStart' "vcycle" Nothing
|
|
||||||
let v' = v { viewComponents = vcycle [] (viewComponents v) }
|
let v' = v { viewComponents = vcycle [] (viewComponents v) }
|
||||||
if v == v'
|
if v == v'
|
||||||
then do
|
then do
|
||||||
showNote "unchanged"
|
showNote "unchanged"
|
||||||
next $ next $ return True
|
next $ return True
|
||||||
else next $ next $ checkoutViewBranch v' narrowView
|
else next $ checkoutViewBranch v' narrowView
|
||||||
|
|
||||||
vcycle rest (c:cs)
|
vcycle rest (c:cs)
|
||||||
| viewVisible c = rest ++ cs ++ [c]
|
| viewVisible c = rest ++ cs ++ [c]
|
||||||
|
|
|
@ -20,11 +20,10 @@ seek :: CmdParams -> CommandSeek
|
||||||
seek = withWords (commandAction . start)
|
seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start params = do
|
start params = starting "vfilter" (ActionItemOther Nothing) $
|
||||||
showStart' "vfilter" Nothing
|
|
||||||
withCurrentView $ \view -> do
|
withCurrentView $ \view -> do
|
||||||
let view' = filterView view $
|
let view' = filterView view $
|
||||||
map parseViewParam $ reverse params
|
map parseViewParam $ reverse params
|
||||||
next $ next $ if visibleViewSize view' > visibleViewSize view
|
next $ if visibleViewSize view' > visibleViewSize view
|
||||||
then giveup "That would add an additional level of directory structure to the view, rather than filtering it. If you want to do that, use vadd instead of vfilter."
|
then giveup "That would add an additional level of directory structure to the view, rather than filtering it. If you want to do that, use vadd instead of vfilter."
|
||||||
else checkoutViewBranch view' narrowView
|
else checkoutViewBranch view' narrowView
|
||||||
|
|
|
@ -27,17 +27,16 @@ start :: [String] -> CommandStart
|
||||||
start ps = go =<< currentView
|
start ps = go =<< currentView
|
||||||
where
|
where
|
||||||
go Nothing = giveup "Not in a view."
|
go Nothing = giveup "Not in a view."
|
||||||
go (Just v) = do
|
go (Just v) = starting "vpop" (ActionItemOther (Just $ show num)) $ do
|
||||||
showStart' "vpop" (Just $ show num)
|
|
||||||
removeView v
|
removeView v
|
||||||
(oldvs, vs) <- splitAt (num - 1) . filter (sameparentbranch v)
|
(oldvs, vs) <- splitAt (num - 1) . filter (sameparentbranch v)
|
||||||
<$> recentViews
|
<$> recentViews
|
||||||
mapM_ removeView oldvs
|
mapM_ removeView oldvs
|
||||||
case vs of
|
case vs of
|
||||||
(oldv:_) -> next $ next $ do
|
(oldv:_) -> next $ do
|
||||||
showOutput
|
showOutput
|
||||||
checkoutViewBranch oldv (return . branchView)
|
checkoutViewBranch oldv (return . branchView)
|
||||||
_ -> next $ next $ do
|
_ -> next $ do
|
||||||
showOutput
|
showOutput
|
||||||
inRepo $ Git.Command.runBool
|
inRepo $ Git.Command.runBool
|
||||||
[ Param "checkout"
|
[ Param "checkout"
|
||||||
|
|
|
@ -29,16 +29,15 @@ seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start :: [String] -> CommandStart
|
start :: [String] -> CommandStart
|
||||||
start [] = giveup "Specify metadata to include in view"
|
start [] = giveup "Specify metadata to include in view"
|
||||||
start ps = do
|
start ps = ifM safeToEnterView
|
||||||
showStart' "view" Nothing
|
( do
|
||||||
ifM safeToEnterView
|
view <- mkView ps
|
||||||
( do
|
go view =<< currentView
|
||||||
view <- mkView ps
|
, giveup "Not safe to enter view."
|
||||||
go view =<< currentView
|
)
|
||||||
, giveup "Not safe to enter view."
|
|
||||||
)
|
|
||||||
where
|
where
|
||||||
go view Nothing = next $ perform view
|
go view Nothing = starting "view" (ActionItemOther Nothing) $
|
||||||
|
perform view
|
||||||
go view (Just v)
|
go view (Just v)
|
||||||
| v == view = stop
|
| v == view = stop
|
||||||
| otherwise = giveup "Already in a view. Use the vfilter and vadd commands to further refine this view."
|
| otherwise = giveup "Already in a view. Use the vfilter and vadd commands to further refine this view."
|
||||||
|
|
|
@ -32,16 +32,15 @@ cmd' name desc getter setter = noMessages $
|
||||||
|
|
||||||
seek = withWords (commandAction . start)
|
seek = withWords (commandAction . start)
|
||||||
|
|
||||||
start (rname:[]) = go rname (performGet getter)
|
start (rname:[]) = do
|
||||||
start (rname:expr:[]) = go rname $ \uuid -> do
|
|
||||||
allowMessages
|
|
||||||
showStart' name (Just rname)
|
|
||||||
performSet setter expr uuid
|
|
||||||
start _ = giveup "Specify a repository."
|
|
||||||
|
|
||||||
go rname a = do
|
|
||||||
u <- Remote.nameToUUID rname
|
u <- Remote.nameToUUID rname
|
||||||
next $ a u
|
startingCustomOutput (ActionItemOther Nothing) $
|
||||||
|
performGet getter u
|
||||||
|
start (rname:expr:[]) = do
|
||||||
|
u <- Remote.nameToUUID rname
|
||||||
|
startingUsualMessages name (ActionItemOther (Just rname)) $
|
||||||
|
performSet setter expr u
|
||||||
|
start _ = giveup "Specify a repository."
|
||||||
|
|
||||||
performGet :: Ord a => Annex (M.Map a PreferredContentExpression) -> a -> CommandPerform
|
performGet :: Ord a => Annex (M.Map a PreferredContentExpression) -> a -> CommandPerform
|
||||||
performGet getter a = do
|
performGet getter a = do
|
||||||
|
|
|
@ -53,9 +53,7 @@ start remotemap file key = startKeys remotemap (key, mkActionItem (key, afile))
|
||||||
afile = AssociatedFile (Just file)
|
afile = AssociatedFile (Just file)
|
||||||
|
|
||||||
startKeys :: M.Map UUID Remote -> (Key, ActionItem) -> CommandStart
|
startKeys :: M.Map UUID Remote -> (Key, ActionItem) -> CommandStart
|
||||||
startKeys remotemap (key, ai) = do
|
startKeys remotemap (key, ai) = starting "whereis" ai $ perform remotemap key
|
||||||
showStartKey "whereis" key ai
|
|
||||||
next $ perform remotemap key
|
|
||||||
|
|
||||||
perform :: M.Map UUID Remote -> Key -> CommandPerform
|
perform :: M.Map UUID Remote -> Key -> CommandPerform
|
||||||
perform remotemap key = do
|
perform remotemap key = do
|
||||||
|
|
|
@ -37,6 +37,7 @@ newtype TopFilePath = TopFilePath { getTopFilePath :: FilePath }
|
||||||
|
|
||||||
{- A file in a branch or other treeish. -}
|
{- A file in a branch or other treeish. -}
|
||||||
data BranchFilePath = BranchFilePath Ref TopFilePath
|
data BranchFilePath = BranchFilePath Ref TopFilePath
|
||||||
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
{- Git uses the branch:file form to refer to a BranchFilePath -}
|
{- Git uses the branch:file form to refer to a BranchFilePath -}
|
||||||
descBranchFilePath :: BranchFilePath -> String
|
descBranchFilePath :: BranchFilePath -> String
|
||||||
|
|
41
Messages.hs
41
Messages.hs
|
@ -1,6 +1,6 @@
|
||||||
{- git-annex output messages
|
{- git-annex output messages
|
||||||
-
|
-
|
||||||
- Copyright 2010-2017 Joey Hess <id@joeyh.name>
|
- Copyright 2010-2019 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU AGPL version 3 or higher.
|
- Licensed under the GNU AGPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
@ -8,8 +8,10 @@
|
||||||
module Messages (
|
module Messages (
|
||||||
showStart,
|
showStart,
|
||||||
showStart',
|
showStart',
|
||||||
showStartKey,
|
showStartMessage,
|
||||||
ActionItem,
|
showEndMessage,
|
||||||
|
StartMessage(..),
|
||||||
|
ActionItem(..),
|
||||||
mkActionItem,
|
mkActionItem,
|
||||||
showNote,
|
showNote,
|
||||||
showAction,
|
showAction,
|
||||||
|
@ -42,7 +44,6 @@ module Messages (
|
||||||
debugEnabled,
|
debugEnabled,
|
||||||
commandProgressDisabled,
|
commandProgressDisabled,
|
||||||
outputMessage,
|
outputMessage,
|
||||||
implicitMessage,
|
|
||||||
withMessageState,
|
withMessageState,
|
||||||
prompt,
|
prompt,
|
||||||
) where
|
) where
|
||||||
|
@ -58,6 +59,8 @@ import Types
|
||||||
import Types.Messages
|
import Types.Messages
|
||||||
import Types.ActionItem
|
import Types.ActionItem
|
||||||
import Types.Concurrency
|
import Types.Concurrency
|
||||||
|
import Types.Command (StartMessage(..))
|
||||||
|
import Types.Transfer (transferKey)
|
||||||
import Messages.Internal
|
import Messages.Internal
|
||||||
import Messages.Concurrent
|
import Messages.Concurrent
|
||||||
import qualified Messages.JSON as JSON
|
import qualified Messages.JSON as JSON
|
||||||
|
@ -81,6 +84,30 @@ showStartKey command key i = outputMessage json $
|
||||||
where
|
where
|
||||||
json = JSON.start command (actionItemWorkTreeFile i) (Just key)
|
json = JSON.start command (actionItemWorkTreeFile i) (Just key)
|
||||||
|
|
||||||
|
showStartMessage :: StartMessage -> Annex ()
|
||||||
|
showStartMessage (StartMessage command ai) = case ai of
|
||||||
|
ActionItemAssociatedFile _ k -> showStartKey command k ai
|
||||||
|
ActionItemKey k -> showStartKey command k ai
|
||||||
|
ActionItemBranchFilePath _ k -> showStartKey command k ai
|
||||||
|
ActionItemFailedTransfer t _ -> showStartKey command (transferKey t) ai
|
||||||
|
ActionItemWorkTreeFile file -> showStart command file
|
||||||
|
ActionItemOther msg -> showStart' command msg
|
||||||
|
OnlyActionOn _ ai' -> showStartMessage (StartMessage command ai')
|
||||||
|
showStartMessage (StartUsualMessages command ai) = do
|
||||||
|
outputType <$> Annex.getState Annex.output >>= \case
|
||||||
|
QuietOutput -> Annex.setOutput NormalOutput
|
||||||
|
_ -> noop
|
||||||
|
showStartMessage (StartMessage command ai)
|
||||||
|
showStartMessage (StartNoMessage _) = noop
|
||||||
|
showStartMessage (CustomOutput _) = Annex.setOutput QuietOutput
|
||||||
|
|
||||||
|
-- Only show end result if the StartMessage is one that gets displayed.
|
||||||
|
showEndMessage :: StartMessage -> Bool -> Annex ()
|
||||||
|
showEndMessage (StartMessage _ _) = showEndResult
|
||||||
|
showEndMessage (StartUsualMessages _ _) = showEndResult
|
||||||
|
showEndMessage (StartNoMessage _) = const noop
|
||||||
|
showEndMessage (CustomOutput _) = const noop
|
||||||
|
|
||||||
showNote :: String -> Annex ()
|
showNote :: String -> Annex ()
|
||||||
showNote s = outputMessage (JSON.note s) $ "(" ++ s ++ ") "
|
showNote s = outputMessage (JSON.note s) $ "(" ++ s ++ ") "
|
||||||
|
|
||||||
|
@ -251,12 +278,6 @@ commandProgressDisabled = withMessageState $ \s -> return $
|
||||||
JSONOutput _ -> True
|
JSONOutput _ -> True
|
||||||
NormalOutput -> concurrentOutputEnabled s
|
NormalOutput -> concurrentOutputEnabled s
|
||||||
|
|
||||||
{- Use to show a message that is displayed implicitly, and so might be
|
|
||||||
- disabled when running a certian command that needs more control over its
|
|
||||||
- output. -}
|
|
||||||
implicitMessage :: Annex () -> Annex ()
|
|
||||||
implicitMessage = whenM (implicitMessages <$> Annex.getState Annex.output)
|
|
||||||
|
|
||||||
{- Prevents any concurrent console access while running an action, so
|
{- Prevents any concurrent console access while running an action, so
|
||||||
- that the action is the only thing using the console, and can eg prompt
|
- that the action is the only thing using the console, and can eg prompt
|
||||||
- the user.
|
- the user.
|
||||||
|
|
|
@ -13,21 +13,38 @@ import Key
|
||||||
import Types.Transfer
|
import Types.Transfer
|
||||||
import Git.FilePath
|
import Git.FilePath
|
||||||
|
|
||||||
|
import Data.Maybe
|
||||||
|
|
||||||
data ActionItem
|
data ActionItem
|
||||||
= ActionItemAssociatedFile AssociatedFile Key
|
= ActionItemAssociatedFile AssociatedFile Key
|
||||||
| ActionItemKey Key
|
| ActionItemKey Key
|
||||||
| ActionItemBranchFilePath BranchFilePath Key
|
| ActionItemBranchFilePath BranchFilePath Key
|
||||||
| ActionItemFailedTransfer Transfer TransferInfo
|
| ActionItemFailedTransfer Transfer TransferInfo
|
||||||
|
| ActionItemWorkTreeFile FilePath
|
||||||
|
| ActionItemOther (Maybe String)
|
||||||
|
-- Use to avoid more than one thread concurrently processing the
|
||||||
|
-- same Key.
|
||||||
|
| OnlyActionOn Key ActionItem
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
class MkActionItem t where
|
class MkActionItem t where
|
||||||
mkActionItem :: t -> ActionItem
|
mkActionItem :: t -> ActionItem
|
||||||
|
|
||||||
|
instance MkActionItem ActionItem where
|
||||||
|
mkActionItem = id
|
||||||
|
|
||||||
instance MkActionItem (AssociatedFile, Key) where
|
instance MkActionItem (AssociatedFile, Key) where
|
||||||
mkActionItem = uncurry ActionItemAssociatedFile
|
mkActionItem = uncurry ActionItemAssociatedFile
|
||||||
|
|
||||||
instance MkActionItem (Key, AssociatedFile) where
|
instance MkActionItem (Key, AssociatedFile) where
|
||||||
mkActionItem = uncurry $ flip ActionItemAssociatedFile
|
mkActionItem = uncurry $ flip ActionItemAssociatedFile
|
||||||
|
|
||||||
|
instance MkActionItem (Key, FilePath) where
|
||||||
|
mkActionItem (key, file) = ActionItemAssociatedFile (AssociatedFile (Just file)) key
|
||||||
|
|
||||||
|
instance MkActionItem (FilePath, Key) where
|
||||||
|
mkActionItem (file, key) = mkActionItem (key, file)
|
||||||
|
|
||||||
instance MkActionItem Key where
|
instance MkActionItem Key where
|
||||||
mkActionItem = ActionItemKey
|
mkActionItem = ActionItemKey
|
||||||
|
|
||||||
|
@ -39,23 +56,33 @@ instance MkActionItem (Transfer, TransferInfo) where
|
||||||
|
|
||||||
actionItemDesc :: ActionItem -> String
|
actionItemDesc :: ActionItem -> String
|
||||||
actionItemDesc (ActionItemAssociatedFile (AssociatedFile (Just f)) _) = f
|
actionItemDesc (ActionItemAssociatedFile (AssociatedFile (Just f)) _) = f
|
||||||
actionItemDesc (ActionItemAssociatedFile (AssociatedFile Nothing) k) = serializeKey k
|
actionItemDesc (ActionItemAssociatedFile (AssociatedFile Nothing) k) =
|
||||||
|
serializeKey k
|
||||||
actionItemDesc (ActionItemKey k) = serializeKey k
|
actionItemDesc (ActionItemKey k) = serializeKey k
|
||||||
actionItemDesc (ActionItemBranchFilePath bfp _) = descBranchFilePath bfp
|
actionItemDesc (ActionItemBranchFilePath bfp _) = descBranchFilePath bfp
|
||||||
actionItemDesc (ActionItemFailedTransfer t i) = actionItemDesc $
|
actionItemDesc (ActionItemFailedTransfer t i) = actionItemDesc $
|
||||||
ActionItemAssociatedFile (associatedFile i) (transferKey t)
|
ActionItemAssociatedFile (associatedFile i) (transferKey t)
|
||||||
|
actionItemDesc (ActionItemWorkTreeFile f) = f
|
||||||
|
actionItemDesc (ActionItemOther s) = fromMaybe "" s
|
||||||
|
actionItemDesc (OnlyActionOn _ ai) = actionItemDesc ai
|
||||||
|
|
||||||
actionItemKey :: ActionItem -> Key
|
actionItemKey :: ActionItem -> Maybe Key
|
||||||
actionItemKey (ActionItemAssociatedFile _ k) = k
|
actionItemKey (ActionItemAssociatedFile _ k) = Just k
|
||||||
actionItemKey (ActionItemKey k) = k
|
actionItemKey (ActionItemKey k) = Just k
|
||||||
actionItemKey (ActionItemBranchFilePath _ k) = k
|
actionItemKey (ActionItemBranchFilePath _ k) = Just k
|
||||||
actionItemKey (ActionItemFailedTransfer t _) = transferKey t
|
actionItemKey (ActionItemFailedTransfer t _) = Just (transferKey t)
|
||||||
|
actionItemKey (ActionItemWorkTreeFile _) = Nothing
|
||||||
|
actionItemKey (ActionItemOther _) = Nothing
|
||||||
|
actionItemKey (OnlyActionOn _ ai) = actionItemKey ai
|
||||||
|
|
||||||
actionItemWorkTreeFile :: ActionItem -> Maybe FilePath
|
actionItemWorkTreeFile :: ActionItem -> Maybe FilePath
|
||||||
actionItemWorkTreeFile (ActionItemAssociatedFile (AssociatedFile af) _) = af
|
actionItemWorkTreeFile (ActionItemAssociatedFile (AssociatedFile af) _) = af
|
||||||
|
actionItemWorkTreeFile (ActionItemWorkTreeFile f) = Just f
|
||||||
|
actionItemWorkTreeFile (OnlyActionOn _ ai) = actionItemWorkTreeFile ai
|
||||||
actionItemWorkTreeFile _ = Nothing
|
actionItemWorkTreeFile _ = Nothing
|
||||||
|
|
||||||
actionItemTransferDirection :: ActionItem -> Maybe Direction
|
actionItemTransferDirection :: ActionItem -> Maybe Direction
|
||||||
actionItemTransferDirection (ActionItemFailedTransfer t _) = Just $
|
actionItemTransferDirection (ActionItemFailedTransfer t _) = Just $
|
||||||
transferDirection t
|
transferDirection t
|
||||||
|
actionItemTransferDirection (OnlyActionOn _ ai) = actionItemTransferDirection ai
|
||||||
actionItemTransferDirection _ = Nothing
|
actionItemTransferDirection _ = Nothing
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{- git-annex command data types
|
{- git-annex command data types
|
||||||
-
|
-
|
||||||
- Copyright 2010-2016 Joey Hess <id@joeyh.name>
|
- Copyright 2010-2019 Joey Hess <id@joeyh.name>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU AGPL version 3 or higher.
|
- Licensed under the GNU AGPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
@ -12,6 +12,7 @@ import Options.Applicative.Types (Parser)
|
||||||
|
|
||||||
import Types
|
import Types
|
||||||
import Types.DeferredParse
|
import Types.DeferredParse
|
||||||
|
import Types.ActionItem
|
||||||
|
|
||||||
{- A command runs in these stages.
|
{- A command runs in these stages.
|
||||||
-
|
-
|
||||||
|
@ -25,11 +26,11 @@ data CommandCheck = CommandCheck { idCheck :: Int, runCheck :: Annex () }
|
||||||
- the repo to find things to act on (ie, new files to add), and
|
- the repo to find things to act on (ie, new files to add), and
|
||||||
- runs commandAction to handle all necessary actions. -}
|
- runs commandAction to handle all necessary actions. -}
|
||||||
type CommandSeek = Annex ()
|
type CommandSeek = Annex ()
|
||||||
{- d. The start stage is run before anything is printed about the
|
{- d. The start stage is run before anything is output, is passed some
|
||||||
- command, is passed some input, and can early abort it
|
- value from the seek stage, and can check if anything needs to be
|
||||||
- if nothing needs to be done. It should run quickly and
|
- done, and early abort if not. It should run quickly and should
|
||||||
- should not modify Annex state. -}
|
- not modify Annex state or output anything. -}
|
||||||
type CommandStart = Annex (Maybe CommandPerform)
|
type CommandStart = Annex (Maybe (StartMessage, CommandPerform))
|
||||||
{- e. The perform stage is run after a message is printed about the command
|
{- e. The perform stage is run after a message is printed about the command
|
||||||
- being run, and it should be where the bulk of the work happens. -}
|
- being run, and it should be where the bulk of the work happens. -}
|
||||||
type CommandPerform = Annex (Maybe CommandCleanup)
|
type CommandPerform = Annex (Maybe CommandCleanup)
|
||||||
|
@ -37,6 +38,29 @@ type CommandPerform = Annex (Maybe CommandCleanup)
|
||||||
- returns the overall success/fail of the command. -}
|
- returns the overall success/fail of the command. -}
|
||||||
type CommandCleanup = Annex Bool
|
type CommandCleanup = Annex Bool
|
||||||
|
|
||||||
|
{- Message that is displayed when starting to perform an action on
|
||||||
|
- something. The String is typically the name of the command or action
|
||||||
|
- being performed.
|
||||||
|
-}
|
||||||
|
data StartMessage
|
||||||
|
= StartMessage String ActionItem
|
||||||
|
| StartUsualMessages String ActionItem
|
||||||
|
-- ^ Like StartMessage, but makes sure to enable usual message
|
||||||
|
-- display in case it was disabled by cmdnomessages.
|
||||||
|
| StartNoMessage ActionItem
|
||||||
|
-- ^ Starts, without displaying any message but also without
|
||||||
|
-- disabling display of any of the usual messages.
|
||||||
|
| CustomOutput ActionItem
|
||||||
|
-- ^ Prevents any start, end, or other usual messages from
|
||||||
|
-- being displayed, letting a command output its own custom format.
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
|
instance MkActionItem StartMessage where
|
||||||
|
mkActionItem (StartMessage _ ai) = ai
|
||||||
|
mkActionItem (StartUsualMessages _ ai) = ai
|
||||||
|
mkActionItem (StartNoMessage ai) = ai
|
||||||
|
mkActionItem (CustomOutput ai) = ai
|
||||||
|
|
||||||
{- A command is defined by specifying these things. -}
|
{- A command is defined by specifying these things. -}
|
||||||
data Command = Command
|
data Command = Command
|
||||||
{ cmdcheck :: [CommandCheck] -- check stage
|
{ cmdcheck :: [CommandCheck] -- check stage
|
||||||
|
|
|
@ -35,7 +35,6 @@ data MessageState = MessageState
|
||||||
{ outputType :: OutputType
|
{ outputType :: OutputType
|
||||||
, concurrentOutputEnabled :: Bool
|
, concurrentOutputEnabled :: Bool
|
||||||
, sideActionBlock :: SideActionBlock
|
, sideActionBlock :: SideActionBlock
|
||||||
, implicitMessages :: Bool
|
|
||||||
, consoleRegion :: Maybe ConsoleRegion
|
, consoleRegion :: Maybe ConsoleRegion
|
||||||
, consoleRegionErrFlag :: Bool
|
, consoleRegionErrFlag :: Bool
|
||||||
, jsonBuffer :: Maybe Aeson.Object
|
, jsonBuffer :: Maybe Aeson.Object
|
||||||
|
@ -49,7 +48,6 @@ newMessageState = do
|
||||||
{ outputType = NormalOutput
|
{ outputType = NormalOutput
|
||||||
, concurrentOutputEnabled = False
|
, concurrentOutputEnabled = False
|
||||||
, sideActionBlock = NoBlock
|
, sideActionBlock = NoBlock
|
||||||
, implicitMessages = True
|
|
||||||
, consoleRegion = Nothing
|
, consoleRegion = Nothing
|
||||||
, consoleRegionErrFlag = False
|
, consoleRegionErrFlag = False
|
||||||
, jsonBuffer = Nothing
|
, jsonBuffer = Nothing
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
module Types.WorkerPool where
|
module Types.WorkerPool where
|
||||||
|
|
||||||
|
import Control.Concurrent
|
||||||
import Control.Concurrent.Async
|
import Control.Concurrent.Async
|
||||||
import Data.Either
|
|
||||||
|
|
||||||
-- | Pool of worker threads.
|
-- | Pool of worker threads.
|
||||||
data WorkerPool t
|
data WorkerPool t
|
||||||
|
@ -16,15 +16,65 @@ data WorkerPool t
|
||||||
| WorkerPool [Worker t]
|
| WorkerPool [Worker t]
|
||||||
|
|
||||||
-- | A worker can either be idle or running an Async action.
|
-- | A worker can either be idle or running an Async action.
|
||||||
type Worker t = Either t (Async t)
|
-- And it is used for some stage.
|
||||||
|
data Worker t
|
||||||
|
= IdleWorker t WorkerStage
|
||||||
|
| ActiveWorker (Async t) WorkerStage
|
||||||
|
|
||||||
|
-- | These correspond to CommandPerform and CommandCleanup.
|
||||||
|
data WorkerStage = PerformStage | CleanupStage
|
||||||
|
deriving (Eq)
|
||||||
|
|
||||||
|
workerStage :: Worker t -> WorkerStage
|
||||||
|
workerStage (IdleWorker _ s) = s
|
||||||
|
workerStage (ActiveWorker _ s) = s
|
||||||
|
|
||||||
|
workerAsync :: Worker t -> Maybe (Async t)
|
||||||
|
workerAsync (IdleWorker _ _) = Nothing
|
||||||
|
workerAsync (ActiveWorker aid _) = Just aid
|
||||||
|
|
||||||
|
-- | Allocates a WorkerPool that has the specified number of workers
|
||||||
|
-- in it, of each stage.
|
||||||
|
--
|
||||||
|
-- The stages are distributed evenly throughout.
|
||||||
allocateWorkerPool :: t -> Int -> WorkerPool t
|
allocateWorkerPool :: t -> Int -> WorkerPool t
|
||||||
allocateWorkerPool t n = WorkerPool $ replicate n (Left t)
|
allocateWorkerPool t n = WorkerPool $ take (n+n) $
|
||||||
|
map (uncurry IdleWorker) $ zip (repeat t) stages
|
||||||
|
where
|
||||||
|
stages = concat $ repeat [PerformStage, CleanupStage]
|
||||||
|
|
||||||
addWorkerPool :: WorkerPool t -> Worker t -> WorkerPool t
|
addWorkerPool :: Worker t -> WorkerPool t -> WorkerPool t
|
||||||
addWorkerPool (WorkerPool l) w = WorkerPool (w:l)
|
addWorkerPool w (WorkerPool l) = WorkerPool (w:l)
|
||||||
addWorkerPool UnallocatedWorkerPool w = WorkerPool [w]
|
addWorkerPool w UnallocatedWorkerPool = WorkerPool [w]
|
||||||
|
|
||||||
idleWorkers :: WorkerPool t -> [t]
|
idleWorkers :: WorkerPool t -> [t]
|
||||||
idleWorkers UnallocatedWorkerPool = []
|
idleWorkers UnallocatedWorkerPool = []
|
||||||
idleWorkers (WorkerPool l) = lefts l
|
idleWorkers (WorkerPool l) = go l
|
||||||
|
where
|
||||||
|
go [] = []
|
||||||
|
go (IdleWorker t _ : rest) = t : go rest
|
||||||
|
go (ActiveWorker _ _ : rest) = go rest
|
||||||
|
|
||||||
|
-- | Removes a worker from the pool whose Async uses the ThreadId.
|
||||||
|
--
|
||||||
|
-- Each Async has its own ThreadId, so this stops once it finds
|
||||||
|
-- a match.
|
||||||
|
removeThreadIdWorkerPool :: ThreadId -> WorkerPool t -> Maybe ((Async t, WorkerStage), WorkerPool t)
|
||||||
|
removeThreadIdWorkerPool _ UnallocatedWorkerPool = Nothing
|
||||||
|
removeThreadIdWorkerPool tid (WorkerPool l) = go [] l
|
||||||
|
where
|
||||||
|
go _ [] = Nothing
|
||||||
|
go c (ActiveWorker a stage : rest)
|
||||||
|
| asyncThreadId a == tid = Just ((a, stage), WorkerPool (c++rest))
|
||||||
|
go c (v : rest) = go (v:c) rest
|
||||||
|
|
||||||
|
deactivateWorker :: WorkerPool t -> Async t -> t -> WorkerPool t
|
||||||
|
deactivateWorker UnallocatedWorkerPool _ _ = UnallocatedWorkerPool
|
||||||
|
deactivateWorker (WorkerPool l) aid t = WorkerPool $ go l
|
||||||
|
where
|
||||||
|
go [] = []
|
||||||
|
go (w@(IdleWorker _ _) : rest) = w : go rest
|
||||||
|
go (w@(ActiveWorker a st) : rest)
|
||||||
|
| a == aid = IdleWorker t st : rest
|
||||||
|
| otherwise = w : go rest
|
||||||
|
|
||||||
|
|
|
@ -21,19 +21,3 @@ are still some things that could be improved, tracked here:
|
||||||
all that needs to be done is make checksum verification be done as the
|
all that needs to be done is make checksum verification be done as the
|
||||||
cleanup action. Currently, it's bundled into the same action that
|
cleanup action. Currently, it's bundled into the same action that
|
||||||
transfers content.
|
transfers content.
|
||||||
|
|
||||||
* onlyActionOn collapses the cleanup action into the start action,
|
|
||||||
and so prevents use of the separate cleanup queue.
|
|
||||||
|
|
||||||
* Don't parallelize start stage actions. They are supposed to run fast,
|
|
||||||
and often a huge number of them don't print out anything. The overhead of
|
|
||||||
bookkeeping for parallizing those swamps the benefit of parallelizing by
|
|
||||||
what seems to be a large degree. Compare `git annex get` in a directory
|
|
||||||
where the first several thousand files are already present with and
|
|
||||||
without -J.
|
|
||||||
|
|
||||||
Only once the start stage has decided
|
|
||||||
something needs to be done should a job be started up.
|
|
||||||
|
|
||||||
This probably needs display of any output to be moved out of the start
|
|
||||||
stage, because no console region will be allocated for it.
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue