Merge branch 'starting'

This commit is contained in:
Joey Hess 2019-06-15 12:42:10 -04:00
commit 502ce3f243
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
85 changed files with 810 additions and 708 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 $

View file

@ -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

View file

@ -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

View file

@ -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'
concurrentjob workerst = start >>= \case
Nothing -> noop
Just (startmsg, perform) ->
concurrentjob' workerst startmsg perform
concurrentjob' workerst startmsg perform = case mkActionItem startmsg of
OnlyActionOn k _ -> ensureOnlyActionOn k $
-- If another job performed the same action while we
-- waited, there may be nothing left to do, so re-run
-- the start stage to see if it still wants to do
-- 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
commandActions :: [CommandStart] -> Annex () -- Like performCommandAction' but the worker thread's stage
commandActions = mapM_ commandAction -- 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
{- Waits for any forked off command actions to finish. -- | Wait until there's an idle worker in the pool, remove it from the
- -- pool, and return its state.
- Merge together the cleanup actions of all the AnnexStates used by --
- threads, into the current Annex's state, so they'll run at shutdown. -- If the pool is unallocated, it will be allocated to the specified size.
- waitWorkerSlot :: Int -> (WorkerStage -> Bool) -> TMVar (WorkerPool Annex.AnnexState) -> Annex (Annex.AnnexState)
- Also merge together the errcounters of the AnnexStates. 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 $

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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
) )

View file

@ -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))

View file

@ -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

View file

@ -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) _) =

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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"

View file

@ -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) $

View file

@ -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."

View file

@ -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."

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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) $
showStart' "generating file list" Nothing withTmpFile "send" $ \t h -> do
fs' <- seekHelper LsFiles.inRepo =<< workTreeItems fs fs' <- seekHelper LsFiles.inRepo =<< workTreeItems fs
matcher <- Limit.getMatcher matcher <- Limit.getMatcher
let addlist f o = whenM (matcher $ MatchingFile $ FileInfo f f) $ let addlist f o = whenM (matcher $ MatchingFile $ FileInfo f f) $
liftIO $ hPutStrLn h o liftIO $ hPutStrLn h o
forM_ fs' $ \f -> do forM_ fs' $ \f -> do
mk <- lookupFile f mk <- lookupFile f
case mk of case mk of
Nothing -> noop Nothing -> noop
Just k -> withObjectLoc k (addlist f) (const noop) Just k -> withObjectLoc k (addlist f) (const noop)
liftIO $ hClose h liftIO $ hClose h
showEndOk
serverkey <- uftpKey
showStart' "sending files" Nothing u <- getUUID
showOutput withAuthList $ \authlist -> do
serverkey <- uftpKey let ps =
u <- getUUID -- Force client authentication.
withAuthList $ \authlist -> do [ Param "-c"
let ps = , Param "-Y", Param "aes256-cbc"
-- Force client authentication. , Param "-h", Param "sha512"
[ Param "-c" -- Picked ecdh_ecdsa for perfect forward secrecy,
, Param "-Y", Param "aes256-cbc" -- and because a EC key exchange algorithm is
, Param "-h", Param "sha512" -- needed since all keys are EC.
-- Picked ecdh_ecdsa for perfect forward secrecy, , Param "-e", Param "ecdh_ecdsa"
-- and because a EC key exchange algorithm is , Param "-k", uftpKeyParam serverkey
-- needed since all keys are EC. , Param "-U", Param (uftpUID u)
, Param "-e", Param "ecdh_ecdsa" -- only allow clients on the authlist
, Param "-k", uftpKeyParam serverkey , Param "-H", Param ("@"++authlist)
, Param "-U", Param (uftpUID u) -- pass in list of files to send
-- only allow clients on the authlist , Param "-i", File t
, Param "-H", Param ("@"++authlist) ] ++ ups
-- pass in list of files to send liftIO (boolSystem "uftp" ps) >>= showEndResult
, Param "-i", File t next $ return True
] ++ 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 $

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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 $

View 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) $

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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"

View file

@ -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."

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.