64738ea157
* config: Added the --show-origin and --for-file options. * config: Support annex.numcopies and annex.mincopies. There is a little bit of redundancy here with other code elsewhere that combines the various configs and selects which to use. But really only for the special case of annex.numcopies, which is a git config that does not override the annex branch setting and for annex.mincopies, which does not have a git config but does have gitattributes settings as well as the annex branch setting. That seems small enough, and unlikely enough to grow into a mess that it was worth supporting annex.numcopies and annex.mincopies in git-annex config --show-origin. Because these settings are a prime thing that someone might get confused about and want to know where they were configured. And, it followed that git-annex config might as well support those two for --set and --get as well. While this is redundant with the speclialized commands, it's only a little code and it makes it more consistent. Note that --set does not have as nice output as numcopies/mincopies commands in some special cases like setting to 0 or a negative number. It does avoid setting to a bad value thanks to the smart constructors (eg configuredNumCopies). As for other git-annex branch configurations that are not set by git-annex config, things like trust and wanted that are specific to a repository don't map to a git config name, so don't really fit into git-annex config. And they are only configured in the git-annex branch with no local override (at least so far), so --show-origin would not be useful for them. Sponsored-by: Dartmouth College's DANDI project
216 lines
6.1 KiB
Haskell
216 lines
6.1 KiB
Haskell
{- git-annex command
|
|
-
|
|
- Copyright 2017-2023 Joey Hess <id@joeyh.name>
|
|
-
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
|
-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
module Command.Config where
|
|
|
|
import Command
|
|
import Logs.Config
|
|
import Config
|
|
import Types.GitConfig (globalConfigs)
|
|
import Git.Types (fromConfigValue, fromConfigKey)
|
|
import qualified Git.Command
|
|
import Utility.SafeOutput
|
|
import Annex.CheckAttr
|
|
import Types.NumCopies
|
|
import Logs.NumCopies
|
|
|
|
import qualified Data.ByteString.Char8 as S8
|
|
|
|
cmd :: Command
|
|
cmd = noMessages $ command "config" SectionSetup
|
|
"configuration stored in git-annex branch"
|
|
paramNothing (seek <$$> optParser)
|
|
|
|
data Action
|
|
= SetConfig ConfigKey ConfigValue
|
|
| GetConfig ConfigKey
|
|
| UnsetConfig ConfigKey
|
|
| ShowOrigin ConfigKey (Maybe FilePath)
|
|
|
|
type Name = String
|
|
type Value = String
|
|
|
|
optParser :: CmdParamsDesc -> Parser Action
|
|
optParser _ = setconfig <|> getconfig <|> unsetconfig <|> showorigin
|
|
where
|
|
setconfig = SetConfig
|
|
<$> strOption
|
|
( long "set"
|
|
<> help "set configuration"
|
|
<> metavar paramName
|
|
)
|
|
<*> strArgument
|
|
( metavar paramValue
|
|
)
|
|
getconfig = GetConfig <$> strOption
|
|
( long "get"
|
|
<> help "get configuration"
|
|
<> metavar paramName
|
|
)
|
|
unsetconfig = UnsetConfig <$> strOption
|
|
( long "unset"
|
|
<> help "unset configuration"
|
|
<> metavar paramName
|
|
)
|
|
showorigin = ShowOrigin
|
|
<$> strOption
|
|
( long "show-origin"
|
|
<> help "explain where a value is configured"
|
|
<> metavar paramName
|
|
)
|
|
<*> optional (strOption
|
|
( long "for-file"
|
|
<> help "filename to check for in gitattributes"
|
|
<> metavar paramFile
|
|
))
|
|
|
|
seek :: Action -> CommandSeek
|
|
seek (SetConfig ck@(ConfigKey name) val) = checkIsGlobalConfig ck $ \setter _unsetter _getter ->
|
|
commandAction $ startingUsualMessages (decodeBS name) ai si $ do
|
|
setter val
|
|
when (needLocalUpdate ck) $
|
|
setConfig ck (fromConfigValue val)
|
|
next $ return True
|
|
where
|
|
ai = ActionItemOther (Just (UnquotedString (fromConfigValue val)))
|
|
si = SeekInput [decodeBS name]
|
|
seek (UnsetConfig ck@(ConfigKey name)) = checkIsGlobalConfig ck $ \_setter unsetter _getter ->
|
|
commandAction $ startingUsualMessages (decodeBS name) ai si $ do
|
|
unsetter
|
|
when (needLocalUpdate ck) $
|
|
unsetConfig ck
|
|
next $ return True
|
|
where
|
|
ai = ActionItemOther (Just "unset")
|
|
si = SeekInput [decodeBS name]
|
|
seek (GetConfig ck) = checkIsGlobalConfig ck $ \_setter _unsetter getter ->
|
|
commandAction $ startingCustomOutput ai $ do
|
|
getter >>= \case
|
|
Just (ConfigValue v) -> liftIO $ S8.putStrLn $ safeOutput v
|
|
Just NoConfigValue -> return ()
|
|
Nothing -> return ()
|
|
next $ return True
|
|
where
|
|
ai = ActionItemOther Nothing
|
|
seek (ShowOrigin ck@(ConfigKey name) forfile) = commandAction $
|
|
startingCustomOutput ai $ next $ checknotconfigured $
|
|
case checkIsGlobalConfig' ck of
|
|
Just (_setter, _unsetter, getter) ->
|
|
ifM gitconfigorigin
|
|
( return True
|
|
, checkattrs (checkconfigbranch getter)
|
|
)
|
|
Nothing -> ifM gitconfigorigin
|
|
( return True
|
|
, checkattrs checkgitconfigunderride
|
|
)
|
|
where
|
|
ai = ActionItemOther Nothing
|
|
|
|
gitconfigorigin
|
|
| name `elem` gitconfigdoesnotoverride = return False
|
|
| otherwise = gitconfigorigin'
|
|
gitconfigorigin' = inRepo $ Git.Command.runBool
|
|
[ Param "config"
|
|
, Param "--show-origin"
|
|
, Param (decodeBS name)
|
|
]
|
|
|
|
-- git configs for these do not override values from git attributes
|
|
-- or the branch
|
|
gitconfigdoesnotoverride =
|
|
[ "annex.numcopies"
|
|
, "annex.mincopies"
|
|
]
|
|
|
|
-- the git config for annex.numcopies is a special case; it's only
|
|
-- used if not configured anywhere else
|
|
checkgitconfigunderride
|
|
| name == "annex.numcopies" = gitconfigorigin'
|
|
| otherwise = return False
|
|
|
|
-- Display similar to git config --show-origin
|
|
showval loc v = liftIO $ do
|
|
putStrLn $ loc ++ "\t" ++ v
|
|
return True
|
|
|
|
configbranch v
|
|
| needLocalUpdate ck = checkgitconfigunderride
|
|
| otherwise = showval "branch:git-annex" (decodeBS v)
|
|
|
|
checkconfigbranch getter = getter >>= \case
|
|
Just (ConfigValue v) -> configbranch v
|
|
_ -> checkgitconfigunderride
|
|
|
|
checkattrs cont
|
|
| decodeBS name `elem` annexAttrs =
|
|
case forfile of
|
|
Just file -> do
|
|
v <- checkAttr (decodeBS name) (toRawFilePath file)
|
|
if null v
|
|
then cont
|
|
else showval "gitattributes" v
|
|
Nothing -> do
|
|
warnforfile
|
|
cont
|
|
| otherwise = cont
|
|
|
|
warnforfile = warning $ UnquotedString $ configKeyMessage ck $ unwords
|
|
[ "may be configured in gitattributes."
|
|
, "Pass --for-file= with a filename to check"
|
|
]
|
|
|
|
checknotconfigured a = do
|
|
ok <- a
|
|
unless ok $
|
|
warning $ UnquotedString $ configKeyMessage ck
|
|
"is not configured"
|
|
return ok
|
|
|
|
type Setter = ConfigValue -> Annex ()
|
|
type Unsetter = Annex ()
|
|
type Getter = Annex (Maybe ConfigValue)
|
|
|
|
checkIsGlobalConfig :: ConfigKey -> (Setter -> Unsetter -> Getter -> Annex a) -> Annex a
|
|
checkIsGlobalConfig ck a = case checkIsGlobalConfig' ck of
|
|
Just (setter, unsetter, getter) -> a setter unsetter getter
|
|
Nothing -> giveup $ configKeyMessage ck "is not a configuration setting that can be stored in the git-annex branch"
|
|
|
|
checkIsGlobalConfig' :: ConfigKey -> Maybe (Setter, Unsetter, Getter)
|
|
checkIsGlobalConfig' ck
|
|
| elem ck globalConfigs = Just
|
|
( setGlobalConfig ck
|
|
, unsetGlobalConfig ck
|
|
, getGlobalConfig ck
|
|
)
|
|
-- These came before this command, but are also global configs,
|
|
-- so support them here as well.
|
|
| ck == ConfigKey "annex.numcopies" = Just
|
|
( mksetter (setGlobalNumCopies . configuredNumCopies)
|
|
, error "unsetting annex.numcopies is not supported"
|
|
, mkgetter fromNumCopies getGlobalNumCopies
|
|
)
|
|
| ck == ConfigKey "annex.mincopies" = Just
|
|
( mksetter (setGlobalMinCopies . configuredMinCopies)
|
|
, error "unsetting annex.mincopies is not supported"
|
|
, mkgetter fromMinCopies getGlobalMinCopies
|
|
)
|
|
| otherwise = Nothing
|
|
where
|
|
mksetter f =
|
|
maybe (error ("invalid value for " ++ fromConfigKey ck)) f
|
|
. readish . decodeBS . fromConfigValue
|
|
mkgetter f g = fmap (ConfigValue . encodeBS . show . f) <$> g
|
|
|
|
configKeyMessage :: ConfigKey -> String -> String
|
|
configKeyMessage (ConfigKey name) msg = decodeBS name ++ " " ++ msg
|
|
|
|
needLocalUpdate :: ConfigKey -> Bool
|
|
needLocalUpdate (ConfigKey "annex.securehashesonly") = True
|
|
needLocalUpdate _ = False
|