annex.addunlocked support for tree imports
Honor annex.addunlocked configuration when importing a tree from a special remote. Note, in a --no-content import, the object file will not be populated (usually) and so expressions that match on mime type will not match. Tested this and it works ok, the file just ends up locked. Updated docs for the mime expressions to mention that they can't match when the file is present Note that in Command.Sync.pullThirdPartyPopulated, recordImportTree is called without a AddUnlockedMatcher. Since the tree generated here is not exposed to the user and does not contain usual filenames, there is no need of the overhead of checking it.
This commit is contained in:
parent
02169a1ce3
commit
29b3c7c660
9 changed files with 93 additions and 30 deletions
|
@ -107,9 +107,10 @@ buildImportCommit
|
||||||
:: Remote
|
:: Remote
|
||||||
-> ImportTreeConfig
|
-> ImportTreeConfig
|
||||||
-> ImportCommitConfig
|
-> ImportCommitConfig
|
||||||
|
-> AddUnlockedMatcher
|
||||||
-> Imported
|
-> Imported
|
||||||
-> Annex (Maybe Ref)
|
-> Annex (Maybe Ref)
|
||||||
buildImportCommit remote importtreeconfig importcommitconfig imported =
|
buildImportCommit remote importtreeconfig importcommitconfig addunlockedmatcher imported =
|
||||||
case importCommitTracking importcommitconfig of
|
case importCommitTracking importcommitconfig of
|
||||||
Nothing -> go Nothing
|
Nothing -> go Nothing
|
||||||
Just trackingcommit -> inRepo (Git.Ref.tree trackingcommit) >>= \case
|
Just trackingcommit -> inRepo (Git.Ref.tree trackingcommit) >>= \case
|
||||||
|
@ -117,7 +118,7 @@ buildImportCommit remote importtreeconfig importcommitconfig imported =
|
||||||
Just _ -> go (Just trackingcommit)
|
Just _ -> go (Just trackingcommit)
|
||||||
where
|
where
|
||||||
go trackingcommit = do
|
go trackingcommit = do
|
||||||
(importedtree, updatestate) <- recordImportTree remote importtreeconfig imported
|
(importedtree, updatestate) <- recordImportTree remote importtreeconfig (Just addunlockedmatcher) imported
|
||||||
buildImportCommit' remote importcommitconfig trackingcommit importedtree >>= \case
|
buildImportCommit' remote importcommitconfig trackingcommit importedtree >>= \case
|
||||||
Just finalcommit -> do
|
Just finalcommit -> do
|
||||||
updatestate
|
updatestate
|
||||||
|
@ -132,10 +133,11 @@ buildImportCommit remote importtreeconfig importcommitconfig imported =
|
||||||
recordImportTree
|
recordImportTree
|
||||||
:: Remote
|
:: Remote
|
||||||
-> ImportTreeConfig
|
-> ImportTreeConfig
|
||||||
|
-> Maybe AddUnlockedMatcher
|
||||||
-> Imported
|
-> Imported
|
||||||
-> Annex (History Sha, Annex ())
|
-> Annex (History Sha, Annex ())
|
||||||
recordImportTree remote importtreeconfig imported = do
|
recordImportTree remote importtreeconfig addunlockedmatcher imported = do
|
||||||
importedtree@(History finaltree _) <- buildImportTrees basetree subdir imported
|
importedtree@(History finaltree _) <- buildImportTrees basetree subdir addunlockedmatcher imported
|
||||||
return (importedtree, updatestate finaltree)
|
return (importedtree, updatestate finaltree)
|
||||||
where
|
where
|
||||||
basetree = case importtreeconfig of
|
basetree = case importtreeconfig of
|
||||||
|
@ -177,7 +179,7 @@ recordImportTree remote importtreeconfig imported = do
|
||||||
}
|
}
|
||||||
return oldexport
|
return oldexport
|
||||||
|
|
||||||
-- downloadImport takes care of updating the location log
|
-- importKeys takes care of updating the location log
|
||||||
-- for the local repo when keys are downloaded, and also updates
|
-- for the local repo when keys are downloaded, and also updates
|
||||||
-- the location log for the remote for keys that are present in it.
|
-- the location log for the remote for keys that are present in it.
|
||||||
-- That leaves updating the location log for the remote for keys
|
-- That leaves updating the location log for the remote for keys
|
||||||
|
@ -283,11 +285,12 @@ buildImportCommit' remote importcommitconfig mtrackingcommit imported@(History t
|
||||||
buildImportTrees
|
buildImportTrees
|
||||||
:: Ref
|
:: Ref
|
||||||
-> Maybe TopFilePath
|
-> Maybe TopFilePath
|
||||||
|
-> Maybe AddUnlockedMatcher
|
||||||
-> Imported
|
-> Imported
|
||||||
-> Annex (History Sha)
|
-> Annex (History Sha)
|
||||||
buildImportTrees basetree msubdir (ImportedFull imported) =
|
buildImportTrees basetree msubdir addunlockedmatcher (ImportedFull imported) =
|
||||||
buildImportTreesGeneric convertImportTree basetree msubdir imported
|
buildImportTreesGeneric (convertImportTree addunlockedmatcher) basetree msubdir imported
|
||||||
buildImportTrees basetree msubdir (ImportedDiff (LastImportedTree oldtree) imported) = do
|
buildImportTrees basetree msubdir addunlockedmatcher (ImportedDiff (LastImportedTree oldtree) imported) = do
|
||||||
importtree <- if null (importableContents imported)
|
importtree <- if null (importableContents imported)
|
||||||
then pure oldtree
|
then pure oldtree
|
||||||
else applydiff
|
else applydiff
|
||||||
|
@ -312,7 +315,7 @@ buildImportTrees basetree msubdir (ImportedDiff (LastImportedTree oldtree) impor
|
||||||
oldtree
|
oldtree
|
||||||
|
|
||||||
mktreeitem (loc, DiffChanged v) =
|
mktreeitem (loc, DiffChanged v) =
|
||||||
Just <$> mkImportTreeItem msubdir loc v
|
Just <$> mkImportTreeItem addunlockedmatcher msubdir loc v
|
||||||
mktreeitem (_, DiffRemoved) =
|
mktreeitem (_, DiffRemoved) =
|
||||||
pure Nothing
|
pure Nothing
|
||||||
|
|
||||||
|
@ -320,17 +323,26 @@ buildImportTrees basetree msubdir (ImportedDiff (LastImportedTree oldtree) impor
|
||||||
|
|
||||||
isremoved (_, v) = v == DiffRemoved
|
isremoved (_, v) = v == DiffRemoved
|
||||||
|
|
||||||
convertImportTree :: Maybe TopFilePath -> [(ImportLocation, Either Sha Key)] -> Annex Tree
|
convertImportTree :: Maybe AddUnlockedMatcher -> Maybe TopFilePath -> [(ImportLocation, Either Sha Key)] -> Annex Tree
|
||||||
convertImportTree msubdir ls =
|
convertImportTree maddunlockedmatcher msubdir ls =
|
||||||
treeItemsToTree <$> mapM (uncurry $ mkImportTreeItem msubdir) ls
|
treeItemsToTree <$> mapM (uncurry $ mkImportTreeItem maddunlockedmatcher msubdir) ls
|
||||||
|
|
||||||
mkImportTreeItem :: Maybe TopFilePath -> ImportLocation -> Either Sha Key -> Annex TreeItem
|
mkImportTreeItem :: Maybe AddUnlockedMatcher -> Maybe TopFilePath -> ImportLocation -> Either Sha Key -> Annex TreeItem
|
||||||
mkImportTreeItem msubdir loc v = case v of
|
mkImportTreeItem maddunlockedmatcher msubdir loc v = case v of
|
||||||
Right k -> do
|
Right k -> case maddunlockedmatcher of
|
||||||
relf <- fromRepo $ fromTopFilePath topf
|
Nothing -> mklink k
|
||||||
symlink <- calcRepo $ gitAnnexLink relf k
|
Just addunlockedmatcher -> do
|
||||||
linksha <- hashSymlink symlink
|
objfile <- calcRepo (gitAnnexLocation k)
|
||||||
return $ TreeItem treepath (fromTreeItemType TreeSymlink) linksha
|
let mi = MatchingFile FileInfo
|
||||||
|
{ contentFile = objfile
|
||||||
|
, matchFile = getTopFilePath topf
|
||||||
|
, matchKey = Just k
|
||||||
|
}
|
||||||
|
ifM (checkAddUnlockedMatcher NoLiveUpdate addunlockedmatcher mi)
|
||||||
|
( mkpointer k
|
||||||
|
, mklink k
|
||||||
|
)
|
||||||
|
|
||||||
Left sha ->
|
Left sha ->
|
||||||
return $ TreeItem treepath (fromTreeItemType TreeFile) sha
|
return $ TreeItem treepath (fromTreeItemType TreeFile) sha
|
||||||
where
|
where
|
||||||
|
@ -338,6 +350,13 @@ mkImportTreeItem msubdir loc v = case v of
|
||||||
treepath = asTopFilePath lf
|
treepath = asTopFilePath lf
|
||||||
topf = asTopFilePath $
|
topf = asTopFilePath $
|
||||||
maybe lf (\sd -> getTopFilePath sd P.</> lf) msubdir
|
maybe lf (\sd -> getTopFilePath sd P.</> lf) msubdir
|
||||||
|
mklink k = do
|
||||||
|
relf <- fromRepo $ fromTopFilePath topf
|
||||||
|
symlink <- calcRepo $ gitAnnexLink relf k
|
||||||
|
linksha <- hashSymlink symlink
|
||||||
|
return $ TreeItem treepath (fromTreeItemType TreeSymlink) linksha
|
||||||
|
mkpointer k = TreeItem treepath (fromTreeItemType TreeFile)
|
||||||
|
<$> hashPointerFile k
|
||||||
|
|
||||||
{- Builds a history of git trees using ContentIdentifiers.
|
{- Builds a history of git trees using ContentIdentifiers.
|
||||||
-
|
-
|
||||||
|
@ -604,8 +623,8 @@ getLastImportedTree remote = do
|
||||||
- generates Keys without downloading.
|
- generates Keys without downloading.
|
||||||
-
|
-
|
||||||
- Generates either a Key or a git Sha, depending on annex.largefiles.
|
- Generates either a Key or a git Sha, depending on annex.largefiles.
|
||||||
- But when importcontent is False, it cannot match on annex.largefiles
|
- But when importcontent is False, it cannot generate a git Sha,
|
||||||
- (or generate a git Sha), so always generates Keys.
|
- so always generates Keys.
|
||||||
-
|
-
|
||||||
- Supports concurrency when enabled.
|
- Supports concurrency when enabled.
|
||||||
-
|
-
|
||||||
|
|
|
@ -11,6 +11,8 @@ git-annex (10.20241203) UNRELEASED; urgency=medium
|
||||||
default unset behavior.
|
default unset behavior.
|
||||||
* sync: Avoid misleading warning about future preferred content
|
* sync: Avoid misleading warning about future preferred content
|
||||||
transition when preferred content is set to "".
|
transition when preferred content is set to "".
|
||||||
|
* Honor annex.addunlocked configuration when importing a tree from a
|
||||||
|
special remote.
|
||||||
|
|
||||||
-- Joey Hess <id@joeyh.name> Mon, 02 Dec 2024 13:41:31 -0400
|
-- Joey Hess <id@joeyh.name> Mon, 02 Dec 2024 13:41:31 -0400
|
||||||
|
|
||||||
|
|
|
@ -147,8 +147,10 @@ seek o@(RemoteImportOptions {}) = startConcurrency commandStages $ do
|
||||||
(pure Nothing)
|
(pure Nothing)
|
||||||
(Just <$$> inRepo . toTopFilePath . toRawFilePath)
|
(Just <$$> inRepo . toTopFilePath . toRawFilePath)
|
||||||
(importToSubDir o)
|
(importToSubDir o)
|
||||||
|
addunlockedmatcher <- addUnlockedMatcher
|
||||||
seekRemote r (importToBranch o) subdir (importContent o)
|
seekRemote r (importToBranch o) subdir (importContent o)
|
||||||
(checkGitIgnoreOption o)
|
(checkGitIgnoreOption o)
|
||||||
|
addunlockedmatcher
|
||||||
(messageOption o)
|
(messageOption o)
|
||||||
|
|
||||||
startLocal :: ImportOptions -> AddUnlockedMatcher -> GetFileMatcher -> DuplicateMode -> (RawFilePath, RawFilePath) -> CommandStart
|
startLocal :: ImportOptions -> AddUnlockedMatcher -> GetFileMatcher -> DuplicateMode -> (RawFilePath, RawFilePath) -> CommandStart
|
||||||
|
@ -322,8 +324,8 @@ verifyExisting key destfile (yes, no) = do
|
||||||
verifyEnoughCopiesToDrop [] key Nothing Nothing needcopies mincopies [] preverified tocheck
|
verifyEnoughCopiesToDrop [] key Nothing Nothing needcopies mincopies [] preverified tocheck
|
||||||
(const yes) no
|
(const yes) no
|
||||||
|
|
||||||
seekRemote :: Remote -> Branch -> Maybe TopFilePath -> Bool -> CheckGitIgnore -> [String] -> CommandSeek
|
seekRemote :: Remote -> Branch -> Maybe TopFilePath -> Bool -> CheckGitIgnore -> AddUnlockedMatcher -> [String] -> CommandSeek
|
||||||
seekRemote remote branch msubdir importcontent ci importmessages = do
|
seekRemote remote branch msubdir importcontent ci addunlockedmatcher importmessages = do
|
||||||
importtreeconfig <- case msubdir of
|
importtreeconfig <- case msubdir of
|
||||||
Nothing -> return ImportTree
|
Nothing -> return ImportTree
|
||||||
Just subdir ->
|
Just subdir ->
|
||||||
|
@ -337,7 +339,7 @@ seekRemote remote branch msubdir importcontent ci importmessages = do
|
||||||
trackingcommit <- fromtrackingbranch Git.Ref.sha
|
trackingcommit <- fromtrackingbranch Git.Ref.sha
|
||||||
cmode <- annexCommitMode <$> Annex.getGitConfig
|
cmode <- annexCommitMode <$> Annex.getGitConfig
|
||||||
let importcommitconfig = ImportCommitConfig trackingcommit cmode importmessages'
|
let importcommitconfig = ImportCommitConfig trackingcommit cmode importmessages'
|
||||||
let commitimport = commitRemote remote branch tb trackingcommit importtreeconfig importcommitconfig
|
let commitimport = commitRemote remote branch tb trackingcommit importtreeconfig importcommitconfig addunlockedmatcher
|
||||||
|
|
||||||
importabletvar <- liftIO $ newTVarIO Nothing
|
importabletvar <- liftIO $ newTVarIO Nothing
|
||||||
void $ includeCommandAction (listContents remote importtreeconfig ci importabletvar)
|
void $ includeCommandAction (listContents remote importtreeconfig ci importabletvar)
|
||||||
|
@ -383,10 +385,10 @@ listContents' remote importtreeconfig ci a =
|
||||||
, err
|
, err
|
||||||
]
|
]
|
||||||
|
|
||||||
commitRemote :: Remote -> Branch -> RemoteTrackingBranch -> Maybe Sha -> ImportTreeConfig -> ImportCommitConfig -> Imported -> CommandStart
|
commitRemote :: Remote -> Branch -> RemoteTrackingBranch -> Maybe Sha -> ImportTreeConfig -> ImportCommitConfig -> AddUnlockedMatcher -> Imported -> CommandStart
|
||||||
commitRemote remote branch tb trackingcommit importtreeconfig importcommitconfig imported =
|
commitRemote remote branch tb trackingcommit importtreeconfig importcommitconfig addunlockedmatcher imported =
|
||||||
starting "update" ai si $ do
|
starting "update" ai si $ do
|
||||||
importcommit <- buildImportCommit remote importtreeconfig importcommitconfig imported
|
importcommit <- buildImportCommit remote importtreeconfig importcommitconfig addunlockedmatcher imported
|
||||||
next $ updateremotetrackingbranch importcommit
|
next $ updateremotetrackingbranch importcommit
|
||||||
where
|
where
|
||||||
ai = ActionItemOther (Just $ UnquotedString $ fromRef $ fromRemoteTrackingBranch tb)
|
ai = ActionItemOther (Just $ UnquotedString $ fromRef $ fromRemoteTrackingBranch tb)
|
||||||
|
|
|
@ -53,6 +53,7 @@ import Annex.Path
|
||||||
import Annex.Wanted
|
import Annex.Wanted
|
||||||
import Annex.Content
|
import Annex.Content
|
||||||
import Annex.WorkTree
|
import Annex.WorkTree
|
||||||
|
import Annex.FileMatcher
|
||||||
import Command.Get (getKey')
|
import Command.Get (getKey')
|
||||||
import qualified Command.Move
|
import qualified Command.Move
|
||||||
import qualified Command.Export
|
import qualified Command.Export
|
||||||
|
@ -77,7 +78,6 @@ import Annex.CurrentBranch
|
||||||
import Annex.Import
|
import Annex.Import
|
||||||
import Annex.CheckIgnore
|
import Annex.CheckIgnore
|
||||||
import Annex.PidLock
|
import Annex.PidLock
|
||||||
import Types.FileMatcher
|
|
||||||
import Types.GitConfig
|
import Types.GitConfig
|
||||||
import Types.Availability
|
import Types.Availability
|
||||||
import qualified Database.Export as Export
|
import qualified Database.Export as Export
|
||||||
|
@ -580,7 +580,8 @@ importRemote importcontent o remote currbranch
|
||||||
let (branch, subdir) = splitRemoteAnnexTrackingBranchSubdir b
|
let (branch, subdir) = splitRemoteAnnexTrackingBranchSubdir b
|
||||||
if canImportKeys remote importcontent
|
if canImportKeys remote importcontent
|
||||||
then do
|
then do
|
||||||
Command.Import.seekRemote remote branch subdir importcontent (CheckGitIgnore True) []
|
addunlockedmatcher <- addUnlockedMatcher
|
||||||
|
Command.Import.seekRemote remote branch subdir importcontent (CheckGitIgnore True) addunlockedmatcher []
|
||||||
-- Importing generates a branch
|
-- Importing generates a branch
|
||||||
-- that is not initially connected
|
-- that is not initially connected
|
||||||
-- to the current branch, so allow
|
-- to the current branch, so allow
|
||||||
|
@ -607,7 +608,7 @@ pullThirdPartyPopulated o remote
|
||||||
where
|
where
|
||||||
go (Just importable) = importChanges remote ImportTree False True importable >>= \case
|
go (Just importable) = importChanges remote ImportTree False True importable >>= \case
|
||||||
ImportFinished imported -> do
|
ImportFinished imported -> do
|
||||||
(_t, updatestate) <- recordImportTree remote ImportTree imported
|
(_t, updatestate) <- recordImportTree remote ImportTree Nothing imported
|
||||||
next $ do
|
next $ do
|
||||||
updatestate
|
updatestate
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -54,3 +54,5 @@ This was to consider using `import` for a folder with DANDI stats. For now I wil
|
||||||
|
|
||||||
[[!meta author=yoh]]
|
[[!meta author=yoh]]
|
||||||
[[!tag projects/dandi]]
|
[[!tag projects/dandi]]
|
||||||
|
|
||||||
|
> [[fixed|done]] --[[Joey]]
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
[[!comment format=mdwn
|
||||||
|
username="joey"
|
||||||
|
subject="""comment 1"""
|
||||||
|
date="2024-12-18T19:24:38Z"
|
||||||
|
content="""
|
||||||
|
Turns out that while `git-annex import` from a directory does support
|
||||||
|
addunlocked, this was forgotten about when implementing the newer special
|
||||||
|
remote tree import.
|
||||||
|
|
||||||
|
I agree that this should be supported.
|
||||||
|
"""]]
|
|
@ -0,0 +1,11 @@
|
||||||
|
[[!comment format=mdwn
|
||||||
|
username="joey"
|
||||||
|
subject="""comment 2"""
|
||||||
|
date="2024-12-19T15:31:59Z"
|
||||||
|
content="""
|
||||||
|
Note that for --no-content imports, it will not be possible for mimetype=
|
||||||
|
and mimeencoding= expressions to match.
|
||||||
|
|
||||||
|
So if addunlocked is set to such an expression, it will not match and will
|
||||||
|
add the file locked. Does not seem like a blocker.
|
||||||
|
"""]]
|
|
@ -0,0 +1,7 @@
|
||||||
|
[[!comment format=mdwn
|
||||||
|
username="joey"
|
||||||
|
subject="""comment 3"""
|
||||||
|
date="2024-12-19T15:34:48Z"
|
||||||
|
content="""
|
||||||
|
Implemented this.
|
||||||
|
"""]]
|
|
@ -48,6 +48,10 @@ The following terms can be used:
|
||||||
|
|
||||||
The MIME types are the same that are displayed by running `file --mime-type`
|
The MIME types are the same that are displayed by running `file --mime-type`
|
||||||
|
|
||||||
|
This only matches when the content of the file is present in the local
|
||||||
|
repository. Usually that is the case, but eg, when importing from a
|
||||||
|
special remote with --no-content, the content is usually not present.
|
||||||
|
|
||||||
This is only available to use when git-annex was built with the
|
This is only available to use when git-annex was built with the
|
||||||
MagicMime build flag.
|
MagicMime build flag.
|
||||||
|
|
||||||
|
@ -60,6 +64,10 @@ The following terms can be used:
|
||||||
|
|
||||||
The MIME encodings are the same that are displayed by running `file --mime-encoding`
|
The MIME encodings are the same that are displayed by running `file --mime-encoding`
|
||||||
|
|
||||||
|
This only matches when the content of the file is present in the local
|
||||||
|
repository. Usually that is the case, but eg, when importing from a
|
||||||
|
special remote with --no-content, the content is usually not present.
|
||||||
|
|
||||||
This is only available to use when git-annex was built with the
|
This is only available to use when git-annex was built with the
|
||||||
MagicMime build flag.
|
MagicMime build flag.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue