module B9.Repository (RemoteRepo(..)
,remoteRepoRepoId
,RepoCache(..)
,SshPrivKey(..)
,SshRemoteHost(..)
,SshRemoteUser(..)
,initRepoCache
,initRemoteRepo
,remoteRepoCheckSshPrivKey
,remoteRepoCacheDir
,localRepoDir
,writeRemoteRepoConfig
,getConfiguredRemoteRepos
,lookupRemoteRepo) where
import Control.Monad
import Control.Monad.IO.Class
import Control.Applicative
import Data.Data
import Data.List
import Data.ConfigFile
import Text.Printf
import System.FilePath
import System.Directory
import B9.ConfigUtils
newtype RepoCache = RepoCache FilePath
deriving (Read, Show, Typeable, Data)
data RemoteRepo = RemoteRepo String
FilePath
SshPrivKey
SshRemoteHost
SshRemoteUser
deriving (Read, Show, Typeable, Data)
remoteRepoRepoId :: RemoteRepo -> String
remoteRepoRepoId (RemoteRepo repoId _ _ _ _) = repoId
newtype SshPrivKey = SshPrivKey FilePath
deriving (Read, Show, Typeable, Data)
newtype SshRemoteHost = SshRemoteHost (String,Int)
deriving (Read, Show, Typeable, Data)
newtype SshRemoteUser = SshRemoteUser String
deriving (Read, Show, Typeable, Data)
initRepoCache :: MonadIO m => SystemPath -> m RepoCache
initRepoCache repoDirSystemPath = do
repoDir <- resolve repoDirSystemPath
ensureDir (repoDir ++ "/")
return (RepoCache repoDir)
remoteRepoCheckSshPrivKey :: MonadIO m => RemoteRepo -> m RemoteRepo
remoteRepoCheckSshPrivKey (RemoteRepo rId rp (SshPrivKey keyFile) h u) = do
exists <- liftIO (doesFileExist keyFile)
keyFile' <- liftIO (canonicalizePath keyFile)
when (not exists)
(error (printf "SSH Key file '%s' for repository '%s' is missing."
keyFile'
rId))
return (RemoteRepo rId rp (SshPrivKey keyFile') h u)
initRemoteRepo :: MonadIO m
=> RepoCache
-> RemoteRepo
-> m RemoteRepo
initRemoteRepo cache repo = do
repo' <- remoteRepoCheckSshPrivKey repo
let (RemoteRepo repoId _ _ _ _) = repo'
ensureDir (remoteRepoCacheDir cache repoId ++ "/")
return repo'
remoteRepoCacheDir :: RepoCache
-> String
-> FilePath
remoteRepoCacheDir (RepoCache cacheDir) repoId =
cacheDir </> "remote-repos" </> repoId
localRepoDir :: RepoCache
-> FilePath
localRepoDir (RepoCache cacheDir) =
cacheDir </> "local-repo"
writeRemoteRepoConfig :: RemoteRepo
-> ConfigParser
-> Either CPError ConfigParser
writeRemoteRepoConfig repo cpIn = cpWithRepo
where section = repoId ++ repoSectionSuffix
(RemoteRepo repoId
remoteRootDir
(SshPrivKey keyFile)
(SshRemoteHost (host,port))
(SshRemoteUser user)) = repo
cpWithRepo = do cp1 <- add_section cpIn section
cp2 <- set cp1 section repoRemotePathK remoteRootDir
cp3 <- set cp2 section repoRemoteSshKeyK keyFile
cp4 <- set cp3 section repoRemoteSshHostK host
cp5 <- setshow cp4 section repoRemoteSshPortK port
set cp5 section repoRemoteSshUserK user
lookupRemoteRepo :: [RemoteRepo] -> String -> Maybe RemoteRepo
lookupRemoteRepo repos repoId = lookup repoId repoIdRepoPairs
where repoIdRepoPairs = map (\r@(RemoteRepo rid _ _ _ _) -> (rid,r)) repos
getConfiguredRemoteRepos :: ConfigParser -> [RemoteRepo]
getConfiguredRemoteRepos cp = map parseRepoSection repoSections
where
repoSections =
filter (repoSectionSuffix `isSuffixOf`) (sections cp)
parseRepoSection section =
case parseResult of
Left e -> error ("Error while parsing repo section \""
++ section ++ "\": " ++ show e)
Right r -> r
where
getsec :: Get_C a => OptionSpec -> Either CPError a
getsec = get cp section
parseResult = do
RemoteRepo repoId
<$> getsec repoRemotePathK
<*> (SshPrivKey <$> getsec repoRemoteSshKeyK)
<*> (SshRemoteHost <$> ((,) <$> (getsec repoRemoteSshHostK)
<*> (getsec repoRemoteSshPortK)))
<*> (SshRemoteUser <$> getsec repoRemoteSshUserK)
where
repoId = let prefixLen = length section suffixLen
suffixLen = length repoSectionSuffix
in take prefixLen section
repoSectionSuffix :: String
repoSectionSuffix = "-repo"
repoRemotePathK :: String
repoRemotePathK = "remote_path"
repoRemoteSshKeyK :: String
repoRemoteSshKeyK = "ssh_priv_key_file"
repoRemoteSshHostK :: String
repoRemoteSshHostK = "ssh_remote_host"
repoRemoteSshPortK :: String
repoRemoteSshPortK = "ssh_remote_port"
repoRemoteSshUserK :: String
repoRemoteSshUserK = "ssh_remote_user"