External special remotes can now be built that can be used in readonly mode, where git-annex downloads content from the remote using regular http.

Note that, if an url is added to the web log for such a remote, it's not
distinguishable from another url that might be added for the web remote.
(Because the web log doesn't distinguish which remote owns a plain url.
Urls with a downloader set are distinguishable, but we're not using them
here.)

This seems ok-ish.. In such a case, both remotes will try to use both
urls, and both remotes should be able to.

The only issue I see is that dropping a file from the web remote will
remove both urls in this case. This is not often done, and could even
be considered a feature, I suppose.
This commit is contained in:
Joey Hess 2015-08-17 11:22:22 -04:00
parent 99b9a3f277
commit 3a5b7dbaf0

View file

@ -1,6 +1,6 @@
{- External special remote interface. {- External special remote interface.
- -
- Copyright 2013 Joey Hess <id@joeyh.name> - Copyright 2013-2015 Joey Hess <id@joeyh.name>
- -
- Licensed under the GNU GPL version 3 or higher. - Licensed under the GNU GPL version 3 or higher.
-} -}
@ -13,9 +13,13 @@ import Common.Annex
import Types.Remote import Types.Remote
import Types.CleanupActions import Types.CleanupActions
import Types.UrlContents import Types.UrlContents
import Types.Key
import qualified Git import qualified Git
import Config import Config
import Git.Config (isTrue, boolConfig)
import Remote.Helper.Special import Remote.Helper.Special
import Remote.Helper.ReadOnly
import Remote.Helper.Messages
import Utility.Metered import Utility.Metered
import Messages.Progress import Messages.Progress
import Logs.Transfer import Logs.Transfer
@ -23,6 +27,8 @@ import Logs.PreferredContent.Raw
import Logs.RemoteState import Logs.RemoteState
import Logs.Web import Logs.Web
import Config.Cost import Config.Cost
import Annex.Content
import Annex.Url
import Annex.UUID import Annex.UUID
import Creds import Creds
@ -40,17 +46,34 @@ remote = RemoteType {
} }
gen :: Git.Repo -> UUID -> RemoteConfig -> RemoteGitConfig -> Annex (Maybe Remote) gen :: Git.Repo -> UUID -> RemoteConfig -> RemoteGitConfig -> Annex (Maybe Remote)
gen r u c gc = do gen r u c gc
-- readonly mode only downloads urls; does not use external program
| remoteAnnexReadOnly gc = do
cst <- remoteCost gc expensiveRemoteCost
mk cst GloballyAvailable
readonlyStorer
retrieveUrl
readonlyRemoveKey
(checkKeyUrl r)
Nothing
Nothing
Nothing
| otherwise = do
external <- newExternal externaltype u c external <- newExternal externaltype u c
Annex.addCleanup (RemoteCleanup u) $ stopExternal external Annex.addCleanup (RemoteCleanup u) $ stopExternal external
cst <- getCost external r gc cst <- getCost external r gc
avail <- getAvailability external r gc avail <- getAvailability external r gc
return $ Just $ specialRemote c mk cst avail
(simplyPrepare $ store external) (store external)
(simplyPrepare $ retrieve external) (retrieve external)
(simplyPrepare $ remove external) (remove external)
(simplyPrepare $ checkKey external) (checkKey external)
Remote (Just (whereis external))
(Just (claimurl external))
(Just (checkurl external))
where
mk cst avail tostore toretrieve toremove tocheckkey towhereis toclaimurl tocheckurl = do
let rmt = Remote
{ uuid = u { uuid = u
, cost = cst , cost = cst
, name = Git.repoDescribe r , name = Git.repoDescribe r
@ -60,7 +83,7 @@ gen r u c gc = do
, removeKey = removeKeyDummy , removeKey = removeKeyDummy
, checkPresent = checkPresentDummy , checkPresent = checkPresentDummy
, checkPresentCheap = False , checkPresentCheap = False
, whereisKey = Just $ whereis external , whereisKey = towhereis
, remoteFsck = Nothing , remoteFsck = Nothing
, repairRepo = Nothing , repairRepo = Nothing
, config = c , config = c
@ -73,10 +96,15 @@ gen r u c gc = do
, mkUnavailable = gen r u c $ , mkUnavailable = gen r u c $
gc { remoteAnnexExternalType = Just "!dne!" } gc { remoteAnnexExternalType = Just "!dne!" }
, getInfo = return [("externaltype", externaltype)] , getInfo = return [("externaltype", externaltype)]
, claimUrl = Just (claimurl external) , claimUrl = toclaimurl
, checkUrl = Just (checkurl external) , checkUrl = tocheckurl
} }
where return $ Just $ specialRemote c
(simplyPrepare tostore)
(simplyPrepare toretrieve)
(simplyPrepare toremove)
(simplyPrepare tocheckkey)
rmt
externaltype = fromMaybe (error "missing externaltype") (remoteAnnexExternalType gc) externaltype = fromMaybe (error "missing externaltype") (remoteAnnexExternalType gc)
externalSetup :: Maybe UUID -> Maybe CredPair -> RemoteConfig -> Annex (RemoteConfig, UUID) externalSetup :: Maybe UUID -> Maybe CredPair -> RemoteConfig -> Annex (RemoteConfig, UUID)
@ -86,12 +114,17 @@ externalSetup mu _ c = do
M.lookup "externaltype" c M.lookup "externaltype" c
(c', _encsetup) <- encryptionSetup c (c', _encsetup) <- encryptionSetup c
c'' <- case M.lookup "readonly" c of
Just v | isTrue v == Just True -> do
setConfig (remoteConfig (fromJust (M.lookup "name" c)) "readonly") (boolConfig True)
return c'
_ -> do
external <- newExternal externaltype u c' external <- newExternal externaltype u c'
handleRequest external INITREMOTE Nothing $ \resp -> case resp of handleRequest external INITREMOTE Nothing $ \resp -> case resp of
INITREMOTE_SUCCESS -> Just noop INITREMOTE_SUCCESS -> Just noop
INITREMOTE_FAILURE errmsg -> Just $ error errmsg INITREMOTE_FAILURE errmsg -> Just $ error errmsg
_ -> Nothing _ -> Nothing
c'' <- liftIO $ atomically $ readTMVar $ externalConfig external liftIO $ atomically $ readTMVar $ externalConfig external
gitConfigSpecialRemote u c'' "externaltype" externaltype gitConfigSpecialRemote u c'' "externaltype" externaltype
return (c'', u) return (c'', u)
@ -467,3 +500,20 @@ checkurl external url =
_ -> Nothing _ -> Nothing
where where
mkmulti (u, s, f) = (u, s, mkSafeFilePath f) mkmulti (u, s, f) = (u, s, mkSafeFilePath f)
retrieveUrl :: Retriever
retrieveUrl = fileRetriever $ \f k _p -> do
us <- getWebUrls k
unlessM (downloadUrl us f) $
error "failed to download content"
checkKeyUrl :: Git.Repo -> CheckPresent
checkKeyUrl r k = do
showChecking r
us <- getWebUrls k
anyM (\u -> withUrlOptions $ checkBoth u (keySize k)) us
getWebUrls :: Key -> Annex [URLString]
getWebUrls key = filter supported <$> getUrls key
where
supported u = snd (getDownloader u) == WebDownloader