hbs2/hbs2-git/lib/HBS2Git/Config.hs

143 lines
4.2 KiB
Haskell

module HBS2Git.Config
( module HBS2Git.Config
, module Data.Config.Suckless
) where
import HBS2.Prelude.Plated
import HBS2.Base58
import HBS2.System.Logger.Simple
import HBS2.OrDie
import Data.Config.Suckless
import HBS2Git.Types
import Control.Applicative
import Control.Exception
import Control.Monad.Catch (MonadThrow, throwM)
import System.FilePath
import System.Directory
import Data.Maybe
import Data.Either
import Data.List (isSuffixOf)
import Control.Monad.Trans.Maybe
import System.Environment
import System.IO (stderr)
data NoWorkDirException =
NoWorkDirException
deriving (Show, Typeable)
instance Exception NoWorkDirException
appName :: FilePath
appName = "hbs2-git"
-- Finds .git dir inside given directory moving upwards
findGitDir :: MonadIO m => FilePath -> m (Maybe FilePath)
findGitDir dir = liftIO do
trace "locating .git directory"
let gitDir = dir </> ".git"
exists <- doesDirectoryExist gitDir
if exists
then return $ Just gitDir
else let parentDir = takeDirectory dir
in if parentDir == dir -- we've reached the root directory
then return Nothing
else findGitDir parentDir
configPathOld :: MonadIO m => FilePath -> m FilePath
configPathOld pwd = liftIO do
xdg <- liftIO $ getXdgDirectory XdgConfig appName
home <- liftIO getHomeDirectory
pure $ xdg </> makeRelative home pwd
configPath :: (MonadIO m, MonadThrow m) => FilePath -> m FilePath
configPath _ = do
pwd <- liftIO getCurrentDirectory
git <- findGitDir pwd
byEnv <- liftIO $ lookupEnv "GIT_DIR"
bare <- if isJust (git <|> byEnv) then do
pure Nothing
else runMaybeT do
-- check may be it's a bare git repo
gitConf <- toMPlus =<< liftIO ( try @IOException $
readFile "config"
<&> parseTop
<&> fromRight mempty )
let core = or [True | SymbolVal @C "core" <- universeBi gitConf]
let bare = or [True | ListVal [SymbolVal @C "bare", _, SymbolVal "true"] <- universeBi gitConf ]
let repo = or [True | SymbolVal @C "repositoryformatversion" <- universeBi gitConf ]
if core && bare && repo then do
pure pwd
else
MaybeT $ pure Nothing
let maybePath = dropSuffix <$> (git <|> byEnv <|> bare)
path <- maybe (throwM NoWorkDirException)
pure
maybePath
pure (path </> ".hbs2")
where
dropSuffix s | isSuffixOf ".git/" s = takeDirectory s
| isSuffixOf ".git" s = takeDirectory s
| otherwise = s
data ConfigPathInfo = ConfigPathInfo {
configRepoParentDir :: FilePath,
configDir :: FilePath,
configFilePath :: FilePath
} deriving (Eq, Show)
-- returns git repository parent dir, config directory and config file path
getConfigPathInfo :: (MonadIO m, MonadThrow m) => m ConfigPathInfo
getConfigPathInfo = do
trace "getConfigPathInfo"
confP <- configPath ""
let pwd = takeDirectory confP
let confFile = confP </> "config"
trace $ "confPath:" <+> pretty confP
pure ConfigPathInfo {
configRepoParentDir = pwd,
configDir = confP,
configFilePath = confFile
}
-- returns current directory, where found .git directory
configInit :: (MonadIO m, MonadThrow m) => m (FilePath, [Syntax C])
configInit = liftIO do
trace "configInit"
ConfigPathInfo{..} <- getConfigPathInfo
here <- doesDirectoryExist configDir
unless here do
debug $ "create directory" <+> pretty configDir
createDirectoryIfMissing True configDir
confHere <- doesFileExist configFilePath
unless confHere do
appendFile configFilePath ""
cfg <- readFile configFilePath <&> parseTop <&> either mempty id
pure (configRepoParentDir, cfg)
cookieFile :: (MonadIO m, MonadThrow m) => m FilePath
cookieFile = configPath "" <&> (</> "cookie")
getAppStateDir :: forall m . MonadIO m => m FilePath
getAppStateDir = liftIO $ getXdgDirectory XdgData appName
makeDbPath :: MonadIO m => RepoRef -> m FilePath
makeDbPath h = do
state <- getAppStateDir
liftIO $ createDirectoryIfMissing True state
pure $ state </> show (pretty (AsBase58 h))