{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}
module HMGit.Internal.Core.Runner.API (
    HMGitT
  , hmGitDBPath
  , hmGitDBName
  , hmGitLoadMasterHash
  , hmGitRoot
  , hmGitTreeLim
  , hmGitIndexPath
  , hmGitBRPath
  , hmGitBRPath'
  , hmGitBRName
  , hmGitBRName'
  , getCurrentDirFromHMGit
  , runHMGit
) where

import           HMGit.Internal.Core.Runner.HMGitConfig (HMGitConfig (..))
import           HMGit.Internal.Parser.Core.ByteString  (ParseException (..))

import qualified Codec.Binary.UTF8.String               as BUS
import           Control.Arrow                          ((|||))
import           Control.Exception.Safe                 (MonadThrow, throw,
                                                         throwString)
import           Control.Monad.Extra                    (ifM, replicateM)
import           Control.Monad.IO.Class                 (MonadIO (..))
import           Control.Monad.Trans                    (lift)
import           Control.Monad.Trans.Reader             (ReaderT (..), asks)
import qualified Data.Binary.Get                        as BG
import qualified Data.ByteString.Lazy                   as BL
import           Data.Functor                           ((<&>))
import           Data.List                              (isPrefixOf)
import           Data.List.Extra                        (dropPrefix)
import           Data.Tuple.Extra                       (thd3, third3)
import           Path                                   (File, Rel)
import qualified Path                                   as P
import qualified Path.IO                                as P
import           System.FilePath                        (takeFileName)
import           Text.Printf                            (printf)

type HMGitT = ReaderT HMGitConfig

-- | Get an abstract path to the HMGit database directory
hmGitDBPath :: Monad m => HMGitT m (P.Path P.Abs P.Dir)
hmGitDBPath :: HMGitT m (Path Abs Dir)
hmGitDBPath = (HMGitConfig -> Path Abs Dir) -> HMGitT m (Path Abs Dir)
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
asks HMGitConfig -> Path Abs Dir
hmGitDir

-- | Get the HMGit database name
hmGitDBName :: Monad m => HMGitT m String
hmGitDBName :: HMGitT m String
hmGitDBName = String -> String
takeFileName (String -> String)
-> (Path Abs Dir -> String) -> Path Abs Dir -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
forall a. [a] -> [a]
init (String -> String)
-> (Path Abs Dir -> String) -> Path Abs Dir -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path Abs Dir -> String
forall b t. Path b t -> String
P.toFilePath (Path Abs Dir -> String)
-> ReaderT HMGitConfig m (Path Abs Dir) -> HMGitT m String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT HMGitConfig m (Path Abs Dir)
forall (m :: * -> *). Monad m => HMGitT m (Path Abs Dir)
hmGitDBPath

-- | Get an abstract path to the HMGit project directory
hmGitRoot :: Monad m => HMGitT m (P.Path P.Abs P.Dir)
hmGitRoot :: HMGitT m (Path Abs Dir)
hmGitRoot = Path Abs Dir -> Path Abs Dir
forall b t. Path b t -> Path b Dir
P.parent (Path Abs Dir -> Path Abs Dir)
-> HMGitT m (Path Abs Dir) -> HMGitT m (Path Abs Dir)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HMGitT m (Path Abs Dir)
forall (m :: * -> *). Monad m => HMGitT m (Path Abs Dir)
hmGitDBPath

-- | Get a loop limit of the tree
hmGitTreeLim :: Monad m => HMGitT m Int
hmGitTreeLim :: HMGitT m Int
hmGitTreeLim = (HMGitConfig -> Int) -> HMGitT m Int
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
asks HMGitConfig -> Int
hmGitTreeLimit

-- | The index file path
hmGitIndexPath :: Monad m => HMGitT m (P.Path P.Abs P.File)
hmGitIndexPath :: HMGitT m (Path Abs File)
hmGitIndexPath = (Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
P.</> $(P.mkRelFile "index")) (Path Abs Dir -> Path Abs File)
-> ReaderT HMGitConfig m (Path Abs Dir) -> HMGitT m (Path Abs File)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT HMGitConfig m (Path Abs Dir)
forall (m :: * -> *). Monad m => HMGitT m (Path Abs Dir)
hmGitDBPath

