whereused --historical

Does not check the reflog, but otherwise works.

It's possible for it to display something that is not an annexed file,
if a non-annexed file somehow ends up containing something that looks
like the key's name. This seems very unlikely to happen, and it would
add a lot of complexity to detect it and somehow skip over that file,
since the git log would need to either be run again, or not limited to 1
result and canceled once enough results have been read.

Also, it kind of seems ok, if a file refers to a key, to consider that
as a place the key was used, for some definition of used. So, I punted
on dealing with that. May revisit later.

Sponsored-by: Brock Spratlen on Patreon
This commit is contained in:
Joey Hess 2021-07-14 15:38:28 -04:00
parent 47d3dccf19
commit fcd1b93a7d
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
2 changed files with 73 additions and 4 deletions

View file

@ -8,10 +8,21 @@
module Command.WhereUsed where
import Command
import Git
import Git.Sha
import Git.FilePath
import qualified Git.Ref
import qualified Git.Command
import qualified Git.DiffTree as DiffTree
import qualified Annex
import qualified Annex.Branch
import Annex.CatFile
import Database.Keys
import Data.Char
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
cmd :: Command
cmd = noCommit $ withGlobalOptions [annexedMatchingOptions] $
command "whereused" SectionQuery
@ -60,9 +71,62 @@ start o (_, key, _) = startingCustomOutput key $ do
Just k | k == key -> return True
_ -> return False
display :: Key -> FilePath -> IO ()
display key f = putStrLn (serializeKey key ++ " " ++ f)
display :: Key -> String -> IO ()
display key loc = putStrLn (serializeKey key ++ " " ++ loc)
findHistorical :: Key -> Annex ()
findHistorical key = do
error "TODO"
Annex.inRepo $ \repo -> do
-- Find most recent change to the key, in all branches and
-- tags, except the git-annex branch.
(output, cleanup) <- Git.Command.pipeNullSplit
[ Param "log"
, Param "-z"
-- Don't convert pointer files.
, Param "--no-textconv"
-- Only find the most recent commit, for speed.
, Param "-n1"
-- Find commits that contain the key.
, Param ("-S" ++ fromRawFilePath (keyFile key))
-- Skip commits where the file was deleted,
-- only find those where it was added or modified.
, Param "--diff-filter=ACMRTUX"
-- Search all local branches, except git-annex branch.
, Param ("--exclude=*/" ++ fromRef (Annex.Branch.name))
, Param "--glob=*"
-- Also search remote branches
, Param ("--exclude=" ++ fromRef (Annex.Branch.name))
, Param "--remotes=*"
-- And search tags.
, Param "--tags=*"
-- Output the commit hash
, Param "--pretty=%H"
-- And the raw diff.
, Param "--raw"
-- Don't abbreviate hashes.
, Param "--no-abbrev"
] repo
found <- case output of
(h:rest) -> do
commitsha <- getSha "log" (pure (L.toStrict h))
let diff = DiffTree.parseDiffRaw rest
forM_ (map (flip fromTopFilePath repo . DiffTree.file) diff) $ \f -> do
commitdesc <- S.takeWhile (/= fromIntegral (ord '\n'))
<$> Git.Command.pipeReadStrict
[ Param "describe"
, Param "--contains"
, Param "--all"
, Param (fromRef commitsha)
] repo
if S.null commitdesc
then return False
else do
rf <- relPathCwdToFile f
let fref = Git.Ref.branchFileRef (Ref commitdesc) rf
display key (fromRef fref)
return True
_ -> return False
void cleanup
unless found $ do
error "todo reflog"

View file

@ -15,6 +15,7 @@ module Git.DiffTree (
diffFiles,
diffLog,
commitDiff,
parseDiffRaw,
) where
import qualified Data.ByteString as B
@ -116,9 +117,13 @@ parseDiffRaw l = go l
go (s:[]) = error $ "diff-tree parse error near \"" ++ decodeBL' s ++ "\""
-- :<srcmode> SP <dstmode> SP <srcsha> SP <dstsha> SP <status>
--
-- May be prefixed with a newline, which git log --pretty=format
-- adds to the first line of the diff, even with -z.
parserDiffRaw :: RawFilePath -> A.Parser DiffTreeItem
parserDiffRaw f = DiffTreeItem
<$ A8.char ':'
<$ A.option '\n' (A8.char '\n')
<* A8.char ':'
<*> octal
<* A8.char ' '
<*> octal