Skip to content
Snippets Groups Projects
CmdLine.hs 3.16 KiB
Newer Older
Joey Hess's avatar
Joey Hess committed
{- git-annex command line parsing and dispatch
 -
 - Copyright 2010 Joey Hess <joey@kitenet.net>
 -
 - Licensed under the GNU GPL version 3 or higher.
 -}

Joey Hess's avatar
Joey Hess committed
	dispatch,
Joey Hess's avatar
Joey Hess committed
	shutdown
import qualified Control.Exception as E
import qualified Data.Map as M
import System.Console.GetOpt

Joey Hess's avatar
Joey Hess committed
import Common.Annex
import qualified Annex
Joey Hess's avatar
Joey Hess committed
import qualified Annex.Queue
Joey Hess's avatar
Joey Hess committed
import qualified Git
Joey Hess's avatar
Joey Hess committed
import qualified Git.Command
Joey Hess's avatar
Joey Hess committed
import Annex.Content
Joey Hess's avatar
Joey Hess committed
import Annex.Ssh
Joey Hess's avatar
Joey Hess committed
type Params = [String]
type Flags = [Annex ()]

Joey Hess's avatar
Joey Hess committed
{- Runs the passed command line. -}
dispatch :: Params -> [Command] -> [Option] -> String -> IO Git.Repo -> IO ()
dispatch args cmds commonoptions header getgitrepo = do
	r <- E.try getgitrepo :: IO (Either E.SomeException Git.Repo)
	case r of
Joey Hess's avatar
Joey Hess committed
		Left e -> fromMaybe (throw e) (cmdnorepo cmd)
		Right g -> do
			state <- Annex.new g
			(actions, state') <- Annex.run state $ do
				sequence_ flags
				prepCommand cmd params
			tryRun state' cmd $ [startup] ++ actions ++ [shutdown $ cmdoneshot cmd]
Joey Hess's avatar
Joey Hess committed
	where
Joey Hess's avatar
Joey Hess committed
		(flags, cmd, params) = parseCmd args cmds commonoptions header
Joey Hess's avatar
Joey Hess committed

Joey Hess's avatar
Joey Hess committed
{- Parses command line, and returns actions to run to configure flags,
 - the Command being run, and the remaining parameters for the command. -} 
parseCmd :: Params -> [Command] -> [Option] -> String -> (Flags, Command, Params)
Joey Hess's avatar
Joey Hess committed
parseCmd argv cmds commonoptions header
Joey Hess's avatar
Joey Hess committed
	| isNothing name = err "missing command"
Joey Hess's avatar
Joey Hess committed
	| null matches = err $ "unknown command " ++ fromJust name
	| otherwise = check $ getOpt Permute (commonoptions ++ cmdoptions cmd) args
Joey Hess's avatar
Joey Hess committed
		(name, args) = findname argv []
		findname [] c = (Nothing, reverse c)
		findname (a:as) c
			| "-" `isPrefixOf` a = findname as (a:c)
			| otherwise = (Just a, reverse c ++ as)
		matches = filter (\c -> name == Just (cmdname c)) cmds
		cmd = Prelude.head matches
		check (flags, rest, []) = (flags, cmd, rest)
Joey Hess's avatar
Joey Hess committed
		check (_, _, errs) = err $ concat errs
Joey Hess's avatar
Joey Hess committed
		err msg = error $ msg ++ "\n\n" ++ usage header cmds commonoptions
Joey Hess's avatar
Joey Hess committed

{- Runs a list of Annex actions. Catches IO errors and continues
 - (but explicitly thrown errors terminate the whole command).
 -}
Joey Hess's avatar
Joey Hess committed
tryRun :: Annex.AnnexState -> Command -> [CommandCleanup] -> IO ()
Joey Hess's avatar
Joey Hess committed
tryRun = tryRun' 0
Joey Hess's avatar
Joey Hess committed
tryRun' :: Integer -> Annex.AnnexState -> Command -> [CommandCleanup] -> IO ()
tryRun' errnum _ cmd []
	| errnum > 0 = error $ cmdname cmd ++ ": " ++ show errnum ++ " failed"
	| otherwise = return ()
Joey Hess's avatar
Joey Hess committed
tryRun' errnum state cmd (a:as) = do
	r <- run
	handle $! r
Joey Hess's avatar
Joey Hess committed
	where
Joey Hess's avatar
Joey Hess committed
		run = tryIO $ Annex.run state $ do
Joey Hess's avatar
Joey Hess committed
			Annex.Queue.flushWhenFull
			a
		handle (Left err) = showerr err >> cont False state
		handle (Right (success, state')) = cont success state'
Joey Hess's avatar
Joey Hess committed
		cont success s = do
			let errnum' = if success then errnum else errnum + 1
			(tryRun' $! errnum') s cmd as
Joey Hess's avatar
Joey Hess committed
		showerr err = Annex.eval state $ do
			showErr err
			showEndFail
Joey Hess's avatar
Joey Hess committed

{- Actions to perform each time ran. -}
startup :: Annex Bool
startup = return True
Joey Hess's avatar
Joey Hess committed

{- Cleanup actions. -}
shutdown :: Bool -> Annex Bool
shutdown oneshot = do
	saveState oneshot
	sequence_ =<< M.elems <$> Annex.getState Annex.cleanup
Joey Hess's avatar
Joey Hess committed
	liftIO Git.Command.reap -- zombies from long-running git processes
Joey Hess's avatar
Joey Hess committed
	sshCleanup -- ssh connection caching
	return True