-- | Returns the current path relative to the hmgit database directory
getCurrentDirFromHMGit :: (MonadThrow m, MonadIO m)
    => HMGitT m (P.Path P.Rel P.Dir)
getCurrentDirFromHMGit :: HMGitT m (Path Rel Dir)
getCurrentDirFromHMGit = do
    String
currentDir <- Path Abs Dir -> String
forall b t. Path b t -> String
P.toFilePath (Path Abs Dir -> String)
-> ReaderT HMGitConfig m (Path Abs Dir)
-> ReaderT HMGitConfig m String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT HMGitConfig m (Path Abs Dir)
forall (m :: * -> *). MonadIO m => m (Path Abs Dir)
P.getCurrentDir
    String
rootPath <- Path Abs Dir -> String
forall b t. Path b t -> String
P.toFilePath (Path Abs Dir -> String)
-> ReaderT HMGitConfig m (Path Abs Dir)
-> ReaderT HMGitConfig m String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReaderT HMGitConfig m (Path Abs Dir)
forall (m :: * -> *). Monad m => HMGitT m (Path Abs Dir)
hmGitRoot
    if String
rootPath String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
currentDir then
        let path :: String
path = String -> String -> String
forall a. Eq a => [a] -> [a] -> [a]
dropPrefix String
rootPath String
currentDir in
            String -> HMGitT m (Path Rel Dir)
forall (m :: * -> *). MonadThrow m => String -> m (Path Rel Dir)
P.parseRelDir (String -> HMGitT m (Path Rel Dir))
-> String -> HMGitT m (Path Rel Dir)
forall a b. (a -> b) -> a -> b
$ if String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
path then String
"./" else String
path
    else
        ReaderT HMGitConfig m String
forall (m :: * -> *). Monad m => HMGitT m String
hmGitDBName
            ReaderT HMGitConfig m String
-> (String -> HMGitT m (Path Rel Dir)) -> HMGitT m (Path Rel Dir)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> HMGitT m (Path Rel Dir)
forall (m :: * -> *) a.
(MonadThrow m, HasCallStack) =>
String -> m a
throwString
             (String -> HMGitT m (Path Rel Dir))
-> (String -> String) -> String -> HMGitT m (Path Rel Dir)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
forall r. PrintfType r => String -> r
printf String
"The current working directory is not in %s repository"

-- | If @refs\/heads\/master@ or @refs\/heads\/main@ exists, return @Right@,
-- if they are not exist, the candidate path is wrapped in @Left@ returned.
hmGitBRPath :: MonadIO m => HMGitT m (Either (P.Path P.Abs P.File) (P.Path P.Abs P.File))
hmGitBRPath :: HMGitT m (Either (Path Abs File) (Path Abs File))
hmGitBRPath = do
    Path Abs File
m <- HMGitT m (Path Abs Dir)
forall (m :: * -> *). Monad m => HMGitT m (Path Abs Dir)
hmGitDBPath HMGitT m (Path Abs Dir)
-> (Path Abs Dir -> Path Abs File)
-> ReaderT HMGitConfig m (Path Abs File)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
P.</> $(P.mkRelFile "refs/heads/master"))
    ReaderT HMGitConfig m Bool
-> HMGitT m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM (Path Abs File -> ReaderT HMGitConfig m Bool
forall (m :: * -> *) b. MonadIO m => Path b File -> m Bool
P.doesFileExist Path Abs File
m) (m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Either (Path Abs File) (Path Abs File))
 -> HMGitT m (Either (Path Abs File) (Path Abs File)))
-> m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall a b. (a -> b) -> a -> b
$ Either (Path Abs File) (Path Abs File)
-> m (Either (Path Abs File) (Path Abs File))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either (Path Abs File) (Path Abs File)
 -> m (Either (Path Abs File) (Path Abs File)))
