aboutsummaryrefslogtreecommitdiffstats
path: root/app/Git.hs
diff options
context:
space:
mode:
authorLibravatar Alexander Foremny <aforemny@posteo.de>2024-03-14 07:10:03 +0100
committerLibravatar Alexander Foremny <aforemny@posteo.de>2024-03-14 07:10:03 +0100
commit11284c7c12c44e12de1cfc712c0391d5ee32a9f2 (patch)
tree553a527ff19f5ef105cbc2f026284e75fa5900db /app/Git.hs
parentc8ab97e77c8ab56b9835d9f260dc222a10e9b3c6 (diff)
parent09e26c37de7e7227d856ffe15c9554af36b50c58 (diff)
Merge remote-tracking branch 'origin/feature/review'main
Diffstat (limited to 'app/Git.hs')
-rw-r--r--app/Git.hs36
1 files changed, 34 insertions, 2 deletions
diff --git a/app/Git.hs b/app/Git.hs
index 6431259..e195d1b 100644
--- a/app/Git.hs
+++ b/app/Git.hs
@@ -8,6 +8,9 @@ module Git
getCommitOf,
readTextFileOfText,
readTextFileOfBS,
+ resolveRef,
+ getCommitsBetween,
+ diffOf,
)
where
@@ -27,7 +30,8 @@ import Data.Time.Clock (UTCTime, getCurrentTime)
import Exception qualified as E
import GHC.Generics (Generic)
import Git.CommitHash
-import Process (proc, sh)
+import Patch qualified as A
+import Process (proc, sh, sh_)
import Text.Printf (printf)
getCommitHashes :: IO (NonEmpty T.Text)
@@ -91,7 +95,7 @@ readTextFileOfText :: CommitHash -> FilePath -> IO LT.Text
readTextFileOfText = readTextFileOf LT.readFile LT.decodeUtf8
readTextFileOfBS :: CommitHash -> FilePath -> IO LB.ByteString
-readTextFileOfBS = readTextFileOf LB.readFile (\x->x)
+readTextFileOfBS = readTextFileOf LB.readFile id
readTextFileOf :: (FilePath -> IO a) -> (LB.ByteString -> a) -> CommitHash -> FilePath -> IO a
readTextFileOf readFile _ WorkingTree filePath =
@@ -102,3 +106,31 @@ readTextFileOf _ decode (Commit hash) filePath =
catch
(decode <$> sh (proc "git show %:%" hash filePath))
(\(_ :: E.ProcessException) -> throwIO (E.CannotReadFile (printf "%s:%s" hash filePath)))
+
+resolveRef :: T.Text -> IO CommitHash
+resolveRef =
+ fmap (Commit . T.strip . T.decodeUtf8 . LB.toStrict)
+ . sh
+ . proc "git rev-parse %"
+
+-- | `getCommitsBetween prevCommit commit` returns the commits from `prevCommit` to `commit`. The result excludes `prevCommit`, but includes `commit`.
+--
+-- If `prevCommit` is not an ancestor of `commit`, this functions throws `NoAncestor commit prevCommit`.
+getCommitsBetween :: CommitHash -> CommitHash -> IO [CommitHash]
+getCommitsBetween WorkingTree commit@(Commit _) =
+ throwIO (E.NoAncestor WorkingTree commit)
+getCommitsBetween WorkingTree WorkingTree = pure [WorkingTree]
+getCommitsBetween prevCommit WorkingTree =
+ fmap (++ [WorkingTree]) . getCommitsBetween prevCommit
+ =<< resolveRef "HEAD"
+getCommitsBetween prevCommit@(Commit prevHash) commit@(Commit hash) = do
+ catch
+ (sh_ (proc "git merge-base --is-ancestor % %" prevHash hash))
+ (\(_ :: E.ProcessException) -> throwIO (E.NoAncestor commit prevCommit))
+ map (Commit . T.strip) . T.lines . T.decodeUtf8 . LB.toStrict
+ <$> sh (proc "git log --format=%%H %..%" prevHash hash)
+
+diffOf :: CommitHash -> CommitHash -> IO A.Patch
+diffOf prevHash hash =
+ A.parse . T.decodeUtf8 . LB.toStrict
+ <$> sh (proc "git diff % %" (toTextUnsafe prevHash) (toTextUnsafe hash))