pre-init config and hook

Added annex.pre-init-command git config and pre-init-annex hook that is run
before git-annex repository initialization.

This can block initialization. Or it can preform pre-initialization
configuration or tweaking.

I left stdio connected while it's running, so it could also be used for
interactive prompting conceivably, although that would want to use /dev/tty
anyway probably in order to not pollute the stdout of a command when
automatic initialization is done.

Sponsored-by: Dartmouth College's OpenNeuro project
This commit is contained in:
Joey Hess 2025-01-13 14:22:49 -04:00
parent 9e95556d69
commit 42d55bc57c
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
9 changed files with 87 additions and 19 deletions

View file

@ -48,6 +48,9 @@ preCommitAnnexHook = Git.Hook "pre-commit-annex" "" []
postUpdateAnnexHook :: Git.Hook
postUpdateAnnexHook = Git.Hook "post-update-annex" "" []
preInitAnnexHook :: Git.Hook
preInitAnnexHook = Git.Hook "pre-init-annex" "" []
freezeContentAnnexHook :: Git.Hook
freezeContentAnnexHook = Git.Hook "freezecontent-annex" "" []
@ -98,20 +101,33 @@ doesAnnexHookExist hook = do
return exists
runAnnexHook :: Git.Hook -> (GitConfig -> Maybe String) -> Annex ()
runAnnexHook hook commandcfg = ifM (doesAnnexHookExist hook)
runAnnexHook hook commandcfg = runAnnexHook' hook commandcfg >>= \case
Nothing -> noop
Just failedcommanddesc ->
warning $ UnquotedString $ failedcommanddesc ++ " failed"
-- Returns Nothing if the hook or GitConfig command succeeded, or a
-- description of what failed.
runAnnexHook' :: Git.Hook -> (GitConfig -> Maybe String) -> Annex (Maybe String)
runAnnexHook' hook commandcfg = ifM (doesAnnexHookExist hook)
( runhook
, runcommandcfg
)
where
runhook = unlessM (inRepo $ Git.runHook boolSystem hook []) $ do
h <- fromRepo $ Git.hookFile hook
commandfailed h
runhook = ifM (inRepo $ Git.runHook boolSystem hook [])
( return Nothing
, do
h <- fromRepo (Git.hookFile hook)
commandfailed h
)
runcommandcfg = commandcfg <$> Annex.getGitConfig >>= \case
Nothing -> return Nothing
Just command ->
unlessM (liftIO $ boolSystem "sh" [Param "-c", Param command]) $
commandfailed command
Nothing -> noop
commandfailed c = warning $ UnquotedString $ c ++ " failed"
ifM (liftIO $ boolSystem "sh" [Param "-c", Param command])
( return Nothing
, commandfailed $ "git configured command '" ++ command ++ "'"
)
commandfailed c = return $ Just c
runAnnexPathHook :: String -> Git.Hook -> (GitConfig -> Maybe String) -> RawFilePath -> Annex Bool
runAnnexPathHook pathtoken hook commandcfg p = ifM (doesAnnexHookExist hook)
@ -121,9 +137,9 @@ runAnnexPathHook pathtoken hook commandcfg p = ifM (doesAnnexHookExist hook)
where
runhook = inRepo $ Git.runHook boolSystem hook [ File (fromRawFilePath p) ]
runcommandcfg = commandcfg <$> Annex.getGitConfig >>= \case
Nothing -> return True
Just basecmd -> liftIO $
boolSystem "sh" [Param "-c", Param $ gencmd basecmd]
Nothing -> return True
gencmd = massReplace [ (pathtoken, shellEscape (fromRawFilePath p)) ]
outputOfAnnexHook :: Git.Hook -> (GitConfig -> Maybe String) -> Annex (Maybe String)
@ -135,6 +151,6 @@ outputOfAnnexHook hook commandcfg = ifM (doesAnnexHookExist hook)
runhook = inRepo (Git.runHook runhook' hook [])
runhook' c ps = Just <$> readProcess c (toCommand ps)
runcommandcfg = commandcfg <$> Annex.getGitConfig >>= \case
Nothing -> return Nothing
Just command -> liftIO $
Just <$> readProcess "sh" ["-c", command]
Nothing -> return Nothing

View file

@ -1,6 +1,6 @@
{- git-annex repository initialization
-
- Copyright 2011-2024 Joey Hess <id@joeyh.name>
- Copyright 2011-2025 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
@ -74,17 +74,29 @@ data InitializeAllowed = InitializeAllowed
checkInitializeAllowed :: (InitializeAllowed -> Annex a) -> Annex a
checkInitializeAllowed a = guardSafeToUseRepo $ noAnnexFileContent' >>= \case
Nothing -> do
checkSqliteWorks
a InitializeAllowed
Nothing -> runAnnexHook' preInitAnnexHook annexPreInitCommand >>= \case
Nothing -> do
checkSqliteWorks
a InitializeAllowed
Just failedcommanddesc -> do
initpreventedby failedcommanddesc
notinitialized
Just noannexmsg -> do
warning "Initialization prevented by .noannex file (remove the file to override)"
initpreventedby ".noannex file (remove the file to override)"
unless (null noannexmsg) $
warning (UnquotedString noannexmsg)
giveup "Not initialized."
notinitialized
where
initpreventedby r = warning $ UnquotedString $
"Initialization prevented by " ++ r
notinitialized = giveup "Not initialized."
initializeAllowed :: Annex Bool
initializeAllowed = isNothing <$> noAnnexFileContent'
initializeAllowed = noAnnexFileContent' >>= \case
Nothing -> runAnnexHook' preInitAnnexHook annexPreInitCommand >>= \case
Nothing -> return True
Just _ -> return False
Just _ -> return False
noAnnexFileContent' :: Annex (Maybe String)
noAnnexFileContent' = inRepo $
@ -268,7 +280,7 @@ autoInitialize' check startupannex remotelist =
getInitializedVersion >>= maybe needsinit checkUpgrade
where
needsinit =
whenM (initializeAllowed <&&> check) $ do
whenM (check <&&> initializeAllowed) $ do
initialize startupannex Nothing Nothing
autoEnableSpecialRemotes remotelist

View file

@ -22,6 +22,8 @@ git-annex (10.20250103) UNRELEASED; urgency=medium
annex.http-headers-command.
* Added git configs annex.post-update-command and annex.pre-commit-command
that correspond to the post-update-annex and pre-commit-annex hooks.
* Added annex.pre-init-command git config and pre-init-annex hook
that is run before git-annex repository initialization.
-- Joey Hess <id@joeyh.name> Fri, 03 Jan 2025 14:30:38 -0400

View file

@ -97,6 +97,7 @@ data GitConfig = GitConfig
, annexAlwaysCompact :: Bool
, annexCommitMessage :: Maybe String
, annexCommitMessageCommand :: Maybe String
, annexPreInitCommand :: Maybe String
, annexPreCommitCommand :: Maybe String
, annexPostUpdateCommand :: Maybe String
, annexMergeAnnexBranches :: Bool
@ -192,6 +193,7 @@ extractGitConfig configsource r = GitConfig
, annexAlwaysCompact = getbool (annexConfig "alwayscompact") True
, annexCommitMessage = getmaybe (annexConfig "commitmessage")
, annexCommitMessageCommand = getmaybe (annexConfig "commitmessage-command")
, annexPreInitCommand = getmaybe (annexConfig "pre-init-command")
, annexPreCommitCommand = getmaybe (annexConfig "pre-commit-command")
, annexPostUpdateCommand = getmaybe (annexConfig "post-update-command")
, annexMergeAnnexBranches = getbool (annexConfig "merge-annex-branches") True

View file

@ -27,7 +27,11 @@ already initialized git-annex repository.
A top-level `.noannex` file will prevent git-annex init from being used
in a repository. This is useful for repositories that have a policy
reason not to use git-annex. The content of the file will be displayed
to the user who tries to run git-annex init.
to the user who tries to run git-annex init.
The annex.pre-init-command git configuration or pre-init-annex hook
is run before initialization and can exit nonzero as well to prevent
initialization, as well as doing other setup.
# EXAMPLES

View file

@ -1176,6 +1176,16 @@ repository, using [[git-annex-config]]. See its man page for a list.)
Alternatively, a hook script can be installed in
`.git/hooks/pre-commit-annex`
* `annex.pre-init-command`
This command is run before the repository is initialized, either by
`git-annex init`, or automatic initialization. It can configure
the repository in any way needed. If it exits nonzero, the repository
initialization will fail.
Alternatively, a hook script can be installed in
`.git/hooks/pre-init-annex`
* `annex.alwayscompact`
By default, git-annex compacts data it records in the git-annex branch.

View file

@ -6,3 +6,5 @@ The idea is stemmed from discussions/problems with using freeze/thaw hooks, and
[[!meta author=yoh]]
[[!tag projects/openneuro]]
> [[done]] --[[Joey]]

View file

@ -0,0 +1,10 @@
[[!comment format=mdwn
username="joey"
subject="""comment 5"""
date="2025-01-13T17:33:02Z"
content="""
Note that the `.noannex` file that prevents init has some overlap with
a pre-init hook that exits nonzero. I guess the .noannex file has the
benefit of working in every clone of a repository without additional
configuration.
"""]]

View file

@ -0,0 +1,10 @@
[[!comment format=mdwn
username="joey"
subject="""comment 6"""
date="2025-01-13T18:17:42Z"
content="""
Implemented .git/hooks/pre-init-annex
(and alternatively git config annex.pre-init-command)
Note that this is also run before automatic initialization.
"""]]