-> Either (Path Abs File) (Path Abs File)
-> m (Either (Path Abs File) (Path Abs File))
forall a b. (a -> b) -> a -> b
$ Path Abs File -> Either (Path Abs File) (Path Abs File)
forall a b. b -> Either a b
Right Path Abs File
m) (HMGitT m (Either (Path Abs File) (Path Abs File))
 -> HMGitT m (Either (Path Abs File) (Path Abs File)))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall a b. (a -> b) -> a -> b
$ do
        Path Abs File
m' <- HMGitT m (Path Abs Dir)
forall (m :: * -> *). Monad m => HMGitT m (Path Abs Dir)
hmGitDBPath HMGitT m (Path Abs Dir)
-> (Path Abs Dir -> Path Abs File)
-> ReaderT HMGitConfig m (Path Abs File)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (Path Abs Dir -> Path Rel File -> Path Abs File
forall b t. Path b Dir -> Path Rel t -> Path b t
P.</> $(P.mkRelFile "refs/heads/main"))
        ReaderT HMGitConfig m Bool
-> HMGitT m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM (Path Abs File -> ReaderT HMGitConfig m Bool
forall (m :: * -> *) b. MonadIO m => Path b File -> m Bool
P.doesFileExist Path Abs File
m') (m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Either (Path Abs File) (Path Abs File))
 -> HMGitT m (Either (Path Abs File) (Path Abs File)))
-> m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall a b. (a -> b) -> a -> b
$ Either (Path Abs File) (Path Abs File)
-> m (Either (Path Abs File) (Path Abs File))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either (Path Abs File) (Path Abs File)
 -> m (Either (Path Abs File) (Path Abs File)))
-> Either (Path Abs File) (Path Abs File)
-> m (Either (Path Abs File) (Path Abs File))
forall a b. (a -> b) -> a -> b
$ Path Abs File -> Either (Path Abs File) (Path Abs File)
forall a b. b -> Either a b
Right Path Abs File
m') (HMGitT m (Either (Path Abs File) (Path Abs File))
 -> HMGitT m (Either (Path Abs File) (Path Abs File)))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall a b. (a -> b) -> a -> b
$
            m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Either (Path Abs File) (Path Abs File))
 -> HMGitT m (Either (Path Abs File) (Path Abs File)))
-> m (Either (Path Abs File) (Path Abs File))
-> HMGitT m (Either (Path Abs File) (Path Abs File))
forall a b. (a -> b) -> a -> b
$ Either (Path Abs File) (Path Abs File)
-> m (Either (Path Abs File) (Path Abs File))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either (Path Abs File) (Path Abs File)
 -> m (Either (Path Abs File) (Path Abs File)))
-> Either (Path Abs File) (Path Abs File)
-> m (Either (Path Abs File) (Path Abs File))
forall a b. (a -> b) -> a -> b
$ Path Abs File -> Either (Path Abs File) (Path Abs File)
forall a b. a -> Either a b
Left Path Abs File
m'

-- | Get the path, ignoring whether it is an actual path or a candidate path.
hmGitBRPath' :: MonadIO m => HMGitT m (P.Path P.Abs P.File)
hmGitBRPath' :: HMGitT m (Path Abs File)
hmGitBRPath' = HMGitT m (Either (Path Abs File) (Path Abs File))
forall (m :: * -> *).
MonadIO m =>
HMGitT m (Either (Path Abs File) (Path Abs File))
hmGitBRPath HMGitT m (Either (Path Abs File) (Path Abs File))
-> (Either (Path Abs File) (Path Abs File)
    -> HMGitT m (Path Abs File))
-> HMGitT m (Path Abs File)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Path Abs File -> HMGitT m (Path Abs File)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Path Abs File -> HMGitT m (Path Abs File))
-> (Path Abs File -> HMGitT m (Path Abs File))
-> Either (Path Abs File) (Path Abs File)
-> HMGitT m (Path Abs File)
forall (a :: * -> * -> *) b d c.
ArrowChoice a =>
a b d -> a c d -> a (Either b c) d
||| Path Abs File -> HMGitT m (Path Abs File)
forall (f :: * -> *) a. Applicative f => a -> f a
pure

