moved config reading into GitRepo

This commit is contained in:
Joey Hess 2010-10-11 23:22:38 -04:00
parent f6306bc301
commit cd1e39b127
2 changed files with 76 additions and 65 deletions

View file

@ -20,49 +20,41 @@ import LocationLog
-- git-annex's runtime state -- git-annex's runtime state
data State = State { data State = State {
repo :: GitRepo, repo :: GitRepo,
config :: Config backends :: [Backend]
}
data Config = Config {
annex_name :: String,
annex_numcopies :: Int,
annex_backends :: [Backend]
} }
{- An annexed file's content is stored somewhere under .git/annex/ -} {- An annexed file's content is stored somewhere under .git/annex/ -}
annexDir :: GitRepo -> Key -> IO FilePath annexDir :: GitRepo -> Key -> FilePath
annexDir repo key = do annexDir repo key = gitDir repo ++ "/annex/" ++ key
dir <- gitDir repo
return $ dir ++ "/annex/" ++ key
{- On startup, examine the git repo, prepare it, and record state for {- On startup, examine the git repo, prepare it, and record state for
- later. -} - later. -}
startAnnex :: IO State startAnnex :: IO State
startAnnex = do startAnnex = do
r <- gitRepoCurrent r <- gitRepoCurrent
config <- queryConfig r
gitPrep r gitPrep r
return State { return State {
repo = r, repo = r,
config = config backends = parseBackendList $ gitConfig r "annex.backends" ""
} }
{- Annexes a file, storing it in a backend, and then moving it into {- Annexes a file, storing it in a backend, and then moving it into
- the annex directory and setting up the symlink pointing to its content. -} - the annex directory and setting up the symlink pointing to its content. -}
annexFile :: State -> FilePath -> IO () annexFile :: State -> FilePath -> IO ()
annexFile state file = do annexFile state file = do
alreadyannexed <- lookupBackend backends (repo state) file alreadyannexed <- lookupBackend (backends state) (repo state) file
case (alreadyannexed) of case (alreadyannexed) of
Just _ -> error $ "already annexed: " ++ file Just _ -> error $ "already annexed: " ++ file
Nothing -> do Nothing -> do
checkLegal file checkLegal file
stored <- storeFile backends (repo state) file stored <- storeFile (backends state) (repo state) file
case (stored) of case (stored) of
Nothing -> error $ "no backend could store: " ++ file Nothing -> error $ "no backend could store: " ++ file
Just key -> symlink key Just key -> symlink key
where where
symlink key = do symlink key = do
dest <- annexDir (repo state) key let dest = annexDir (repo state) key
createDirectoryIfMissing True (parentDir dest) createDirectoryIfMissing True (parentDir dest)
renameFile file dest renameFile file dest
createSymbolicLink dest file createSymbolicLink dest file
@ -72,40 +64,22 @@ annexFile state file = do
if ((isSymbolicLink s) || (not $ isRegularFile s)) if ((isSymbolicLink s) || (not $ isRegularFile s))
then error $ "not a regular file: " ++ file then error $ "not a regular file: " ++ file
else return () else return ()
backends = getConfig state annex_backends
{- Inverse of annexFile. -} {- Inverse of annexFile. -}
unannexFile :: State -> FilePath -> IO () unannexFile :: State -> FilePath -> IO ()
unannexFile state file = do unannexFile state file = do
alreadyannexed <- lookupBackend backends (repo state) file alreadyannexed <- lookupBackend (backends state) (repo state) file
case (alreadyannexed) of case (alreadyannexed) of
Nothing -> error $ "not annexed " ++ file Nothing -> error $ "not annexed " ++ file
Just _ -> do Just _ -> do
mkey <- dropFile backends (repo state) file mkey <- dropFile (backends state) (repo state) file
case (mkey) of case (mkey) of
Nothing -> return () Nothing -> return ()
Just key -> do Just key -> do
src <- annexDir (repo state) key let src = annexDir (repo state) key
removeFile file removeFile file
renameFile src file renameFile src file
return () return ()
where
backends = getConfig state annex_backends
{- Query the git repo for relevant configuration settings. -}
queryConfig :: GitRepo -> IO Config
queryConfig repo = do
-- a name can be configured, if none is, use the repository path
name <- gitConfigGet "annex.name" (gitRepoTop repo)
-- default number of copies to keep of file contents is 1
numcopies <- gitConfigGet "annex.numcopies" "1"
backends <- gitConfigGet "annex.backends" ""
return Config {
annex_name = name,
annex_numcopies = read numcopies,
annex_backends = parseBackendList backends
}
{- Sets up a git repo for git-annex. May be called repeatedly. -} {- Sets up a git repo for git-annex. May be called repeatedly. -}
gitPrep :: GitRepo -> IO () gitPrep :: GitRepo -> IO ()
@ -125,7 +99,3 @@ gitPrep repo = do
appendFile attributes $ attrLine ++ "\n" appendFile attributes $ attrLine ++ "\n"
gitAdd repo attributes gitAdd repo attributes
else return () else return ()
{- Looks up a key in a State's Config -}
getConfig :: State -> (Config -> b) -> b
getConfig state key = key $ config state

View file

@ -1,4 +1,9 @@
{- git repository handling -} {- git repository handling
-
- This is written to be completely independant of git-annex and should be
- suitable for other uses.
-
- -}
module GitRepo ( module GitRepo (
GitRepo, GitRepo,
@ -6,38 +11,46 @@ module GitRepo (
gitRepoTop, gitRepoTop,
gitDir, gitDir,
gitRelative, gitRelative,
gitConfigGet, gitConfig,
gitAdd, gitAdd,
gitAttributes gitAttributes
) where ) where
import Directory import Directory
import System
import System.Directory import System.Directory
import System.Path import System.Path
import System.Cmd.Utils import System.Cmd.Utils
import System.IO import System.IO
import System.IO.Error import System.Posix.Process
import Data.String.Utils import Data.String.Utils
import Data.Map as Map (fromList, empty, lookup, Map)
import Utility import Utility
-- a git repository -- a git repository
data GitRepo = GitRepo { data GitRepo = GitRepo {
gitRepoTop :: FilePath, top :: FilePath,
bare :: Bool bare :: Bool,
} config :: Map String String
} deriving (Show, Read, Eq)
{- GitRepo constructor -} {- GitRepo constructor -}
gitRepo :: FilePath -> IO GitRepo gitRepo :: FilePath -> IO GitRepo
gitRepo dir = do gitRepo dir = do
b <- isBareRepo dir b <- isBareRepo dir
return GitRepo { let r = GitRepo {
gitRepoTop = dir, top = dir,
bare = b bare = b,
config = Map.empty
} }
r' <- gitConfigRead r
{- Short name used in here for top of repo. -} return r'
top = gitRepoTop
{- Field accessor. -}
gitRepoTop :: GitRepo -> FilePath
gitRepoTop repo = top repo
{- Path to a repository's gitattributes file. -} {- Path to a repository's gitattributes file. -}
gitAttributes :: GitRepo -> IO String gitAttributes :: GitRepo -> IO String
@ -49,11 +62,11 @@ gitAttributes repo = do
{- Path to a repository's .git directory. {- Path to a repository's .git directory.
- (For a bare repository, that is the root of the repository.) - (For a bare repository, that is the root of the repository.)
- TODO: support GIT_DIR -} - TODO: support GIT_DIR -}
gitDir :: GitRepo -> IO String gitDir :: GitRepo -> String
gitDir repo = do gitDir repo =
if (bare repo) if (bare repo)
then return $ (top repo) then top repo
else return $ (top repo) ++ "/.git" else top repo ++ "/.git"
{- Given a relative or absolute filename, calculates the name to use {- Given a relative or absolute filename, calculates the name to use
- to refer to the file relative to a git repository directory. - to refer to the file relative to a git repository directory.
@ -72,18 +85,46 @@ gitRelative repo file = drop (length absrepo) absfile
{- Stages a changed file in git's index. -} {- Stages a changed file in git's index. -}
gitAdd :: GitRepo -> FilePath -> IO () gitAdd :: GitRepo -> FilePath -> IO ()
gitAdd repo file = do gitAdd repo file = runGit repo ["add", file]
-- TODO
{- Constructs a git command line operating on the specified repo. -}
gitCommandLine :: GitRepo -> [String] -> [String]
gitCommandLine repo params =
-- force use of specified repo via --git-dir and --work-tree
["--git-dir="++(gitDir repo), "--work-tree="++(top repo)] ++ params
{- Runs git in the specified repo. -}
runGit :: GitRepo -> [String] -> IO ()
runGit repo params = do
r <- executeFile "git" True (gitCommandLine repo params) Nothing
return () return ()
{- Queries git-config. -} {- Runs a git subcommand and returns its output. -}
gitConfigGet :: String -> String -> IO String gitPipeRead :: GitRepo -> [String] -> IO String
gitConfigGet name defaultValue = gitPipeRead repo params =
flip catch (\_ -> return defaultValue) $ pOpen ReadFromPipe "git" (gitCommandLine repo params) $ \h -> do
pOpen ReadFromPipe "git" ["config", "--get", name] $ \h -> do ret <- hGetContentsStrict h
ret <- hGetLine h
return ret return ret
{- Runs git config and populates a repo with its settings. -}
gitConfigRead :: GitRepo -> IO GitRepo
gitConfigRead repo = do
c <- gitPipeRead repo ["config", "--list"]
return repo { config = Map.fromList $ parse c }
where
parse s = map ( \l -> (key l, val l) ) $ lines s
keyval l = split sep l :: [String]
key l = (keyval l) !! 0
val l = join sep $ drop 1 $ keyval l
sep = "="
{- Returns a single git config setting, or a default value if not set. -}
gitConfig :: GitRepo -> String -> String -> String
gitConfig repo key defaultValue =
case (Map.lookup key $ config repo) of
Just value -> value
Nothing -> defaultValue
{- Finds the current git repository, which may be in a parent directory. -} {- Finds the current git repository, which may be in a parent directory. -}
gitRepoCurrent :: IO GitRepo gitRepoCurrent :: IO GitRepo
gitRepoCurrent = do gitRepoCurrent = do