add --dry-run: New option
This is intended for users who want to see what it would output in order to eg, check if a file would be added to git or the annex. It is not intended as a way for scripts to get information. Sponsored-by: Dartmouth College's Datalad project
This commit is contained in:
parent
e005bd6f98
commit
3a513cfe73
10 changed files with 78 additions and 27 deletions
|
@ -10,6 +10,7 @@ git-annex (10.20220725) UNRELEASED; urgency=medium
|
||||||
* Added new matching options --want-get-by and --want-drop-by.
|
* Added new matching options --want-get-by and --want-drop-by.
|
||||||
* Allow find --branch to be used in a bare repository, the same as
|
* Allow find --branch to be used in a bare repository, the same as
|
||||||
the deprecated findref can be.
|
the deprecated findref can be.
|
||||||
|
* add --dry-run: New option.
|
||||||
|
|
||||||
-- Joey Hess <id@joeyh.name> Mon, 25 Jul 2022 15:35:45 -0400
|
-- Joey Hess <id@joeyh.name> Mon, 25 Jul 2022 15:35:45 -0400
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,12 @@ parseUUIDOption :: String -> DeferredParse UUID
|
||||||
parseUUIDOption = DeferredParse
|
parseUUIDOption = DeferredParse
|
||||||
. (Remote.nameToUUID)
|
. (Remote.nameToUUID)
|
||||||
|
|
||||||
|
parseDryRunOption :: Parser DryRun
|
||||||
|
parseDryRunOption = DryRun <$> switch
|
||||||
|
( long "dry-run"
|
||||||
|
<> help "don't make changes, but show what would be done"
|
||||||
|
)
|
||||||
|
|
||||||
-- | From or To a remote.
|
-- | From or To a remote.
|
||||||
data FromToOptions
|
data FromToOptions
|
||||||
= FromRemote (DeferredParse Remote)
|
= FromRemote (DeferredParse Remote)
|
||||||
|
|
|
@ -106,6 +106,12 @@ stop = return Nothing
|
||||||
stopUnless :: Annex Bool -> Annex (Maybe a) -> Annex (Maybe a)
|
stopUnless :: Annex Bool -> Annex (Maybe a) -> Annex (Maybe a)
|
||||||
stopUnless c a = ifM c ( a , stop )
|
stopUnless c a = ifM c ( a , stop )
|
||||||
|
|
||||||
|
{- When doing a dry run, avoid actually performing the action, but pretend
|
||||||
|
- that it succeeded. -}
|
||||||
|
skipWhenDryRun :: DryRun -> CommandPerform -> CommandPerform
|
||||||
|
skipWhenDryRun (DryRun False) a = a
|
||||||
|
skipWhenDryRun (DryRun True) _ = next $ return True
|
||||||
|
|
||||||
{- When acting on a failed transfer, stops unless it was in the specified
|
{- When acting on a failed transfer, stops unless it was in the specified
|
||||||
- direction. -}
|
- direction. -}
|
||||||
checkFailedTransferDirection :: ActionItem -> Direction -> Annex (Maybe a) -> Annex (Maybe a)
|
checkFailedTransferDirection :: ActionItem -> Direction -> Annex (Maybe a) -> Annex (Maybe a)
|
||||||
|
|
|
@ -52,6 +52,7 @@ data AddOptions = AddOptions
|
||||||
, updateOnly :: Bool
|
, updateOnly :: Bool
|
||||||
, largeFilesOverride :: Maybe Bool
|
, largeFilesOverride :: Maybe Bool
|
||||||
, checkGitIgnoreOption :: CheckGitIgnore
|
, checkGitIgnoreOption :: CheckGitIgnore
|
||||||
|
, dryRunOption :: DryRun
|
||||||
}
|
}
|
||||||
|
|
||||||
optParser :: CmdParamsDesc -> Parser AddOptions
|
optParser :: CmdParamsDesc -> Parser AddOptions
|
||||||
|
@ -65,6 +66,7 @@ optParser desc = AddOptions
|
||||||
)
|
)
|
||||||
<*> (parseforcelarge <|> parseforcesmall)
|
<*> (parseforcelarge <|> parseforcesmall)
|
||||||
<*> checkGitIgnoreSwitch
|
<*> checkGitIgnoreSwitch
|
||||||
|
<*> parseDryRunOption
|
||||||
where
|
where
|
||||||
parseforcelarge = flag Nothing (Just True)
|
parseforcelarge = flag Nothing (Just True)
|
||||||
( long "force-large"
|
( long "force-large"
|
||||||
|
@ -91,16 +93,16 @@ seek o = startConcurrency commandStages $ do
|
||||||
ifM (pure (annexdotfiles || not (dotfile file))
|
ifM (pure (annexdotfiles || not (dotfile file))
|
||||||
<&&> (checkFileMatcher largematcher file
|
<&&> (checkFileMatcher largematcher file
|
||||||
<||> Annex.getRead Annex.force))
|
<||> Annex.getRead Annex.force))
|
||||||
( start si file addunlockedmatcher
|
( start dr si file addunlockedmatcher
|
||||||
, if includingsmall
|
, if includingsmall
|
||||||
then ifM (annexAddSmallFiles <$> Annex.getGitConfig)
|
then ifM (annexAddSmallFiles <$> Annex.getGitConfig)
|
||||||
( startSmall si file s
|
( startSmall dr si file s
|
||||||
, stop
|
, stop
|
||||||
)
|
)
|
||||||
else stop
|
else stop
|
||||||
)
|
)
|
||||||
Just True -> start si file addunlockedmatcher
|
Just True -> start dr si file addunlockedmatcher
|
||||||
Just False -> startSmallOverridden si file
|
Just False -> startSmallOverridden dr si file
|
||||||
case batchOption o of
|
case batchOption o of
|
||||||
Batch fmt
|
Batch fmt
|
||||||
| updateOnly o ->
|
| updateOnly o ->
|
||||||
|
@ -126,25 +128,26 @@ seek o = startConcurrency commandStages $ do
|
||||||
-- same as a modified unlocked file would get
|
-- same as a modified unlocked file would get
|
||||||
-- locked when added.
|
-- locked when added.
|
||||||
go False withUnmodifiedUnlockedPointers
|
go False withUnmodifiedUnlockedPointers
|
||||||
|
where
|
||||||
|
dr = dryRunOption o
|
||||||
|
|
||||||
{- Pass file off to git-add. -}
|
{- Pass file off to git-add. -}
|
||||||
startSmall :: SeekInput -> RawFilePath -> FileStatus -> CommandStart
|
startSmall :: DryRun -> SeekInput -> RawFilePath -> FileStatus -> CommandStart
|
||||||
startSmall si file s =
|
startSmall dr si file s =
|
||||||
starting "add" (ActionItemTreeFile file) si $
|
starting "add" (ActionItemTreeFile file) si $
|
||||||
next $ addSmall file s
|
addSmall dr file s
|
||||||
|
|
||||||
addSmall :: RawFilePath -> FileStatus -> Annex Bool
|
addSmall :: DryRun -> RawFilePath -> FileStatus -> CommandPerform
|
||||||
addSmall file s = do
|
addSmall dr file s = do
|
||||||
showNote "non-large file; adding content to git repository"
|
showNote "non-large file; adding content to git repository"
|
||||||
addFile Small file s
|
skipWhenDryRun dr $ next $ addFile Small file s
|
||||||
|
|
||||||
startSmallOverridden :: SeekInput -> RawFilePath -> CommandStart
|
startSmallOverridden :: DryRun -> SeekInput -> RawFilePath -> CommandStart
|
||||||
startSmallOverridden si file =
|
startSmallOverridden dr si file =
|
||||||
liftIO (catchMaybeIO $ R.getSymbolicLinkStatus file) >>= \case
|
liftIO (catchMaybeIO $ R.getSymbolicLinkStatus file) >>= \case
|
||||||
Just s -> starting "add" (ActionItemTreeFile file) si $ next $ do
|
Just s -> starting "add" (ActionItemTreeFile file) si $ do
|
||||||
|
|
||||||
showNote "adding content to git repository"
|
showNote "adding content to git repository"
|
||||||
addFile Small file s
|
skipWhenDryRun dr $ next $ addFile Small file s
|
||||||
Nothing -> stop
|
Nothing -> stop
|
||||||
|
|
||||||
data SmallOrLarge = Small | Large
|
data SmallOrLarge = Small | Large
|
||||||
|
@ -188,8 +191,8 @@ addFile smallorlarge file s = do
|
||||||
isRegularFile a /= isRegularFile b ||
|
isRegularFile a /= isRegularFile b ||
|
||||||
isSymbolicLink a /= isSymbolicLink b
|
isSymbolicLink a /= isSymbolicLink b
|
||||||
|
|
||||||
start :: SeekInput -> RawFilePath -> AddUnlockedMatcher -> CommandStart
|
start :: DryRun -> SeekInput -> RawFilePath -> AddUnlockedMatcher -> CommandStart
|
||||||
start si file addunlockedmatcher =
|
start dr si file addunlockedmatcher =
|
||||||
liftIO (catchMaybeIO $ R.getSymbolicLinkStatus file) >>= \case
|
liftIO (catchMaybeIO $ R.getSymbolicLinkStatus file) >>= \case
|
||||||
Nothing -> stop
|
Nothing -> stop
|
||||||
Just s
|
Just s
|
||||||
|
@ -200,6 +203,7 @@ start si file addunlockedmatcher =
|
||||||
where
|
where
|
||||||
go s = ifAnnexed file (addpresent s) (add s)
|
go s = ifAnnexed file (addpresent s) (add s)
|
||||||
add s = starting "add" (ActionItemTreeFile file) si $
|
add s = starting "add" (ActionItemTreeFile file) si $
|
||||||
|
skipWhenDryRun dr $
|
||||||
if isSymbolicLink s
|
if isSymbolicLink s
|
||||||
then next $ addFile Small file s
|
then next $ addFile Small file s
|
||||||
else perform file addunlockedmatcher
|
else perform file addunlockedmatcher
|
||||||
|
@ -209,7 +213,7 @@ start si file addunlockedmatcher =
|
||||||
fixuplink key =
|
fixuplink key =
|
||||||
starting "add" (ActionItemTreeFile file) si $
|
starting "add" (ActionItemTreeFile file) si $
|
||||||
addingExistingLink file key $
|
addingExistingLink file key $
|
||||||
withOtherTmp $ \tmp -> do
|
skipWhenDryRun dr $ withOtherTmp $ \tmp -> do
|
||||||
let tmpf = tmp P.</> P.takeFileName file
|
let tmpf = tmp P.</> P.takeFileName file
|
||||||
liftIO $ moveFile file tmpf
|
liftIO $ moveFile file tmpf
|
||||||
ifM (isSymbolicLink <$> liftIO (R.getSymbolicLinkStatus tmpf))
|
ifM (isSymbolicLink <$> liftIO (R.getSymbolicLinkStatus tmpf))
|
||||||
|
@ -223,7 +227,8 @@ start si file addunlockedmatcher =
|
||||||
)
|
)
|
||||||
fixuppointer s key =
|
fixuppointer s key =
|
||||||
starting "add" (ActionItemTreeFile file) si $
|
starting "add" (ActionItemTreeFile file) si $
|
||||||
addingExistingLink file key $ do
|
addingExistingLink file key $
|
||||||
|
skipWhenDryRun dr $ do
|
||||||
Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file)
|
Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file)
|
||||||
next $ addFile Large file s
|
next $ addFile Large file s
|
||||||
|
|
||||||
|
|
|
@ -476,7 +476,7 @@ addWorkTree _ addunlockedmatcher u url file key mtmp = case mtmp of
|
||||||
(fromRawFilePath file)
|
(fromRawFilePath file)
|
||||||
(fromRawFilePath tmp)
|
(fromRawFilePath tmp)
|
||||||
go
|
go
|
||||||
else void $ Command.Add.addSmall file s
|
else void $ Command.Add.addSmall (DryRun False) file s
|
||||||
where
|
where
|
||||||
go = do
|
go = do
|
||||||
maybeShowJSON $ JSONChunk [("key", serializeKey key)]
|
maybeShowJSON $ JSONChunk [("key", serializeKey key)]
|
||||||
|
|
|
@ -248,7 +248,7 @@ startLocal o addunlockedmatcher largematcher mode (srcfile, destfile) =
|
||||||
>>= maybe
|
>>= maybe
|
||||||
stop
|
stop
|
||||||
(\addedk -> next $ Command.Add.cleanup addedk True)
|
(\addedk -> next $ Command.Add.cleanup addedk True)
|
||||||
, next $ Command.Add.addSmall destfile s
|
, Command.Add.addSmall (DryRun False) destfile s
|
||||||
)
|
)
|
||||||
notoverwriting why = do
|
notoverwriting why = do
|
||||||
warning $ "not overwriting existing " ++ fromRawFilePath destfile ++ " " ++ why
|
warning $ "not overwriting existing " ++ fromRawFilePath destfile ++ " " ++ why
|
||||||
|
|
|
@ -133,3 +133,6 @@ descSection SectionUtility = "Utility commands"
|
||||||
descSection SectionPlumbing = "Plumbing commands"
|
descSection SectionPlumbing = "Plumbing commands"
|
||||||
descSection SectionTesting = "Testing commands"
|
descSection SectionTesting = "Testing commands"
|
||||||
descSection SectionAddOn = "Addon commands"
|
descSection SectionAddOn = "Addon commands"
|
||||||
|
|
||||||
|
newtype DryRun = DryRun Bool
|
||||||
|
deriving (Show)
|
||||||
|
|
|
@ -77,6 +77,10 @@ annexed content, and other symlinks.
|
||||||
Like `git add --update`, this does not add new files, but any updates
|
Like `git add --update`, this does not add new files, but any updates
|
||||||
to tracked files will be added to the index.
|
to tracked files will be added to the index.
|
||||||
|
|
||||||
|
* `--dry-run`
|
||||||
|
|
||||||
|
Output what would be done for each file, but avoid making any changes.
|
||||||
|
|
||||||
* `--json`
|
* `--json`
|
||||||
|
|
||||||
Enable JSON output. This is intended to be parsed by programs that use
|
Enable JSON output. This is intended to be parsed by programs that use
|
||||||
|
|
|
@ -22,3 +22,4 @@ well -- unless there was a version staged already you don't want to loose etc.
|
||||||
[[!meta author=yoh]]
|
[[!meta author=yoh]]
|
||||||
[[!tag projects/datalad]]
|
[[!tag projects/datalad]]
|
||||||
|
|
||||||
|
> [[done]] joey
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
[[!comment format=mdwn
|
||||||
|
username="joey"
|
||||||
|
subject="""comment 2"""
|
||||||
|
date="2022-08-03T14:53:35Z"
|
||||||
|
content="""
|
||||||
|
Implemented `git-annex add --dry-run`.
|
||||||
|
|
||||||
|
As noted it does not let you tell if a file would be added locked or unlocked
|
||||||
|
since `git-annex add` output is the same either way.
|
||||||
|
|
||||||
|
Also when JSON output is enabled, `git-annex add` usually outputs the key,
|
||||||
|
but with `--dry-run`, it does not. Generating the key would involve locking
|
||||||
|
down the file, and by that point the command is making changes to the
|
||||||
|
filesystem. Use `git-annex calckey` instead.
|
||||||
|
|
||||||
|
Implementation was not as simple as making CommandPerform a no-op. Some parts
|
||||||
|
of CommandPerform actions needed to be run when doing a dry-run, in order for
|
||||||
|
addingExistingLink to display its warning, and for showNote to display the
|
||||||
|
very information that the user is interested in seeing from --dry-run.
|
||||||
|
|
||||||
|
A cleaner implementation would probably involve moving those actions out of
|
||||||
|
CommandPerform, perhaps by splitting CommandPerform into two parts.
|
||||||
|
Which would be a lot of work and still failure prone. That is why I don't
|
||||||
|
think it's a good idea to add --dry-run to very many commands.
|
||||||
|
"""]]
|
Loading…
Add table
Reference in a new issue