-- | If @refs\/heads\/master@ or @refs\/heads\/main@ exists, return @Right@,
-- if they are not exist, the candidate name is wrapped in @Left@ returned.
hmGitBRName :: MonadIO m => HMGitT m (Either String String)
hmGitBRName :: HMGitT m (Either String String)
hmGitBRName = HMGitT m (Either (Path Abs File) (Path Abs File))
forall (m :: * -> *).
MonadIO m =>
HMGitT m (Either (Path Abs File) (Path Abs File))
hmGitBRPath
    HMGitT m (Either (Path Abs File) (Path Abs File))
-> (Either (Path Abs File) (Path Abs File) -> Either String String)
-> HMGitT m (Either String String)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (Path Abs File -> Either String String)
-> (Path Abs File -> Either String String)
-> Either (Path Abs File) (Path Abs File)
-> Either String String
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> Either String String
forall a b. a -> Either a b
Left (String -> Either String String)
-> (Path Abs File -> String)
-> Path Abs File
-> Either String String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path Rel File -> String
forall b t. Path b t -> String
P.toFilePath (Path Rel File -> String)
-> (Path Abs File -> Path Rel File) -> Path Abs File -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path Abs File -> Path Rel File
forall b. Path b File -> Path Rel File
P.filename) (String -> Either String String
forall a b. b -> Either a b
Right (String -> Either String String)
-> (Path Abs File -> String)
-> Path Abs File
-> Either String String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path Rel File -> String
forall b t. Path b t -> String
P.toFilePath (Path Rel File -> String)
-> (Path Abs File -> Path Rel File) -> Path Abs File -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path Abs File -> Path Rel File
forall b. Path b File -> Path Rel File
P.filename)

-- | Get the name, ignoring whether it is a real name or a candidate name.
hmGitBRName' :: MonadIO m => HMGitT m String
hmGitBRName' :: HMGitT m String
hmGitBRName' = HMGitT m (Either String String)
forall (m :: * -> *). MonadIO m => HMGitT m (Either String String)
hmGitBRName HMGitT m (Either String String)
-> (Either String String -> HMGitT m String) -> HMGitT m String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> HMGitT m String
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String -> HMGitT m String)
-> (String -> HMGitT m String)
-> Either String String
-> HMGitT m String
forall (a :: * -> * -> *) b d c.
ArrowChoice a =>
a b d -> a c d -> a (Either b c) d
||| String -> HMGitT m String
forall (f :: * -> *) a. Applicative f => a -> f a
pure

-- | Read refs\/heads\/master. If it does not exist,
-- look for refs\/heads\/main as a fallback.
-- The @Nothing@ will be returned if neither exists.
hmGitLoadMasterHash :: (MonadIO m, MonadThrow m) => HMGitT m (Maybe String)
hmGitLoadMasterHash :: HMGitT m (Maybe String)
hmGitLoadMasterHash = HMGitT m (Either (Path Abs File) (Path Abs File))
forall (m :: * -> *).
MonadIO m =>
HMGitT m (Either (Path Abs File) (Path Abs File))
hmGitBRPath
    HMGitT m (Either (Path Abs File) (Path Abs File))
-> (Either (Path Abs File) (Path Abs File)
    -> HMGitT m (Maybe String))
-> HMGitT m (Maybe String)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Path Abs File -> HMGitT m (Maybe String))
-> (Path Abs File -> HMGitT m (Maybe String))
-> Either (Path Abs File) (Path Abs File)
-> HMGitT m (Maybe String)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (HMGitT m (Maybe String) -> Path Abs File -> HMGitT m (Maybe String)
forall a b. a -> b -> a
const (HMGitT m (Maybe String)
 -> Path Abs File -> HMGitT m (Maybe String))
-> HMGitT m (Maybe String)
-> Path Abs File
-> HMGitT m (Maybe String)
forall a b. (a -> b) -> a -> b
$ Maybe String -> HMGitT m (Maybe String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe String
forall a. Maybe a
Nothing) Path Abs File -> HMGitT m (Maybe String)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) b t.
(MonadIO (t m), MonadTrans t, MonadThrow m, MonadThrow (t m)) =>
Path b t -> t m (Maybe String)
readHash
    where
        readHash :: Path b t -> t m (Maybe String)
