implemented remotes config caching
This commit is contained in:
parent
89654751da
commit
912d10e78b
3 changed files with 74 additions and 34 deletions
|
@ -43,16 +43,20 @@ copyKeyFile key file = do
|
||||||
if (0 == length remotes)
|
if (0 == length remotes)
|
||||||
then error $ "no known remotes have: " ++ (keyFile key) ++ "\n" ++
|
then error $ "no known remotes have: " ++ (keyFile key) ++ "\n" ++
|
||||||
"(Perhaps you need to git remote add a repository?)"
|
"(Perhaps you need to git remote add a repository?)"
|
||||||
else liftIO $ trycopy remotes remotes
|
else trycopy remotes remotes
|
||||||
where
|
where
|
||||||
trycopy full [] = error $ "unable to get: " ++ (keyFile key) ++ "\n" ++
|
trycopy full [] = error $ "unable to get: " ++ (keyFile key) ++ "\n" ++
|
||||||
"To get that file, need access to one of these remotes: " ++
|
"To get that file, need access to one of these remotes: " ++
|
||||||
(remotesList full)
|
(remotesList full)
|
||||||
trycopy full (r:rs) = do
|
trycopy full (r:rs) = do
|
||||||
result <- try (copyFromRemote r key file)::IO (Either SomeException ())
|
-- annexLocation needs the git config to have been
|
||||||
|
-- read for a remote, so do that now,
|
||||||
|
-- if it hasn't been already
|
||||||
|
r' <- remoteEnsureGitConfigRead r
|
||||||
|
result <- liftIO $ (try (copyFromRemote r' key file)::IO (Either SomeException ()))
|
||||||
case (result) of
|
case (result) of
|
||||||
Left err -> do
|
Left err -> do
|
||||||
hPutStrLn stderr (show err)
|
liftIO $ hPutStrLn stderr (show err)
|
||||||
trycopy full rs
|
trycopy full rs
|
||||||
Right succ -> return True
|
Right succ -> return True
|
||||||
|
|
||||||
|
@ -61,19 +65,11 @@ copyFromRemote :: GitRepo -> Key -> FilePath -> IO ()
|
||||||
copyFromRemote r key file = do
|
copyFromRemote r key file = do
|
||||||
putStrLn $ "copy from " ++ (gitRepoDescribe r ) ++ " " ++ file
|
putStrLn $ "copy from " ++ (gitRepoDescribe r ) ++ " " ++ file
|
||||||
|
|
||||||
-- annexLocation needs the git config read for the remote first.
|
if (gitRepoIsLocal r)
|
||||||
-- FIXME: Having this here means git-config is run repeatedly when
|
then getlocal
|
||||||
-- copying a series of files; need to use state monad to avoid
|
else getremote
|
||||||
-- this.
|
|
||||||
r' <- gitConfigRead r
|
|
||||||
|
|
||||||
_ <- if (gitRepoIsLocal r')
|
|
||||||
then getlocal r'
|
|
||||||
else getremote r'
|
|
||||||
return ()
|
return ()
|
||||||
where
|
where
|
||||||
getlocal r = do
|
getlocal = rawSystem "cp" ["-a", location, file]
|
||||||
rawSystem "cp" ["-a", location r, file]
|
getremote = error "get via network not yet implemented!"
|
||||||
getremote r = do
|
location = annexLocation r backend key
|
||||||
error "get via network not yet implemented!"
|
|
||||||
location r = annexLocation r backend key
|
|
||||||
|
|
50
GitRepo.hs
50
GitRepo.hs
|
@ -12,15 +12,17 @@ module GitRepo (
|
||||||
gitRepoFromUrl,
|
gitRepoFromUrl,
|
||||||
gitRepoIsLocal,
|
gitRepoIsLocal,
|
||||||
gitRepoIsRemote,
|
gitRepoIsRemote,
|
||||||
gitConfigRemotes,
|
|
||||||
gitRepoDescribe,
|
gitRepoDescribe,
|
||||||
gitWorkTree,
|
gitWorkTree,
|
||||||
gitDir,
|
gitDir,
|
||||||
gitRelative,
|
gitRelative,
|
||||||
gitConfig,
|
gitConfig,
|
||||||
|
gitConfigMap,
|
||||||
gitConfigRead,
|
gitConfigRead,
|
||||||
gitRun,
|
gitRun,
|
||||||
gitAttributes,
|
gitAttributes,
|
||||||
|
gitRepoRemotes,
|
||||||
|
gitRepoRemotesAdd,
|
||||||
gitRepoRemoteName
|
gitRepoRemoteName
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
@ -46,12 +48,14 @@ data GitRepo =
|
||||||
LocalGitRepo {
|
LocalGitRepo {
|
||||||
top :: FilePath,
|
top :: FilePath,
|
||||||
config :: Map String String,
|
config :: Map String String,
|
||||||
|
remotes :: [GitRepo],
|
||||||
-- remoteName holds the name used for this repo in remotes
|
-- remoteName holds the name used for this repo in remotes
|
||||||
remoteName :: Maybe String
|
remoteName :: Maybe String
|
||||||
} | RemoteGitRepo {
|
} | RemoteGitRepo {
|
||||||
url :: String,
|
url :: String,
|
||||||
top :: FilePath,
|
top :: FilePath,
|
||||||
config :: Map String String,
|
config :: Map String String,
|
||||||
|
remotes :: [GitRepo],
|
||||||
remoteName :: Maybe String
|
remoteName :: Maybe String
|
||||||
} deriving (Show, Read, Eq)
|
} deriving (Show, Read, Eq)
|
||||||
|
|
||||||
|
@ -61,6 +65,7 @@ gitRepoFromPath dir =
|
||||||
LocalGitRepo {
|
LocalGitRepo {
|
||||||
top = dir,
|
top = dir,
|
||||||
config = Map.empty,
|
config = Map.empty,
|
||||||
|
remotes = [],
|
||||||
remoteName = Nothing
|
remoteName = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +76,7 @@ gitRepoFromUrl url =
|
||||||
url = url,
|
url = url,
|
||||||
top = path url,
|
top = path url,
|
||||||
config = Map.empty,
|
config = Map.empty,
|
||||||
|
remotes = [],
|
||||||
remoteName = Nothing
|
remoteName = Nothing
|
||||||
}
|
}
|
||||||
where path url = uriPath $ fromJust $ parseURI url
|
where path url = uriPath $ fromJust $ parseURI url
|
||||||
|
@ -83,6 +89,15 @@ gitRepoDescribe repo =
|
||||||
then top repo
|
then top repo
|
||||||
else url repo
|
else url repo
|
||||||
|
|
||||||
|
{- Returns the list of a repo's remotes. -}
|
||||||
|
gitRepoRemotes :: GitRepo -> [GitRepo]
|
||||||
|
gitRepoRemotes r = remotes r
|
||||||
|
|
||||||
|
{- Constructs and returns an updated version of a repo with
|
||||||
|
- different remotes list. -}
|
||||||
|
gitRepoRemotesAdd :: GitRepo -> [GitRepo] -> GitRepo
|
||||||
|
gitRepoRemotesAdd repo rs = repo { remotes = rs }
|
||||||
|
|
||||||
{- Returns the name of the remote that corresponds to the repo, if
|
{- Returns the name of the remote that corresponds to the repo, if
|
||||||
- it is a remote. Otherwise, "" -}
|
- it is a remote. Otherwise, "" -}
|
||||||
gitRepoRemoteName r =
|
gitRepoRemoteName r =
|
||||||
|
@ -169,10 +184,24 @@ gitConfigRead repo = assertlocal repo $ do
|
||||||
been already read. Instead, chdir to the repo. -}
|
been already read. Instead, chdir to the repo. -}
|
||||||
cwd <- getCurrentDirectory
|
cwd <- getCurrentDirectory
|
||||||
bracket_ (changeWorkingDirectory (top repo))
|
bracket_ (changeWorkingDirectory (top repo))
|
||||||
(\_ -> changeWorkingDirectory cwd) $ do
|
(\_ -> changeWorkingDirectory cwd) $
|
||||||
pOpen ReadFromPipe "git" ["config", "--list"] $ \h -> do
|
pOpen ReadFromPipe "git" ["config", "--list"] $ \h -> do
|
||||||
val <- hGetContentsStrict h
|
val <- hGetContentsStrict h
|
||||||
return repo { config = gitConfigParse val }
|
let r = repo { config = gitConfigParse val }
|
||||||
|
return r { remotes = gitConfigRemotes r }
|
||||||
|
|
||||||
|
{- Calculates a list of a repo's configured remotes, by parsing its config. -}
|
||||||
|
gitConfigRemotes :: GitRepo -> [GitRepo]
|
||||||
|
gitConfigRemotes repo = map construct remotes
|
||||||
|
where
|
||||||
|
remotes = toList $ filter $ config repo
|
||||||
|
filter = filterWithKey (\k _ -> isremote k)
|
||||||
|
isremote k = (startswith "remote." k) && (endswith ".url" k)
|
||||||
|
remotename k = (split "." k) !! 1
|
||||||
|
construct (k,v) = (gen v) { remoteName = Just $ remotename k }
|
||||||
|
gen v = if (isURI v)
|
||||||
|
then gitRepoFromUrl v
|
||||||
|
else gitRepoFromPath v
|
||||||
|
|
||||||
{- Parses git config --list output into a config map. -}
|
{- Parses git config --list output into a config map. -}
|
||||||
gitConfigParse :: String -> Map.Map String String
|
gitConfigParse :: String -> Map.Map String String
|
||||||
|
@ -189,18 +218,9 @@ gitConfig :: GitRepo -> String -> String -> String
|
||||||
gitConfig repo key defaultValue =
|
gitConfig repo key defaultValue =
|
||||||
Map.findWithDefault defaultValue key (config repo)
|
Map.findWithDefault defaultValue key (config repo)
|
||||||
|
|
||||||
{- Returns a list of a repo's configured remotes. -}
|
{- Access to raw config Map -}
|
||||||
gitConfigRemotes :: GitRepo -> [GitRepo]
|
gitConfigMap :: GitRepo -> Map String String
|
||||||
gitConfigRemotes repo = map construct remotes
|
gitConfigMap repo = config repo
|
||||||
where
|
|
||||||
remotes = toList $ filter $ config repo
|
|
||||||
filter = filterWithKey (\k _ -> isremote k)
|
|
||||||
isremote k = (startswith "remote." k) && (endswith ".url" k)
|
|
||||||
remotename k = (split "." k) !! 1
|
|
||||||
construct (k,v) = (gen v) { remoteName = Just $ remotename k }
|
|
||||||
gen v = if (isURI v)
|
|
||||||
then gitRepoFromUrl v
|
|
||||||
else gitRepoFromPath v
|
|
||||||
|
|
||||||
{- Finds the current git repository, which may be in a parent directory. -}
|
{- Finds the current git repository, which may be in a parent directory. -}
|
||||||
gitRepoFromCwd :: IO GitRepo
|
gitRepoFromCwd :: IO GitRepo
|
||||||
|
|
28
Remotes.hs
28
Remotes.hs
|
@ -2,10 +2,12 @@
|
||||||
|
|
||||||
module Remotes (
|
module Remotes (
|
||||||
remotesList,
|
remotesList,
|
||||||
remotesWithKey
|
remotesWithKey,
|
||||||
|
remoteEnsureGitConfigRead
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.State (liftIO)
|
import Control.Monad.State (liftIO)
|
||||||
|
import qualified Data.Map as Map
|
||||||
import Types
|
import Types
|
||||||
import GitRepo
|
import GitRepo
|
||||||
import LocationLog
|
import LocationLog
|
||||||
|
@ -29,7 +31,7 @@ remotesWithKey key = do
|
||||||
remotesByCost :: Annex [GitRepo]
|
remotesByCost :: Annex [GitRepo]
|
||||||
remotesByCost = do
|
remotesByCost = do
|
||||||
g <- gitAnnex
|
g <- gitAnnex
|
||||||
reposByCost $ gitConfigRemotes g
|
reposByCost $ gitRepoRemotes g
|
||||||
|
|
||||||
{- Orders a list of git repos by cost. -}
|
{- Orders a list of git repos by cost. -}
|
||||||
reposByCost :: [GitRepo] -> Annex [GitRepo]
|
reposByCost :: [GitRepo] -> Annex [GitRepo]
|
||||||
|
@ -58,3 +60,25 @@ repoCost r = do
|
||||||
where
|
where
|
||||||
config g r = gitConfig g (configkey r) ""
|
config g r = gitConfig g (configkey r) ""
|
||||||
configkey r = "remote." ++ (gitRepoRemoteName r) ++ ".annex-cost"
|
configkey r = "remote." ++ (gitRepoRemoteName r) ++ ".annex-cost"
|
||||||
|
|
||||||
|
{- The git configs for the git repo's remotes is not read on startup
|
||||||
|
- because reading it may be expensive. This function ensures that it is
|
||||||
|
- read for a specified remote, and updates state. It returns the
|
||||||
|
- updated git repo also. -}
|
||||||
|
remoteEnsureGitConfigRead :: GitRepo -> Annex GitRepo
|
||||||
|
remoteEnsureGitConfigRead r = do
|
||||||
|
if (Map.null $ gitConfigMap r)
|
||||||
|
then do
|
||||||
|
r' <- liftIO $ gitConfigRead r
|
||||||
|
g <- gitAnnex
|
||||||
|
let l = gitRepoRemotes g
|
||||||
|
let g' = gitRepoRemotesAdd g $ exchange l r'
|
||||||
|
gitAnnexChange g'
|
||||||
|
return r'
|
||||||
|
else return r
|
||||||
|
where
|
||||||
|
exchange [] new = []
|
||||||
|
exchange (old:ls) new =
|
||||||
|
if ((gitRepoRemoteName old) == (gitRepoRemoteName new))
|
||||||
|
then new:(exchange ls new)
|
||||||
|
else old:(exchange ls new)
|
||||||
|
|
Loading…
Reference in a new issue