git-annex/Remotes.hs

147 lines
4.5 KiB
Haskell
Raw Normal View History

{- git-annex remote repositories -}
module Remotes (
2010-10-14 06:41:54 +00:00
list,
withKey,
tryGitConfigRead
) where
2010-10-16 21:44:59 +00:00
import Control.Exception
2010-10-14 01:28:47 +00:00
import Control.Monad.State (liftIO)
import Control.Monad (filterM)
2010-10-14 02:59:43 +00:00
import qualified Data.Map as Map
2010-10-14 03:18:58 +00:00
import Data.String.Utils
import Data.Either.Utils
import List
import Maybe
2010-10-16 20:20:49 +00:00
2010-10-14 07:18:11 +00:00
import Types
2010-10-14 06:36:41 +00:00
import qualified GitRepo as Git
2010-10-14 07:18:11 +00:00
import qualified Annex
import LocationLog
2010-10-14 03:18:58 +00:00
import Locations
import UUID
import Core
{- Human visible list of remotes. -}
2010-10-14 06:41:54 +00:00
list :: [Git.Repo] -> String
2010-10-22 19:21:23 +00:00
list remotes = join ", " $ map Git.repoDescribe remotes
{- Cost ordered list of remotes that the LocationLog indicate may have a key. -}
2010-10-14 06:41:54 +00:00
withKey :: Key -> Annex [Git.Repo]
withKey key = do
2010-10-14 07:18:11 +00:00
g <- Annex.gitRepo
2010-10-14 01:28:47 +00:00
uuids <- liftIO $ keyLocations g key
2010-10-14 03:18:58 +00:00
allremotes <- remotesByCost
-- To determine if a remote has a key, its UUID needs to be known.
-- The locally cached UIIDs of remotes can fall out of date if
-- eg, a different drive is mounted at the same location.
-- But, reading the config of remotes can be expensive, so make
-- sure we only do it once per git-annex run.
remotesread <- Annex.flagIsSet "remotesread"
if (remotesread)
then reposByUUID allremotes uuids
else do
-- We assume that it's cheap to read the config
-- of non-URL remotes, so that is done each time.
-- But reading the config of an URL remote is
-- only done when there is no cached UUID value.
let cheap = filter (not . Git.repoIsUrl) allremotes
let expensive = filter Git.repoIsUrl allremotes
doexpensive <- filterM cachedUUID expensive
2010-10-23 00:47:14 +00:00
if (not $ null doexpensive)
then showNote $ "getting UUIDs for " ++ (list doexpensive) ++ "..."
else return ()
let todo = cheap ++ doexpensive
2010-10-23 00:47:14 +00:00
if (not $ null todo)
then do
e <- mapM tryGitConfigRead todo
Annex.flagChange "remotesread" $ FlagBool True
withKey key
else reposByUUID allremotes uuids
where
cachedUUID r = do
u <- getUUID r
2010-10-23 00:47:14 +00:00
return $ null u
{- Cost Ordered list of remotes. -}
2010-10-14 06:36:41 +00:00
remotesByCost :: Annex [Git.Repo]
2010-10-14 01:28:47 +00:00
remotesByCost = do
2010-10-14 07:18:11 +00:00
g <- Annex.gitRepo
2010-10-14 06:36:41 +00:00
reposByCost $ Git.remotes g
{- Orders a list of git repos by cost. Throws out ignored ones. -}
2010-10-14 06:36:41 +00:00
reposByCost :: [Git.Repo] -> Annex [Git.Repo]
2010-10-14 01:28:47 +00:00
reposByCost l = do
notignored <- filterM repoNotIgnored l
costpairs <- mapM costpair notignored
2010-10-14 01:28:47 +00:00
return $ fst $ unzip $ sortBy bycost $ costpairs
where
2010-10-14 01:28:47 +00:00
costpair r = do
cost <- repoCost r
return (r, cost)
bycost (_, c1) (_, c2) = compare c1 c2
{- Calculates cost for a repo.
-
- The default cost is 100 for local repositories, and 200 for remote
- repositories; it can also be configured by remote.<name>.annex-cost
-}
2010-10-14 06:36:41 +00:00
repoCost :: Git.Repo -> Annex Int
2010-10-14 01:28:47 +00:00
repoCost r = do
2010-10-14 07:18:11 +00:00
g <- Annex.gitRepo
2010-10-23 00:47:14 +00:00
if (not $ null $ config g r)
2010-10-14 01:28:47 +00:00
then return $ read $ config g r
else if (Git.repoIsUrl r)
then return 200
else return 100
where
2010-10-14 06:36:41 +00:00
config g r = Git.configGet g (configkey r) ""
configkey r = "remote." ++ (Git.repoRemoteName r) ++ ".annex-cost"
2010-10-14 02:59:43 +00:00
{- Checks if a repo should be ignored, based either on annex-ignore
- setting, or on command-line options. Allows command-line to override
- annex-ignore. -}
repoNotIgnored :: Git.Repo -> Annex Bool
repoNotIgnored r = do
g <- Annex.gitRepo
fromName <- Annex.flagGet "fromrepository"
toName <- Annex.flagGet "torepository"
let name = if (not $ null fromName) then fromName else toName
if (not $ null name)
then return $ match name
else return $ notignored g
where
match name = name == Git.repoRemoteName r
notignored g = "true" /= config g
config g = Git.configGet g configkey ""
configkey = "remote." ++ (Git.repoRemoteName r) ++ ".annex-ignore"
2010-10-14 02:59:43 +00:00
{- The git configs for the git repo's remotes is not read on startup
- because reading it may be expensive. This function tries to read the
- config for a specified remote, and updates state. If successful, it
- returns the updated git repo. -}
tryGitConfigRead :: Git.Repo -> Annex (Either Git.Repo Git.Repo)
tryGitConfigRead r = do
2010-10-14 06:36:41 +00:00
if (Map.null $ Git.configMap r)
2010-10-14 02:59:43 +00:00
then do
2010-10-16 21:44:59 +00:00
-- configRead can fail due to IO error or
-- for other reasons; catch all possible exceptions
result <- liftIO $ (try (Git.configRead r)::IO (Either SomeException (Git.Repo)))
case (result) of
Left e -> return $ Left r
Right r' -> do
g <- Annex.gitRepo
let l = Git.remotes g
let g' = Git.remotesAdd g $
exchange l r'
Annex.gitRepoChange g'
return $ Right r'
else return $ Right r -- config already read
2010-10-14 02:59:43 +00:00
where
exchange [] new = []
exchange (old:ls) new =
2010-10-14 06:36:41 +00:00
if ((Git.repoRemoteName old) == (Git.repoRemoteName new))
2010-10-14 02:59:43 +00:00
then new:(exchange ls new)
else old:(exchange ls new)