Skip to content
Snippets Groups Projects
Backend.hs 3.54 KiB
Newer Older
{- git-annex key/value backends
Joey Hess's avatar
Joey Hess committed
 -
 - Copyright 2010 Joey Hess <joey@kitenet.net>
 -
 - Licensed under the GNU GPL version 3 or higher.
 -}
Joey Hess's avatar
Joey Hess committed

Joey Hess's avatar
Joey Hess committed
module Backend (
Joey Hess's avatar
Joey Hess committed
	BackendFile,
	orderedList,
	genKey,
	lookupFile,
Joey Hess's avatar
Joey Hess committed
	chooseBackends,
Joey Hess's avatar
Joey Hess committed
	lookupBackendName,
	maybeLookupBackendName
Joey Hess's avatar
Joey Hess committed
) where
Joey Hess's avatar
Joey Hess committed

Joey Hess's avatar
Joey Hess committed
import System.IO.Error (try)
import System.Posix.Files
Joey Hess's avatar
Joey Hess committed

Joey Hess's avatar
Joey Hess committed
import Common.Annex
Joey Hess's avatar
Joey Hess committed
import qualified Git
import qualified Annex
import Types.Key
import qualified Types.Backend as B

-- When adding a new backend, import it here and add it to the list.
import qualified Backend.WORM
import qualified Backend.SHA

list :: [Backend Annex]
list = Backend.WORM.backends ++ Backend.SHA.backends ++ Backend.URL.backends
Joey Hess's avatar
Joey Hess committed

{- List of backends in the order to try them when storing a new key. -}
orderedList :: Annex [Backend Annex]
orderedList = do
	l <- Annex.getState Annex.backends -- list is cached here
Joey Hess's avatar
Joey Hess committed
	if not $ null l
Joey Hess's avatar
Joey Hess committed
		then return l
		else do
Joey Hess's avatar
Joey Hess committed
			s <- getstandard
			d <- Annex.getState Annex.forcebackend
Joey Hess's avatar
Joey Hess committed
			handle d s
	where
		parseBackendList [] = list
		parseBackendList s = map lookupBackendName $ words s
Joey Hess's avatar
Joey Hess committed
		handle Nothing s = return s
		handle (Just "") s = return s
		handle (Just name) s = do
Joey Hess's avatar
Joey Hess committed
			let l' = lookupBackendName name : s
Joey Hess's avatar
Joey Hess committed
			Annex.changeState $ \state -> state { Annex.backends = l' }
Joey Hess's avatar
Joey Hess committed
		getstandard = do
Joey Hess's avatar
Joey Hess committed
			g <- gitRepo
			return $ parseBackendList $
Joey Hess's avatar
Joey Hess committed
				Git.configGet g "annex.backends" ""
{- Generates a key for a file, trying each backend in turn until one
 - accepts it. -}
genKey :: FilePath -> Maybe (Backend Annex) -> Annex (Maybe (Key, Backend Annex))
genKey file trybackend = do
	bs <- orderedList
Joey Hess's avatar
Joey Hess committed
	let bs' = maybe bs (: bs) trybackend
	genKey' bs' file
genKey' :: [Backend Annex] -> FilePath -> Annex (Maybe (Key, Backend Annex))
genKey' [] _ = return Nothing
genKey' (b:bs) file = do
	r <- (B.getKey b) file
	case r of
		Nothing -> genKey' bs file
		Just k -> return $ Just (k, b)
Joey Hess's avatar
Joey Hess committed
{- Looks up the key and backend corresponding to an annexed file,
 - by examining what the file symlinks to. -}
Joey Hess's avatar
Joey Hess committed
lookupFile :: FilePath -> Annex (Maybe (Key, Backend Annex))
Joey Hess's avatar
Joey Hess committed
lookupFile file = do
	tl <- liftIO $ try getsymlink
	case tl of
Joey Hess's avatar
Joey Hess committed
		Left _ -> return Nothing
		Right l -> makekey l
	where
		getsymlink = takeFileName <$> readSymbolicLink file
		makekey l = maybe (return Nothing) (makeret l) (fileKey l)
		makeret l k =
			case maybeLookupBackendName bname of
Joey Hess's avatar
Joey Hess committed
					Just backend -> return $ Just (k, backend)
					Nothing -> do
						when (isLinkToAnnex l) $
							warning skip
						return Nothing
Joey Hess's avatar
Joey Hess committed
			where
Joey Hess's avatar
Joey Hess committed
				bname = keyBackendName k
				skip = "skipping " ++ file ++ 
					" (unknown backend " ++ bname ++ ")"
Joey Hess's avatar
Joey Hess committed
type BackendFile = (Maybe (Backend Annex), FilePath)

{- Looks up the backends that should be used for each file in a list.
 - That can be configured on a per-file basis in the gitattributes file.
 -}
Joey Hess's avatar
Joey Hess committed
chooseBackends :: [FilePath] -> Annex [BackendFile]
chooseBackends fs = do
Joey Hess's avatar
Joey Hess committed
	g <- gitRepo
	forced <- Annex.getState Annex.forcebackend
Joey Hess's avatar
Joey Hess committed
	if isJust forced
			l <- orderedList
Joey Hess's avatar
Joey Hess committed
			return $ map (\f -> (Just $ head l, f)) fs
		else do
			pairs <- liftIO $ Git.checkAttr g "annex.backend" fs
Joey Hess's avatar
Joey Hess committed
			return $ map (\(f,b) -> (maybeLookupBackendName b, f)) pairs
{- Looks up a backend by name. May fail if unknown. -}
lookupBackendName :: String -> Backend Annex
Joey Hess's avatar
Joey Hess committed
lookupBackendName s = fromMaybe unknown $ maybeLookupBackendName s
	where
		unknown = error $ "unknown backend " ++ s
maybeLookupBackendName :: String -> Maybe (Backend Annex)
Joey Hess's avatar
Joey Hess committed
maybeLookupBackendName s
	| length matches == 1 = Just $ head matches
	| otherwise = Nothing
	where matches = filter (\b -> s == B.name b) list