diff options
author | Alexander Foremny <aforemny@posteo.de> | 2023-10-17 14:14:48 +0200 |
---|---|---|
committer | Alexander Foremny <aforemny@posteo.de> | 2023-11-07 09:50:51 +0100 |
commit | ea1236f2cf6d3ef4b739b2ca28f47a3bbed42295 (patch) | |
tree | 3b1801ad9654e657ed0c0b202e316dc42244c56d /app/History/PartialCommitInfo.hs | |
parent | 4521eb7a4b0d4a4ff8cf9153484d0596c5143170 (diff) |
refactor history
Diffstat (limited to 'app/History/PartialCommitInfo.hs')
-rw-r--r-- | app/History/PartialCommitInfo.hs | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/app/History/PartialCommitInfo.hs b/app/History/PartialCommitInfo.hs new file mode 100644 index 0000000..fb53fbf --- /dev/null +++ b/app/History/PartialCommitInfo.hs @@ -0,0 +1,97 @@ +module History.PartialCommitInfo + ( PartialCommitInfo (..), + getPartialCommitInfos, + ) +where + +import Control.Exception (catch) +import Data.Binary (Binary) +import Data.ByteString.Lazy.Char8 qualified as LB8 +import Data.Function ((&)) +import Data.Text qualified as T +import Die (die) +import Exception qualified as E +import GHC.Generics (Generic) +import Git qualified +import History.Cache (cached) +import History.CommitHash (CommitHash (..)) +import Issue (Issue, getIssuesPar) +import Process (proc, sh) +import System.Directory (getCurrentDirectory) +import System.FilePath ((</>)) +import System.IO.Temp (withSystemTempDirectory) +import System.Process.Typed (setWorkingDir) + +-- | `PartialCommitInfo` records the complete issues ONLY in files that have +-- been changed in the commit. +data PartialCommitInfo = PartialCommitInfo + { hash :: CommitHash, + filesChanged :: [FilePath], + issues :: [Issue] + } + deriving (Show, Binary, Generic) + +getPartialCommitInfos :: IO [PartialCommitInfo] +getPartialCommitInfos = do + -- TODO Revise `getCommitHashes` + -- + -- - Should throw if no commits. + -- - Should always be reversed? + commitHashes <- reverse <$> Git.getCommitHashes + mapM getCommitInfoOf (map Commit commitHashes ++ [WorkingTree]) + +getCommitInfoOf :: CommitHash -> IO PartialCommitInfo +getCommitInfoOf WorkingTree = do + (issuesWorkingTreeChanged, filesChanged) <- getIssuesAndFilesWorkingTreeChanged [] + pure $ + PartialCommitInfo + { hash = WorkingTree, + filesChanged = filesChanged, + issues = issuesWorkingTreeChanged + } +getCommitInfoOf (Commit hash) = cached (hash <> (T.pack ".changed")) $ \_ -> do + (issuesCommitChanged, filesChanged) <- getIssuesAndFilesCommitChanged hash + pure $ + PartialCommitInfo + { hash = Commit hash, + filesChanged = filesChanged, + issues = issuesCommitChanged + } + +-- | Given the hash of a commit, get all issues in the files which have +-- been changed by this commit, as well as all changed files. +getIssuesAndFilesCommitChanged :: T.Text -> IO ([Issue], [FilePath]) +getIssuesAndFilesCommitChanged hash = do + withSystemTempDirectory "history" $ \tmp -> do + let cwd = tmp </> T.unpack hash + Git.withWorkingTree cwd hash do + files <- gitShowChanged cwd + issues <- concat <$> catch (getIssuesPar cwd files) dieOfInvalidTreeGrepperResult + pure (issues, files) + +dieOfInvalidTreeGrepperResult :: E.InvalidTreeGrepperResult -> IO a +dieOfInvalidTreeGrepperResult (E.InvalidTreeGrepperResult e) = + die e + +-- | Gets issues in all files which have been changed in your current +-- [working +-- - tree](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefworkingtreeaworkingtree) +getIssuesAndFilesWorkingTreeChanged :: [FilePath] -> IO ([Issue], [FilePath]) +getIssuesAndFilesWorkingTreeChanged paths = do + cwd <- getCurrentDirectory + files <- gitLsFilesModifiedIn cwd paths + issues <- concat <$> catch (getIssuesPar cwd files) dieOfInvalidTreeGrepperResult + pure (issues, files) + +gitShowChanged :: FilePath -> IO [FilePath] +gitShowChanged cwd = + Prelude.lines . LB8.unpack + <$> sh ("git show -p --name-only --format=''" & setWorkingDir cwd) + +gitLsFilesModifiedIn :: FilePath -> [FilePath] -> IO [FilePath] +gitLsFilesModifiedIn cwd paths = + Prelude.lines . LB8.unpack + <$> sh + ( proc "git ls-files --modified %" ("--" : paths) + & setWorkingDir cwd + ) |