reorganize some files and imports

This commit is contained in:
Joey Hess 2014-01-26 16:25:55 -04:00
parent 3149a62a35
commit 86ffeb73d1
34 changed files with 92 additions and 120 deletions

182
CmdLine/GitAnnex.hs Normal file
View file

@ -0,0 +1,182 @@
{- git-annex main program
-
- Copyright 2010-2013 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
{-# LANGUAGE CPP, OverloadedStrings #-}
module CmdLine.GitAnnex where
import qualified Git.CurrentRepo
import CmdLine
import Command
import qualified Command.Add
import qualified Command.Unannex
import qualified Command.Drop
import qualified Command.Move
import qualified Command.Copy
import qualified Command.Get
import qualified Command.LookupKey
import qualified Command.ExamineKey
import qualified Command.FromKey
import qualified Command.DropKey
import qualified Command.TransferKey
import qualified Command.TransferKeys
import qualified Command.ReKey
import qualified Command.Reinject
import qualified Command.Fix
import qualified Command.Init
import qualified Command.Describe
import qualified Command.InitRemote
import qualified Command.EnableRemote
import qualified Command.Fsck
import qualified Command.Repair
import qualified Command.Unused
import qualified Command.DropUnused
import qualified Command.AddUnused
import qualified Command.Unlock
import qualified Command.Lock
import qualified Command.PreCommit
import qualified Command.Find
import qualified Command.Whereis
import qualified Command.List
import qualified Command.Log
import qualified Command.Merge
import qualified Command.Info
import qualified Command.Status
import qualified Command.Migrate
import qualified Command.Uninit
import qualified Command.NumCopies
import qualified Command.Trust
import qualified Command.Untrust
import qualified Command.Semitrust
import qualified Command.Dead
import qualified Command.Group
import qualified Command.Wanted
import qualified Command.Schedule
import qualified Command.Ungroup
import qualified Command.Vicfg
import qualified Command.Sync
import qualified Command.Mirror
import qualified Command.AddUrl
#ifdef WITH_FEED
import qualified Command.ImportFeed
#endif
import qualified Command.RmUrl
import qualified Command.Import
import qualified Command.Map
import qualified Command.Direct
import qualified Command.Indirect
import qualified Command.Upgrade
import qualified Command.Forget
import qualified Command.Version
import qualified Command.Help
#ifdef WITH_ASSISTANT
import qualified Command.Watch
import qualified Command.Assistant
#ifdef WITH_WEBAPP
import qualified Command.WebApp
#endif
#ifdef WITH_XMPP
import qualified Command.XMPPGit
#endif
#endif
import qualified Command.Test
#ifdef WITH_TESTSUITE
import qualified Command.FuzzTest
#endif
#ifdef WITH_EKG
import System.Remote.Monitoring
#endif
cmds :: [Command]
cmds = concat
[ Command.Add.def
, Command.Get.def
, Command.Drop.def
, Command.Move.def
, Command.Copy.def
, Command.Unlock.def
, Command.Lock.def
, Command.Sync.def
, Command.Mirror.def
, Command.AddUrl.def
#ifdef WITH_FEED
, Command.ImportFeed.def
#endif
, Command.RmUrl.def
, Command.Import.def
, Command.Init.def
, Command.Describe.def
, Command.InitRemote.def
, Command.EnableRemote.def
, Command.Reinject.def
, Command.Unannex.def
, Command.Uninit.def
, Command.PreCommit.def
, Command.NumCopies.def
, Command.Trust.def
, Command.Untrust.def
, Command.Semitrust.def
, Command.Dead.def
, Command.Group.def
, Command.Wanted.def
, Command.Schedule.def
, Command.Ungroup.def
, Command.Vicfg.def
, Command.LookupKey.def
, Command.ExamineKey.def
, Command.FromKey.def
, Command.DropKey.def
, Command.TransferKey.def
, Command.TransferKeys.def
, Command.ReKey.def
, Command.Fix.def
, Command.Fsck.def
, Command.Repair.def
, Command.Unused.def
, Command.DropUnused.def
, Command.AddUnused.def
, Command.Find.def
, Command.Whereis.def
, Command.List.def
, Command.Log.def
, Command.Merge.def
, Command.Info.def
, Command.Status.def
, Command.Migrate.def
, Command.Map.def
, Command.Direct.def
, Command.Indirect.def
, Command.Upgrade.def
, Command.Forget.def
, Command.Version.def
, Command.Help.def
#ifdef WITH_ASSISTANT
, Command.Watch.def
, Command.Assistant.def
#ifdef WITH_WEBAPP
, Command.WebApp.def
#endif
#ifdef WITH_XMPP
, Command.XMPPGit.def
#endif
#endif
, Command.Test.def
#ifdef WITH_TESTSUITE
, Command.FuzzTest.def
#endif
]
header :: String
header = "git-annex command [option ...]"
run :: [String] -> IO ()
run args = do
#ifdef WITH_EKG
_ <- forkServer "localhost" 4242
#endif
dispatch True args cmds gitAnnexOptions [] header Git.CurrentRepo.get

View file

@ -0,0 +1,99 @@
{- git-annex options
-
- Copyright 2010, 2013 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module CmdLine.GitAnnex.Options where
import System.Console.GetOpt
import Common.Annex
import qualified Git.Config
import Git.Types
import Types.TrustLevel
import Types.NumCopies
import Types.Messages
import qualified Annex
import qualified Remote
import qualified Limit
import qualified Limit.Wanted
import CmdLine.Option
import CmdLine.Usage
gitAnnexOptions :: [Option]
gitAnnexOptions = commonOptions ++
[ Option ['N'] ["numcopies"] (ReqArg setnumcopies paramNumber)
"override default number of copies"
, Option [] ["trust"] (trustArg Trusted)
"override trust setting"
, Option [] ["semitrust"] (trustArg SemiTrusted)
"override trust setting back to default"
, Option [] ["untrust"] (trustArg UnTrusted)
"override trust setting to untrusted"
, Option ['c'] ["config"] (ReqArg setgitconfig "NAME=VALUE")
"override git configuration setting"
, Option ['x'] ["exclude"] (ReqArg Limit.addExclude paramGlob)
"skip files matching the glob pattern"
, Option ['I'] ["include"] (ReqArg Limit.addInclude paramGlob)
"limit to files matching the glob pattern"
, Option ['i'] ["in"] (ReqArg Limit.addIn paramRemote)
"match files present in a remote"
, Option ['C'] ["copies"] (ReqArg Limit.addCopies paramNumber)
"skip files with fewer copies"
, Option [] ["lackingcopies"] (ReqArg (Limit.addLackingCopies False) paramNumber)
"match files that need more copies"
, Option [] ["approxlackingcopies"] (ReqArg (Limit.addLackingCopies True) paramNumber)
"match files that need more copies (faster)"
, Option ['B'] ["inbackend"] (ReqArg Limit.addInBackend paramName)
"match files using a key-value backend"
, Option [] ["inallgroup"] (ReqArg Limit.addInAllGroup paramGroup)
"match files present in all remotes in a group"
, Option [] ["largerthan"] (ReqArg Limit.addLargerThan paramSize)
"match files larger than a size"
, Option [] ["smallerthan"] (ReqArg Limit.addSmallerThan paramSize)
"match files smaller than a size"
, Option [] ["want-get"] (NoArg Limit.Wanted.addWantGet)
"match files the repository wants to get"
, Option [] ["want-drop"] (NoArg Limit.Wanted.addWantDrop)
"match files the repository wants to drop"
, Option ['T'] ["time-limit"] (ReqArg Limit.addTimeLimit paramTime)
"stop after the specified amount of time"
, Option [] ["user-agent"] (ReqArg setuseragent paramName)
"override default User-Agent"
, Option [] ["trust-glacier"] (NoArg (Annex.setFlag "trustglacier"))
"Trust Amazon Glacier inventory"
] ++ matcherOptions
where
trustArg t = ReqArg (Remote.forceTrust t) paramRemote
setnumcopies v = maybe noop
(\n -> Annex.changeState $ \s -> s { Annex.forcenumcopies = Just $ NumCopies n })
(readish v)
setuseragent v = Annex.changeState $ \s -> s { Annex.useragent = Just v }
setgitconfig v = inRepo (Git.Config.store v)
>>= pure . (\r -> r { gitGlobalOpts = gitGlobalOpts r ++ [Param "-c", Param v] })
>>= Annex.changeGitRepo
keyOptions :: [Option]
keyOptions =
[ Option ['A'] ["all"] (NoArg (Annex.setFlag "all"))
"operate on all versions of all files"
, Option ['U'] ["unused"] (NoArg (Annex.setFlag "unused"))
"operate on files found by last run of git-annex unused"
, Option [] ["key"] (ReqArg (Annex.setField "key") paramKey)
"operate on specified key"
]
fromOption :: Option
fromOption = fieldOption ['f'] "from" paramRemote "source remote"
toOption :: Option
toOption = fieldOption ['t'] "to" paramRemote "destination remote"
fromToOptions :: [Option]
fromToOptions = [fromOption, toOption]
jsonOption :: Option
jsonOption = Option ['j'] ["json"] (NoArg (Annex.setOutput JSONOutput))
"enable JSON output"

199
CmdLine/GitAnnexShell.hs Normal file
View file

@ -0,0 +1,199 @@
{- git-annex-shell main program
-
- Copyright 2010-2012 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module CmdLine.GitAnnexShell where
import System.Environment
import System.Console.GetOpt
import Common.Annex
import qualified Git.Construct
import CmdLine
import Command
import Annex.UUID
import Annex (setField)
import Fields
import Utility.UserInfo
import Remote.GCrypt (getGCryptUUID)
import qualified Annex
import Init
import qualified Command.ConfigList
import qualified Command.InAnnex
import qualified Command.DropKey
import qualified Command.RecvKey
import qualified Command.SendKey
import qualified Command.TransferInfo
import qualified Command.Commit
import qualified Command.GCryptSetup
cmds_readonly :: [Command]
cmds_readonly = concat
[ gitAnnexShellCheck Command.ConfigList.def
, gitAnnexShellCheck Command.InAnnex.def
, gitAnnexShellCheck Command.SendKey.def
, gitAnnexShellCheck Command.TransferInfo.def
]
cmds_notreadonly :: [Command]
cmds_notreadonly = concat
[ gitAnnexShellCheck Command.RecvKey.def
, gitAnnexShellCheck Command.DropKey.def
, gitAnnexShellCheck Command.Commit.def
, Command.GCryptSetup.def
]
cmds :: [Command]
cmds = map adddirparam $ cmds_readonly ++ cmds_notreadonly
where
adddirparam c = c { cmdparamdesc = "DIRECTORY " ++ cmdparamdesc c }
options :: [OptDescr (Annex ())]
options = commonOptions ++
[ Option [] ["uuid"] (ReqArg checkUUID paramUUID) "local repository uuid"
]
where
checkUUID expected = getUUID >>= check
where
check u | u == toUUID expected = noop
check NoUUID = checkGCryptUUID expected
check u = unexpectedUUID expected u
checkGCryptUUID expected = check =<< getGCryptUUID True =<< gitRepo
where
check (Just u) | u == toUUID expected = noop
check Nothing = unexpected expected "uninitialized repository"
check (Just u) = unexpectedUUID expected u
unexpectedUUID expected u = unexpected expected $ "UUID " ++ fromUUID u
unexpected expected s = error $
"expected repository UUID " ++ expected ++ " but found " ++ s
header :: String
header = "git-annex-shell [-c] command [parameters ...] [option ...]"
run :: [String] -> IO ()
run [] = failure
-- skip leading -c options, passed by eg, ssh
run ("-c":p) = run p
-- a command can be either a builtin or something to pass to git-shell
run c@(cmd:dir:params)
| cmd `elem` builtins = builtin cmd dir params
| otherwise = external c
run c@(cmd:_)
-- Handle the case of being the user's login shell. It will be passed
-- a single string containing all the real parameters.
| "git-annex-shell " `isPrefixOf` cmd = run $ drop 1 $ shellUnEscape cmd
| cmd `elem` builtins = failure
| otherwise = external c
builtins :: [String]
builtins = map cmdname cmds
builtin :: String -> String -> [String] -> IO ()
builtin cmd dir params = do
checkNotReadOnly cmd
checkDirectory $ Just dir
let (params', fieldparams, opts) = partitionParams params
fields = filter checkField $ parseFields fieldparams
cmds' = map (newcmd $ unwords opts) cmds
dispatch False (cmd : params') cmds' options fields header $
Git.Construct.repoAbsPath dir >>= Git.Construct.fromAbsPath
where
addrsyncopts opts seek k = setField "RsyncOptions" opts >> seek k
newcmd opts c = c { cmdseek = addrsyncopts opts (cmdseek c) }
external :: [String] -> IO ()
external params = do
{- Normal git-shell commands all have the directory as their last
- parameter. -}
let lastparam = lastMaybe =<< shellUnEscape <$> lastMaybe params
(params', _, _) = partitionParams params
checkDirectory lastparam
checkNotLimited
unlessM (boolSystem "git-shell" $ map Param $ "-c":params') $
error "git-shell failed"
{- Split the input list into 3 groups separated with a double dash --.
- Parameters between two -- markers are field settings, in the form:
- field=value field=value
-
- Parameters after the last -- are the command itself and its arguments e.g.,
- rsync --bandwidth=100.
-}
partitionParams :: [String] -> ([String], [String], [String])
partitionParams ps = case segment (== "--") ps of
params:fieldparams:rest -> ( params, fieldparams, intercalate ["--"] rest )
[params] -> (params, [], [])
_ -> ([], [], [])
parseFields :: [String] -> [(String, String)]
parseFields = map (separate (== '='))
{- Only allow known fields to be set, ignore others.
- Make sure that field values make sense. -}
checkField :: (String, String) -> Bool
checkField (field, value)
| field == fieldName remoteUUID = fieldCheck remoteUUID value
| field == fieldName associatedFile = fieldCheck associatedFile value
| field == fieldName direct = fieldCheck direct value
| otherwise = False
failure :: IO ()
failure = error $ "bad parameters\n\n" ++ usage header cmds
checkNotLimited :: IO ()
checkNotLimited = checkEnv "GIT_ANNEX_SHELL_LIMITED"
checkNotReadOnly :: String -> IO ()
checkNotReadOnly cmd
| cmd `elem` map cmdname cmds_readonly = noop
| otherwise = checkEnv "GIT_ANNEX_SHELL_READONLY"
checkDirectory :: Maybe FilePath -> IO ()
checkDirectory mdir = do
v <- catchMaybeIO $ getEnv "GIT_ANNEX_SHELL_DIRECTORY"
case (v, mdir) of
(Nothing, _) -> noop
(Just d, Nothing) -> req d Nothing
(Just d, Just dir)
| d `equalFilePath` dir -> noop
| otherwise -> do
home <- myHomeDir
d' <- canondir home d
dir' <- canondir home dir
if d' `equalFilePath` dir'
then noop
else req d' (Just dir')
where
req d mdir' = error $ unwords
[ "Only allowed to access"
, d
, maybe "and could not determine directory from command line" ("not " ++) mdir'
]
{- A directory may start with ~/ or in some cases, even /~/,
- or could just be relative to home, or of course could
- be absolute. -}
canondir home d
| "~/" `isPrefixOf` d = return d
| "/~/" `isPrefixOf` d = return $ drop 1 d
| otherwise = relHome $ absPathFrom home d
checkEnv :: String -> IO ()
checkEnv var = do
v <- catchMaybeIO $ getEnv var
case v of
Nothing -> noop
Just "" -> noop
Just _ -> error $ "Action blocked by " ++ var
{- Modifies a Command to check that it is run in either a git-annex
- repository, or a repository with a gcrypt-id set. -}
gitAnnexShellCheck :: [Command] -> [Command]
gitAnnexShellCheck = map $ addCheck okforshell . dontCheck repoExists
where
okforshell = unlessM (isInitialized <||> isJust . gcryptId <$> Annex.getGitConfig) $
error "Not a git-annex or gcrypt repository."

77
CmdLine/Option.hs Normal file
View file

@ -0,0 +1,77 @@
{- common command-line options
-
- Copyright 2010-2011 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module CmdLine.Option (
commonOptions,
matcherOptions,
flagOption,
fieldOption,
optionName,
ArgDescr(..),
OptDescr(..),
) where
import System.Console.GetOpt
import Common.Annex
import qualified Annex
import Types.Messages
import Limit
import CmdLine.Usage
commonOptions :: [Option]
commonOptions =
[ Option [] ["force"] (NoArg (setforce True))
"allow actions that may lose annexed data"
, Option ['F'] ["fast"] (NoArg (setfast True))
"avoid slow operations"
, Option ['a'] ["auto"] (NoArg (setauto True))
"automatic mode"
, Option ['q'] ["quiet"] (NoArg (Annex.setOutput QuietOutput))
"avoid verbose output"
, Option ['v'] ["verbose"] (NoArg (Annex.setOutput NormalOutput))
"allow verbose output (default)"
, Option ['d'] ["debug"] (NoArg setdebug)
"show debug messages"
, Option [] ["no-debug"] (NoArg unsetdebug)
"don't show debug messages"
, Option ['b'] ["backend"] (ReqArg setforcebackend paramName)
"specify key-value backend to use"
]
where
setforce v = Annex.changeState $ \s -> s { Annex.force = v }
setfast v = Annex.changeState $ \s -> s { Annex.fast = v }
setauto v = Annex.changeState $ \s -> s { Annex.auto = v }
setforcebackend v = Annex.changeState $ \s -> s { Annex.forcebackend = Just v }
setdebug = Annex.changeGitConfig $ \c -> c { annexDebug = True }
unsetdebug = Annex.changeGitConfig $ \c -> c { annexDebug = False }
matcherOptions :: [Option]
matcherOptions =
[ longopt "not" "negate next option"
, longopt "and" "both previous and next option must match"
, longopt "or" "either previous or next option must match"
, shortopt "(" "open group of options"
, shortopt ")" "close group of options"
]
where
longopt o = Option [] [o] $ NoArg $ addToken o
shortopt o = Option o [] $ NoArg $ addToken o
{- An option that sets a flag. -}
flagOption :: String -> String -> String -> Option
flagOption short opt description =
Option short [opt] (NoArg (Annex.setFlag opt)) description
{- An option that sets a field. -}
fieldOption :: String -> String -> String -> String -> Option
fieldOption short opt paramdesc description =
Option short [opt] (ReqArg (Annex.setField opt) paramdesc) description
{- The flag or field name used for an option. -}
optionName :: Option -> String
optionName (Option _ o _ _) = Prelude.head o

182
CmdLine/Seek.hs Normal file
View file

@ -0,0 +1,182 @@
{- git-annex command seeking
-
- These functions find appropriate files or other things based on
- the values a user passes to a command, and prepare actions operating
- on them.
-
- Copyright 2010-2014 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module CmdLine.Seek where
import System.PosixCompat.Files
import Common.Annex
import Types.Command
import Types.Key
import Types.FileMatcher
import qualified Annex
import qualified Git
import qualified Git.Command
import qualified Git.LsFiles as LsFiles
import qualified Limit
import CmdLine.Option
import Logs.Location
import Logs.Unused
import Annex.CatFile
import RunCommand
withFilesInGit :: (FilePath -> CommandStart) -> CommandSeek
withFilesInGit a params = seekActions $ prepFiltered a $
seekHelper LsFiles.inRepo params
withFilesNotInGit :: (FilePath -> CommandStart) -> CommandSeek
withFilesNotInGit a params = do
{- dotfiles are not acted on unless explicitly listed -}
files <- filter (not . dotfile) <$>
seekunless (null ps && not (null params)) ps
dotfiles <- seekunless (null dotps) dotps
seekActions $ prepFiltered a $
return $ concat $ segmentPaths params (files++dotfiles)
where
(dotps, ps) = partition dotfile params
seekunless True _ = return []
seekunless _ l = do
force <- Annex.getState Annex.force
g <- gitRepo
liftIO $ Git.Command.leaveZombie <$> LsFiles.notInRepo force l g
withPathContents :: ((FilePath, FilePath) -> CommandStart) -> CommandSeek
withPathContents a params = seekActions $
map a . concat <$> liftIO (mapM get params)
where
get p = ifM (isDirectory <$> getFileStatus p)
( map (\f -> (f, makeRelative (parentDir p) f))
<$> dirContentsRecursiveSkipping (".git" `isSuffixOf`) True p
, return [(p, takeFileName p)]
)
withWords :: ([String] -> CommandStart) -> CommandSeek
withWords a params = seekActions $ return [a params]
withStrings :: (String -> CommandStart) -> CommandSeek
withStrings a params = seekActions $ return $ map a params
withPairs :: ((String, String) -> CommandStart) -> CommandSeek
withPairs a params = seekActions $ return $ map a $ pairs [] params
where
pairs c [] = reverse c
pairs c (x:y:xs) = pairs ((x,y):c) xs
pairs _ _ = error "expected pairs"
withFilesToBeCommitted :: (String -> CommandStart) -> CommandSeek
withFilesToBeCommitted a params = seekActions $ prepFiltered a $
seekHelper LsFiles.stagedNotDeleted params
withFilesUnlocked :: (FilePath -> CommandStart) -> CommandSeek
withFilesUnlocked = withFilesUnlocked' LsFiles.typeChanged
withFilesUnlockedToBeCommitted :: (FilePath -> CommandStart) -> CommandSeek
withFilesUnlockedToBeCommitted = withFilesUnlocked' LsFiles.typeChangedStaged
{- Unlocked files have changed type from a symlink to a regular file.
-
- Furthermore, unlocked files used to be a git-annex symlink,
- not some other sort of symlink.
-}
withFilesUnlocked' :: ([FilePath] -> Git.Repo -> IO ([FilePath], IO Bool)) -> (FilePath -> CommandStart) -> CommandSeek
withFilesUnlocked' typechanged a params = seekActions $
prepFiltered a unlockedfiles
where
check f = liftIO (notSymlink f) <&&>
(isJust <$> catKeyFile f <||> isJust <$> catKeyFileHEAD f)
unlockedfiles = filterM check =<< seekHelper typechanged params
{- Finds files that may be modified. -}
withFilesMaybeModified :: (FilePath -> CommandStart) -> CommandSeek
withFilesMaybeModified a params = seekActions $
prepFiltered a $ seekHelper LsFiles.modified params
withKeys :: (Key -> CommandStart) -> CommandSeek
withKeys a params = seekActions $ return $ map (a . parse) params
where
parse p = fromMaybe (error "bad key") $ file2key p
{- Gets the value of a field options, which is fed into
- a conversion function.
-}
getOptionField :: Option -> (Maybe String -> Annex a) -> Annex a
getOptionField option converter = converter <=< Annex.getField $ optionName option
getOptionFlag :: Option -> Annex Bool
getOptionFlag option = Annex.getFlag (optionName option)
withNothing :: CommandStart -> CommandSeek
withNothing a [] = seekActions $ return [a]
withNothing _ _ = error "This command takes no parameters."
{- If --all is specified, or in a bare repo, runs an action on all
- known keys.
-
- If --unused is specified, runs an action on all keys found by
- the last git annex unused scan.
-
- If --key is specified, operates only on that key.
-
- Otherwise, fall back to a regular CommandSeek action on
- whatever params were passed. -}
withKeyOptions :: (Key -> CommandStart) -> CommandSeek -> CommandSeek
withKeyOptions keyop fallbackop params = do
bare <- fromRepo Git.repoIsLocalBare
allkeys <- Annex.getFlag "all"
unused <- Annex.getFlag "unused"
specifickey <- Annex.getField "key"
auto <- Annex.getState Annex.auto
when (auto && bare) $
error "Cannot use --auto in a bare repository"
case (allkeys, unused, null params, specifickey) of
(False , False , True , Nothing)
| bare -> go auto loggedKeys
| otherwise -> fallbackop params
(False , False , _ , Nothing) -> fallbackop params
(True , False , True , Nothing) -> go auto loggedKeys
(False , True , True , Nothing) -> go auto unusedKeys'
(False , False , True , Just ks) -> case file2key ks of
Nothing -> error "Invalid key"
Just k -> go auto $ return [k]
_ -> error "Can only specify one of file names, --all, --unused, or --key"
where
go True _ = error "Cannot use --auto with --all or --unused or --key"
go False a = do
matcher <- Limit.getMatcher
seekActions $ map (process matcher) <$> a
process matcher k = ifM (matcher $ MatchingKey k)
( keyop k , return Nothing)
prepFiltered :: (FilePath -> CommandStart) -> Annex [FilePath] -> Annex [CommandStart]
prepFiltered a fs = do
matcher <- Limit.getMatcher
map (process matcher) <$> fs
where
process matcher f = ifM (matcher $ MatchingFile $ FileInfo f f)
( a f , return Nothing )
seekActions :: Annex [CommandStart] -> Annex ()
seekActions gen = do
as <- gen
mapM_ commandAction as
seekHelper :: ([FilePath] -> Git.Repo -> IO ([FilePath], IO Bool)) -> [FilePath] -> Annex [FilePath]
seekHelper a params = do
ll <- inRepo $ \g ->
runSegmentPaths (\fs -> Git.Command.leaveZombie <$> a fs g) params
{- Show warnings only for files/directories that do not exist. -}
forM_ (map fst $ filter (null . snd) $ zip params ll) $ \p ->
unlessM (isJust <$> liftIO (catchMaybeIO $ getSymbolicLinkStatus p)) $
fileNotFound p
return $ concat ll
notSymlink :: FilePath -> IO Bool
notSymlink f = liftIO $ not . isSymbolicLink <$> getSymbolicLinkStatus f

111
CmdLine/Usage.hs Normal file
View file

@ -0,0 +1,111 @@
{- git-annex usage messages
-
- Copyright 2010-2011 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module CmdLine.Usage where
import Common.Annex
import Types.Command
import System.Console.GetOpt
usageMessage :: String -> String
usageMessage s = "Usage: " ++ s
{- Usage message with lists of commands by section. -}
usage :: String -> [Command] -> String
usage header cmds = unlines $ usageMessage header : concatMap go [minBound..]
where
go section
| null cs = []
| otherwise =
[ ""
, descSection section ++ ":"
, ""
] ++ map cmdline cs
where
cs = filter (\c -> cmdsection c == section) scmds
cmdline c = concat
[ cmdname c
, namepad (cmdname c)
, cmdparamdesc c
, descpad (cmdparamdesc c)
, cmddesc c
]
pad n s = replicate (n - length s) ' '
namepad = pad $ longest cmdname + 1
descpad = pad $ longest cmdparamdesc + 2
longest f = foldl max 0 $ map (length . f) cmds
scmds = sort cmds
{- Usage message for a single command. -}
commandUsage :: Command -> String
commandUsage cmd = unlines
[ usageInfo header (cmdoptions cmd)
, "To see additional options common to all commands, run: git annex help options"
]
where
header = usageMessage $ unwords
[ "git-annex"
, cmdname cmd
, cmdparamdesc cmd
, "[option ...]"
]
{- Descriptions of params used in usage messages. -}
paramPaths :: String
paramPaths = paramOptional $ paramRepeating paramPath -- most often used
paramPath :: String
paramPath = "PATH"
paramKey :: String
paramKey = "KEY"
paramDesc :: String
paramDesc = "DESC"
paramUrl :: String
paramUrl = "URL"
paramNumber :: String
paramNumber = "NUMBER"
paramNumRange :: String
paramNumRange = "NUM|RANGE"
paramRemote :: String
paramRemote = "REMOTE"
paramGlob :: String
paramGlob = "GLOB"
paramName :: String
paramName = "NAME"
paramValue :: String
paramValue = "VALUE"
paramUUID :: String
paramUUID = "UUID"
paramType :: String
paramType = "TYPE"
paramDate :: String
paramDate = "DATE"
paramTime :: String
paramTime = "TIME"
paramFormat :: String
paramFormat = "FORMAT"
paramFile :: String
paramFile = "FILE"
paramGroup :: String
paramGroup = "GROUP"
paramExpression :: String
paramExpression = "EXPR"
paramSize :: String
paramSize = "SIZE"
paramAddress :: String
paramAddress = "ADDRESS"
paramKeyValue :: String
paramKeyValue = "K=V"
paramNothing :: String
paramNothing = ""
paramRepeating :: String -> String
paramRepeating s = s ++ " ..."
paramOptional :: String -> String
paramOptional s = "[" ++ s ++ "]"
paramPair :: String -> String -> String
paramPair a b = a ++ " " ++ b