readHash Path b t
fpath = do
            (ByteString
uc, ByteOffset
_, String
fp) <- IO ByteString -> t m ByteString
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (String -> IO ByteString
BL.readFile (String -> IO ByteString) -> String -> IO ByteString
forall a b. (a -> b) -> a -> b
$ Path b t -> String
forall b t. Path b t -> String
P.toFilePath Path b t
fpath)
                t m ByteString
-> (ByteString -> t m (ByteString, ByteOffset, [Word8]))
-> t m (ByteString, ByteOffset, [Word8])
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ((ByteString, ByteOffset, String)
 -> t m (ByteString, ByteOffset, [Word8]))
-> ((ByteString, ByteOffset, [Word8])
    -> t m (ByteString, ByteOffset, [Word8]))
-> Either
     (ByteString, ByteOffset, String) (ByteString, ByteOffset, [Word8])
-> t m (ByteString, ByteOffset, [Word8])
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (ParseException -> t m (ByteString, ByteOffset, [Word8])
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (ParseException -> t m (ByteString, ByteOffset, [Word8]))
-> ((ByteString, ByteOffset, String) -> ParseException)
-> (ByteString, ByteOffset, String)
-> t m (ByteString, ByteOffset, [Word8])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ParseException
MasterHashParser (String -> ParseException)
-> ((ByteString, ByteOffset, String) -> String)
-> (ByteString, ByteOffset, String)
-> ParseException
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString, ByteOffset, String) -> String
forall a b c. (a, b, c) -> c
thd3) (ByteString, ByteOffset, [Word8])
-> t m (ByteString, ByteOffset, [Word8])
forall (f :: * -> *) a. Applicative f => a -> f a
pure
                    (Either
   (ByteString, ByteOffset, String) (ByteString, ByteOffset, [Word8])
 -> t m (ByteString, ByteOffset, [Word8]))
-> (ByteString
    -> Either
         (ByteString, ByteOffset, String) (ByteString, ByteOffset, [Word8]))
-> ByteString
-> t m (ByteString, ByteOffset, [Word8])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Get [Word8]
-> ByteString
-> Either
     (ByteString, ByteOffset, String) (ByteString, ByteOffset, [Word8])
forall a.
Get a
-> ByteString
-> Either
     (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)
BG.runGetOrFail (Int -> Get Word8 -> Get [Word8]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
40 Get Word8
BG.getWord8)
                t m (ByteString, ByteOffset, [Word8])
-> ((ByteString, ByteOffset, [Word8])
    -> (ByteString, ByteOffset, String))
-> t m (ByteString, ByteOffset, String)
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> ([Word8] -> String)
-> (ByteString, ByteOffset, [Word8])
-> (ByteString, ByteOffset, String)
forall c c' a b. (c -> c') -> (a, b, c) -> (a, b, c')
third3 [Word8] -> String
BUS.decode
            if ByteString -> Bool
BL.null ByteString
uc Bool -> Bool -> Bool
|| ByteString
uc ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
"\n" then Maybe String -> t m (Maybe String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe String -> t m (Maybe String))
-> Maybe String -> t m (Maybe String)
forall a b. (a -> b) -> a -> b
$ String -> Maybe String
forall a. a -> Maybe a
Just String
fp else
                m (Maybe String) -> t m (Maybe String)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m (Maybe String) -> t m (Maybe String))
-> m (Maybe String) -> t m (Maybe String)
forall a b. (a -> b) -> a -> b
$ ParseException -> m (Maybe String)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw (ParseException -> m (Maybe String))
-> ParseException -> m (Maybe String)
forall a b. (a -> b) -> a -> b
$ String -> ParseException
MasterHashParser String
"invalid master/main hash"

-- | HMGit runner
runHMGit :: HMGitT m a -> HMGitConfig -> m a
runHMGit :: HMGitT m a -> HMGitConfig -> m a
runHMGit = HMGitT m a -> HMGitConfig -> m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT