annex.autocommit can be configured via git-annex config

... to control the default behavior in all clones of a repository.

This includes a new Configurable data type, so the GitConfig type indicates
which values can be configured this way.

The implementation should be quite efficient; the config log is only read
once, and only when a Configurable value has not already been set by
git-config.

Indeed, it would be nice in the future to extend this, so that git-config
is itself only read on demand. Some commands may not need to look at the
git configuration at all.

This commit was sponsored by Trenton Cronholm on Patreon.
This commit is contained in:
Joey Hess 2017-02-03 13:40:14 -04:00
parent d6d23d8a15
commit ed56dba868
No known key found for this signature in database
GPG key ID: C910D9222512E3C7
14 changed files with 93 additions and 26 deletions

View file

@ -114,7 +114,6 @@ data AnnexState = AnnexState
, checkignorehandle :: Maybe (Maybe CheckIgnoreHandle)
, forcebackend :: Maybe String
, globalnumcopies :: Maybe NumCopies
, globalconfig :: Maybe (M.Map String String)
, forcenumcopies :: Maybe NumCopies
, limit :: ExpandableMatcher Annex
, uuidmap :: Maybe UUIDMap
@ -166,7 +165,6 @@ newState c r = do
, checkignorehandle = Nothing
, forcebackend = Nothing
, globalnumcopies = Nothing
, globalconfig = Nothing
, forcenumcopies = Nothing
, limit = BuildingMatcher []
, uuidmap = Nothing

View file

@ -42,6 +42,7 @@ import Annex.InodeSentinal
import Git.Types
import Git.FilePath
import Config
import Config.GitConfig
import Utility.ThreadScheduler
import Logs.Location
import qualified Database.Keys
@ -83,7 +84,7 @@ instance E.Exception WatcherControl
watchThread :: NamedThread
watchThread = namedThread "Watcher" $
ifM (liftAnnex $ annexAutoCommit <$> Annex.getGitConfig)
ifM (liftAnnex $ getGitConfigVal annexAutoCommit)
( runWatcher
, waitFor ResumeWatcher runWatcher
)

View file

@ -43,6 +43,7 @@ import Utility.Gpg
import Annex.UUID
import Assistant.Ssh
import Config
import Config.GitConfig
import qualified Data.Text as T
import qualified Data.Map as M
@ -76,7 +77,7 @@ getRepoConfig uuid mremote = do
syncable <- case mremote of
Just r -> return $ remoteAnnexSync $ Remote.gitconfig r
Nothing -> annexAutoCommit <$> Annex.getGitConfig
Nothing -> getGitConfigVal annexAutoCommit
return $ RepoConfig
(T.pack $ maybe "here" Remote.name mremote)

View file

@ -12,7 +12,6 @@ module Assistant.WebApp.RepoList where
import Assistant.WebApp.Common
import Assistant.DaemonStatus
import Assistant.WebApp.Notifications
import qualified Annex
import qualified Remote
import qualified Types.Remote as Remote
import Remote.List (remoteListRefresh)
@ -21,6 +20,7 @@ import Logs.Remote
import Logs.Trust
import Logs.Group
import Config
import Config.GitConfig
import Git.Remote
import Assistant.Sync
import Config.Cost
@ -152,7 +152,7 @@ repoList reposelector
if includeHere reposelector
then do
r <- RepoUUID <$> getUUID
autocommit <- annexAutoCommit <$> Annex.getGitConfig
autocommit <- getGitConfigVal annexAutoCommit
let hereactions = if autocommit
then mkSyncingRepoActions r
else mkNotSyncingRepoActions r

View file

@ -7,6 +7,8 @@ git-annex (6.20170102) UNRELEASED; urgency=medium
taken for --json.
* vicfg: Include the numcopies configuation.
* config: New command for storing configuration in the git-annex branch.
* annex.autocommit can be configured via git-annex config, to control
the default behavior in all clones of a repository.
* stack.yaml: Update to lts-7.18.
* Some optimisations to string splitting code.
* unused: When large files are checked right into git, avoid buffering

View file

@ -39,6 +39,7 @@ import qualified Git.Ref
import qualified Git
import qualified Remote.Git
import Config
import Config.GitConfig
import Annex.Wanted
import Annex.Content
import Command.Get (getKey')
@ -237,7 +238,7 @@ commit o = stopUnless shouldcommit $ next $ next $ do
)
where
shouldcommit = pure (commitOption o)
<&&> (annexAutoCommit <$> Annex.getGitConfig)
<&&> getGitConfigVal annexAutoCommit
commitMsg :: Annex String
commitMsg = do

View file

@ -1,6 +1,6 @@
{- Git configuration
-
- Copyright 2011-2014 Joey Hess <id@joeyh.name>
- Copyright 2011-2017 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU GPL version 3 or higher.
-}
@ -24,7 +24,8 @@ data ConfigKey = ConfigKey String
instance Show ConfigKey where
show (ConfigKey s) = s
{- Looks up a setting in git config. -}
{- Looks up a setting in git config. This is not as efficient as using the
- GitConfig type. -}
getConfig :: ConfigKey -> String -> Annex String
getConfig (ConfigKey key) d = fromRepo $ Git.Config.get key d

36
Config/GitConfig.hs Normal file
View file

@ -0,0 +1,36 @@
{- git-annex configuration
-
- Copyright 2017 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Config.GitConfig where
import Annex.Common
import qualified Annex
import Types.GitConfig
import Git.Types
import Logs.Config
{- Gets a specific setting from GitConfig. If necessary, loads the
- repository-global defaults when the GitConfig does not yet
- have a value. -}
getGitConfigVal :: (GitConfig -> Configurable a) -> Annex a
getGitConfigVal f = do
v <- f <$> Annex.getGitConfig
case v of
HasConfig c -> return c
DefaultConfig _ -> do
r <- Annex.gitRepo
m <- loadGlobalConfig
let globalgc = extractGitConfig (r { config = m })
-- This merge of the repo-global config and the git
-- config makes all repository-global default
-- values populate the GitConfig with HasConfig
-- values, so it will only need to be done once.
Annex.changeGitConfig (\gc -> mergeGitConfig gc globalgc)
v' <- f <$> Annex.getGitConfig
case v' of
HasConfig c -> return c
DefaultConfig d -> return d

View file

@ -1,4 +1,4 @@
{- git-annex config log
{- git-annex repository-global config log
-
- Copyright 2017 Joey Hess <id@joeyh.name>
-
@ -15,7 +15,6 @@ module Logs.Config (
) where
import Annex.Common
import qualified Annex
import Logs
import Logs.MapLog
import qualified Annex.Branch
@ -44,18 +43,13 @@ unsetGlobalConfig name = do
when (curr /= Nothing) $
setGlobalConfig' name "" -- set to empty string to unset
-- Reads the global config log every time.
getGlobalConfig :: ConfigName -> Annex (Maybe ConfigValue)
getGlobalConfig name = do
m <- maybe loadGlobalConfig return
=<< Annex.getState Annex.globalconfig
return (M.lookup name m)
getGlobalConfig name = M.lookup name <$> loadGlobalConfig
parseGlobalConfig :: String -> MapLog ConfigName ConfigValue
parseGlobalConfig = parseMapLog Just Just
loadGlobalConfig :: Annex (M.Map ConfigName ConfigValue)
loadGlobalConfig = do
m <- M.filter (not . null) . simpleMap . parseGlobalConfig
<$> Annex.Branch.get configLog
Annex.changeState $ \s -> s { Annex.globalconfig = Just m }
return m
loadGlobalConfig = M.filter (not . null) . simpleMap . parseGlobalConfig
<$> Annex.Branch.get configLog

View file

@ -6,8 +6,10 @@
-}
module Types.GitConfig (
Configurable(..),
GitConfig(..),
extractGitConfig,
mergeGitConfig,
RemoteGitConfig(..),
extractRemoteGitConfig,
) where
@ -29,6 +31,14 @@ import Utility.HumanTime
import Utility.Gpg (GpgCmd, mkGpgCmd)
import Utility.ThreadScheduler (Seconds(..))
-- | A configurable value, that may not be fully determined yet.
data Configurable a
= HasConfig a
-- ^ Value is fully determined.
| DefaultConfig a
-- ^ A default value is known, but not all config sources
-- have been read yet.
{- Main git-annex settings. Each setting corresponds to a git-config key
- such as annex.foo -}
data GitConfig = GitConfig
@ -46,7 +56,7 @@ data GitConfig = GitConfig
, annexDelayAdd :: Maybe Int
, annexHttpHeaders :: [String]
, annexHttpHeadersCommand :: Maybe String
, annexAutoCommit :: Bool
, annexAutoCommit :: Configurable Bool
, annexDebug :: Bool
, annexWebOptions :: [String]
, annexQuviOptions :: [String]
@ -93,7 +103,8 @@ extractGitConfig r = GitConfig
, annexDelayAdd = getmayberead (annex "delayadd")
, annexHttpHeaders = getlist (annex "http-headers")
, annexHttpHeadersCommand = getmaybe (annex "http-headers-command")
, annexAutoCommit = getbool (annex "autocommit") True
, annexAutoCommit = configurable True $
getmaybebool (annex "autocommit")
, annexDebug = getbool (annex "debug") False
, annexWebOptions = getwords (annex "web-options")
, annexQuviOptions = getwords (annex "quvi-options")
@ -133,10 +144,26 @@ extractGitConfig r = GitConfig
getlist k = Git.Config.getList k r
getwords k = fromMaybe [] $ words <$> getmaybe k
configurable d Nothing = DefaultConfig d
configurable _ (Just v) = HasConfig v
annex k = "annex." ++ k
onemegabyte = 1000000
{- Merge a GitConfig that comes from git-config with one containing
- repository-global defaults. -}
mergeGitConfig :: GitConfig -> GitConfig -> GitConfig
mergeGitConfig gitconfig repoglobals = gitconfig
{ annexAutoCommit = merge annexAutoCommit
}
where
merge f = case f gitconfig of
HasConfig v -> HasConfig v
DefaultConfig d -> case f repoglobals of
HasConfig v -> HasConfig v
DefaultConfig _ -> HasConfig d
{- Per-remote git-annex settings. Each setting corresponds to a git-config
- key such as <remote>.annex-foo, or if that is not set, a default from
- annex.foo -}

View file

@ -25,9 +25,12 @@ Only a few make sense to be able to set such that all clones of a
repository see the setting, and so git-annex only looks for these:
These settings can be overridden on a per-repository basis using
`git config`:
`git config`.
None yet!
* `annex.autocommit`
Set to false to prevent the git-annex assistant and git-annex sync
from automatically committing changes to files in the repository.
# EXAMPLE

View file

@ -1006,8 +1006,8 @@ Here are all the supported configuration settings.
Set to false to prevent the git-annex assistant and git-annex sync
from automatically committing changes to files in the repository.
To configure the behavior in all repositories, this can be set in
[[git-annex-config]].
To configure the behavior in all clones of the repository,
this can be set in [[git-annex-config]].
* `annex.startupscan`

View file

@ -3,3 +3,5 @@ when using git-annex as a minority participant in a repository (eg. because in a
forgetting to do that explicit configuration results, in one sync command, easily results in an unwanted implicit commit that's pushed across remotes.
could there be a per-repository option (somewhere around .gitattributes, or maybe in the git-annex branch) that disables autocommits for the repository?
> [[done]] --[[Joey]]

View file

@ -793,6 +793,7 @@ Executable git-annex
Config
Config.Cost
Config.Files
Config.GitConfig
Creds
Crypto
Database.Fsck