packages feed

git-annex 10.20250416 → 10.20250520

raw patch · 12 files changed

+122/−63 lines, 12 files

Files

Annex.hs view
@@ -197,6 +197,7 @@ 	, checkignorehandle :: Maybe (ResourcePool CheckIgnoreHandle) 	, globalnumcopies :: Maybe (Maybe NumCopies) 	, globalmincopies :: Maybe (Maybe MinCopies)+	, nummincopiesattrcache :: Maybe (OsPath, (Maybe NumCopies, Maybe MinCopies)) 	, limit :: ExpandableMatcher Annex 	, timelimit :: Maybe (Duration, POSIXTime) 	, sizelimit :: Maybe (TVar Integer)@@ -253,6 +254,7 @@ 		, checkignorehandle = Nothing 		, globalnumcopies = Nothing 		, globalmincopies = Nothing+		, nummincopiesattrcache = Nothing 		, limit = BuildingMatcher [] 		, timelimit = Nothing 		, sizelimit = Nothing
Annex/NumCopies.hs view
@@ -1,6 +1,6 @@ {- git-annex numcopies configuration and checking  -- - Copyright 2014-2024 Joey Hess <id@joeyh.name>+ - Copyright 2014-2025 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -181,12 +181,18 @@ 	]  getNumMinCopiesAttr :: OsPath  -> Annex (Maybe NumCopies, Maybe MinCopies)-getNumMinCopiesAttr file =-	checkAttrs ["annex.numcopies", "annex.mincopies"] file >>= \case-		(n:m:[]) -> return-			( configuredNumCopies <$> readish n-			, configuredMinCopies <$> readish m-			)+getNumMinCopiesAttr file = Annex.getState Annex.nummincopiesattrcache >>= \case+	Just (cfile, v) | cfile == file -> return v+	_ -> checkAttrs ["annex.numcopies", "annex.mincopies"] file >>= \case+		(n:m:[]) -> do+			let v =+				( configuredNumCopies <$> readish n+				, configuredMinCopies <$> readish m+				)+			Annex.changeState $ \s -> s +				{ Annex.nummincopiesattrcache = Just (file, v)+				}+			return v 		_ -> error "internal"  {- Checks if numcopies are satisfied for a file by running a comparison
CHANGELOG view
@@ -1,3 +1,19 @@+git-annex (10.20250520) upstream; urgency=medium++  * Preferred content now supports "balanced=groupname:lackingcopies"+    to make files be evenly balanced amoung as many repositories as are+    needed to satisfy numcopies.+  * map: Fix buggy handling of remotes that are bare git repositories+    accessed via ssh.+  * map: Avoid looping forever with mutually recursive paths between+    repositories accessed via ssh.+  * whereused: Fix bug that could find matches from grafts +    in remote git-annex branches.+  * Windows: Fix bug that can cause git status to show annexed files as+    modified when built with OsPath.++ -- Joey Hess <id@joeyh.name>  Tue, 20 May 2025 10:25:47 -0400+ git-annex (10.20250416) upstream; urgency=medium    * Added the mask special remote.
Command/Map.hs view
@@ -1,6 +1,6 @@ {- git-annex command  -- - Copyright 2010 Joey Hess <id@joeyh.name>+ - Copyright 2010-2025 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -26,9 +26,6 @@ import qualified Remote.Helper.Ssh as Ssh import qualified Utility.Dot as Dot --- a link from the first repository to the second (its remote)-data Link = Link Git.Repo Git.Repo- -- a repo and its remotes type RepoRemotes = (Git.Repo, [Git.Repo]) @@ -68,7 +65,7 @@ 	return True runViewer file ((c, ps):rest) = ifM (liftIO $ inSearchPath c) 	( do-		showLongNote $ UnquotedString $ "running: " ++ c ++ unwords (toCommand ps)+		showLongNote $ UnquotedString $ "running: " ++ c ++ " " ++ unwords (toCommand ps) 		showOutput 		liftIO $ boolSystem c ps 	, runViewer file rest@@ -157,7 +154,7 @@ 	Just DeadTrusted -> Dot.fillColor "grey" s 	Nothing -> Dot.fillColor "white" s -{- Recursively searches out remotes starting with the specified repo. -}+{- Recursively searches out remotes starting with the specified local repo. -} spider :: Git.Repo -> Annex [RepoRemotes] spider r = spider' [r] [] spider' :: [Git.Repo] -> [RepoRemotes] -> Annex [RepoRemotes]@@ -169,15 +166,18 @@  		-- The remotes will be relative to r', and need to be 		-- made absolute for later use.-		remotes <- mapM (absRepo r')-			=<< (liftIO $ Git.Construct.fromRemotes r')-	+		remotes <- mapM (absRepo r') =<<+			if Git.repoIsUrl r+				then liftIO $ Git.Construct.fromRemoteUrlRemotes r'+				else liftIO $ Git.Construct.fromRemotes r'+ 		spider' (rs ++ remotes) ((r', remotes):known)  {- Converts repos to a common absolute form. -} absRepo :: Git.Repo -> Git.Repo -> Annex Git.Repo absRepo reference r-	| Git.repoIsUrl reference = return $ Git.Construct.localToUrl reference r+	| Git.repoIsUrl reference = return $+		Git.Construct.localToUrl reference r 	| Git.repoIsUrl r = return r 	| otherwise = liftIO $ do 		r' <- Git.Construct.fromPath =<< absPath (Git.repoPath r)
Command/Smudge.hs view
@@ -112,7 +112,6 @@ 		discardreststdin 		emitpointer 	stop-  where  -- Handles everything except the IO of the file content. clean'@@ -135,7 +134,6 @@ 		, inSmudgeCleanFilter go 		)   where- 	go = case mk of 		Right (Just k) -> do 			addingExistingLink file k $ do
Command/WhereUsed.hs view
@@ -89,7 +89,7 @@ 		[ Param ("--exclude=*/" ++ fromRef (Annex.Branch.name)) 		, Param "--glob=*" 		-- Also search remote branches-		, Param ("--exclude=" ++ fromRef (Annex.Branch.name))+		, Param ("--exclude=*/" ++ fromRef (Annex.Branch.name)) 		, Param "--remotes=*" 		-- And search tags. 		, Param "--tags=*"
Git.hs view
@@ -89,8 +89,6 @@ localGitDir Repo { location = Local { gitdir = d } } = d localGitDir _ = giveup "unknown localGitDir" -{- Some code needs to vary between URL and normal repos,- - or bare and non-bare, these functions help with that. -} repoIsUrl :: Repo -> Bool repoIsUrl Repo { location = Url _ } = True repoIsUrl Repo { location = UnparseableUrl _ } = True
Git/Construct.hs view
@@ -1,6 +1,6 @@ {- Construction of Git Repo objects  -- - Copyright 2010-2023 Joey Hess <id@joeyh.name>+ - Copyright 2010-2025 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -18,6 +18,7 @@ 	remoteNamed, 	remoteNamedFromKey, 	fromRemotes,+	fromRemoteUrlRemotes, 	fromRemoteLocation, 	repoAbsPath, 	checkForRepo,@@ -97,14 +98,15 @@  - or is invalid, because git can also function despite remotes having  - such urls, only failing if such a remote is used.  -}-fromUrl :: String -> IO Repo-fromUrl url-	| not (isURI url) = fromUrl' $ escapeURIString isUnescapedInURI url-	| otherwise = fromUrl' url+fromUrl :: Bool -> String -> IO Repo+fromUrl fileurlislocal url+	| not (isURI url) = fromUrl' fileurlislocal $+		escapeURIString isUnescapedInURI url+	| otherwise = fromUrl' fileurlislocal url -fromUrl' :: String -> IO Repo-fromUrl' url-	| "file://" `isPrefixOf` url = case parseURIPortable url of+fromUrl' :: Bool -> String -> IO Repo+fromUrl' fileurlislocal url+	| "file://" `isPrefixOf` url && fileurlislocal = case parseURIPortable url of 		Just u -> fromAbsPath $ toOsPath $ unEscapeString $ uriPath u 		Nothing -> pure $ newFrom $ UnparseableUrl url 	| otherwise = case parseURIPortable url of@@ -123,25 +125,42 @@ 	| repoIsUrl r = r 	| otherwise = case (Url.authority reference, Url.scheme reference) of 		(Just auth, Just s) -> -			let absurl = concat+			let referencepath = fromMaybe "" $ Url.path reference+			    absurl = concat 				[ s 				, "//" 				, auth-				, fromOsPath (repoPath r)+				, fromOsPath $ simplifyPath $+					toOsPath referencepath </> repoPath r 				] 			in r { location = Url $ fromJust $ parseURIPortable absurl } 		_ -> r  {- Calculates a list of a repo's configured remotes, by parsing its config. -} fromRemotes :: Repo -> IO [Repo]-fromRemotes repo = catMaybes <$> mapM construct remotepairs+fromRemotes = fromRemotes' fromRemoteLocation++fromRemotes' :: (String -> Bool -> Repo -> IO Repo) -> Repo -> IO [Repo]+fromRemotes' fromremotelocation repo = catMaybes <$> mapM construct remotepairs   where 	filterconfig f = filter f $ M.toList $ config repo 	filterkeys f = filterconfig (\(k,_) -> f k) 	remotepairs = filterkeys isRemoteUrlKey 	construct (k,v) = remoteNamedFromKey k $-		fromRemoteLocation (fromConfigValue v) False repo+		fromremotelocation (fromConfigValue v) False repo +{- Calculates a list of a remote repo's configured remotes, by parsing its+ - config. Unlike fromRemotes, this does not do any local path checking. + - The remote repo must have an url path. -}+fromRemoteUrlRemotes :: Repo -> IO [Repo]+fromRemoteUrlRemotes = fromRemotes' go+  where+	go s knownurl repo = +		case parseRemoteLocation s knownurl repo of+			RemotePath p -> pure $ localToUrl repo $ +				newFrom $ LocalUnknown $ toOsPath p+			RemoteUrl u -> fromUrl False u+ {- Sets the name of a remote when constructing the Repo to represent it. -} remoteNamed :: String -> IO Repo -> IO Repo remoteNamed n constructor = do@@ -167,7 +186,7 @@ fromRemoteLocation s knownurl repo = gen $ parseRemoteLocation s knownurl repo   where 	gen (RemotePath p) = fromRemotePath p repo-	gen (RemoteUrl u) = fromUrl u+	gen (RemoteUrl u) = fromUrl True u  {- Constructs a Repo from the path specified in the git remotes of  - another Repo. -}
Limit.hs view
@@ -1,6 +1,6 @@ {- user-specified limits on files to act on  -- - 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.  -}@@ -459,19 +459,26 @@ 		} 	Nothing -> Left "bad value for number of lacking copies"   where-	go mi needed notpresent key = do-		numcopies <- if approx-			then approxNumCopies-			else case mi of-				MatchingFile fi -> getGlobalFileNumCopies $-					matchFile fi-				MatchingInfo {} -> approxNumCopies-				MatchingUserInfo {} -> approxNumCopies-		us <- filter (`S.notMember` notpresent)-			<$> (trustExclude UnTrusted =<< Remote.keyLocations key)-		let vs nhave numcopies' = numcopies' - nhave >= needed-		return $ numCopiesCheck'' us vs numcopies+	go mi needed notpresent key =+		limitCheckNumCopies approx mi notpresent key vs+	  where+		vs nhave numcopies' = numcopies' - nhave >= needed++limitCheckNumCopies :: Bool -> MatchInfo -> AssumeNotPresent -> Key -> (Int -> Int -> v) -> Annex v+limitCheckNumCopies approx mi notpresent key vs = do+	numcopies <- if approx+		then approxNumCopies+		else case mi of+			MatchingFile fi -> getGlobalFileNumCopies $+				matchFile fi+			MatchingInfo {} -> approxNumCopies+			MatchingUserInfo {} -> approxNumCopies+	us <- filter (`S.notMember` notpresent)+		<$> (trustExclude UnTrusted =<< Remote.keyLocations key)+	return $ numCopiesCheck'' us vs numcopies+  where 	approxNumCopies = fromMaybe defaultNumCopies <$> getGlobalNumCopies+	  {- Match keys that are unused.  - @@ -597,17 +604,21 @@  limitBalanced' :: String -> MatchFiles Annex -> Maybe UUID -> MkLimit Annex limitBalanced' termname fullybalanced mu groupname = do-	copies <- limitCopies $ if ':' `elem` groupname-		then groupname-		else groupname ++ ":1"+	let checknumcopies = ":lackingcopies" `isSuffixOf` groupname+	enoughcopies <- if checknumcopies+		then limitLackingCopies termname False "1"+		else limitCopies $ if ':' `elem` groupname+			then groupname+			else groupname ++ ":1"+	let checkenoughcopies = if checknumcopies then id else not 	let present = limitPresent mu-	let combo f = f present || f fullybalanced || f copies+	let combo f = f present || f fullybalanced || f enoughcopies 	Right $ MatchFiles 		{ matchAction = \lu a i -> 			ifM (Annex.getRead Annex.rebalance) 				( matchAction fullybalanced lu a i 				, matchAction present lu a i <||>-					((not <$> matchAction copies lu a i)+					((checkenoughcopies <$> matchAction enoughcopies lu a i) 						<&&> matchAction fullybalanced lu a i 					) 				)@@ -667,11 +678,16 @@ 	-> MkLimit Annex limitFullyBalanced'' filtercandidates termname mu getgroupmap want = 	case splitc ':' want of-		[g] -> go g 1-		[g, n] -> maybe-			(Left $ "bad number for " ++ termname)-			(go g)-			(readish n)+		[g] -> go g (Right 1)+		[g, n]+			| n == "lackingcopies" -> go g $ +				Left $ \mi notpresent key -> +					let vs nhave numcopies = numcopies - nhave+					in limitCheckNumCopies False mi notpresent key vs+			| otherwise -> maybe+				(Left $ "bad number for " ++ termname)+				(go g . Right)+				(readish n) 		_ -> Left $ "bad value for " ++ termname   where 	go s n = limitFullyBalanced''' filtercandidates termname mu@@ -683,13 +699,16 @@ 	-> Maybe UUID 	-> Annex GroupMap 	-> Group-	-> Int+	-> Either (MatchInfo -> AssumeNotPresent -> Key -> Annex Int) Int 	-> MkLimit Annex-limitFullyBalanced''' filtercandidates termname mu getgroupmap g n want = Right $ MatchFiles-	{ matchAction = \lu -> const $ checkKey $ \key -> do+limitFullyBalanced''' filtercandidates termname mu getgroupmap g getn want = Right $ MatchFiles+	{ matchAction = \lu notpresent mi -> flip checkKey mi $ \key -> do 		gm <- getgroupmap 		let groupmembers = fromMaybe S.empty $ 			M.lookup g (uuidsByGroup gm)+		n <- case getn of+			Right n -> pure n+			Left a -> a mi notpresent key 		candidates <- filtercandidates n key groupmembers 		let wanted = if S.null candidates 			then False
Logs/File.hs view
@@ -145,6 +145,7 @@ 	cleanup (Just h) = liftIO $ hClose h 	go Nothing = finalizer 	go (Just h) = do+		liftIO $ fileEncoding h 		mapM_ processor =<< liftIO (lines <$> hGetContents h) 		liftIO $ hClose h 		finalizer
Remote/Bup.hs view
@@ -304,7 +304,7 @@ 		if "/" `isPrefixOf` r 			then Git.Construct.fromPath (toOsPath r) 			else giveup "please specify an absolute path"-	| otherwise = Git.Construct.fromUrl $ "ssh://" ++ host ++ slash dir+	| otherwise = Git.Construct.fromUrl False $ "ssh://" ++ host ++ slash dir   where 	bits = splitc ':' r 	host = fromMaybe "" $ headMaybe bits
git-annex.cabal view
@@ -1,5 +1,5 @@ Name: git-annex-Version: 10.20250416+Version: 10.20250520 Cabal-Version: 1.12 License: AGPL-3 Maintainer: Joey Hess <id@joeyh.name>