importTree = fromMaybe False . getRemoteConfigValue importTreeField
{- Parsers for fields that are common to all special remotes. -}
-commonFieldsParser :: [RemoteConfigParser]
-commonFieldsParser =
+commonFieldParsers :: [RemoteConfigFieldParser]
+commonFieldParsers =
[ optionalStringParser nameField
, optionalStringParser sameasNameField
, optionalStringParser sameasUUIDField
]
Nothing -> Nothing
-parseRemoteConfig :: RemoteConfig -> [RemoteConfigParser] -> Either String ParsedRemoteConfig
-parseRemoteConfig c ps =
- go [] (M.filterWithKey notaccepted c) (ps ++ commonFieldsParser)
+parseRemoteConfig :: RemoteConfig -> RemoteConfigParser -> Either String ParsedRemoteConfig
+parseRemoteConfig c rpc =
+ go [] (M.filterWithKey notaccepted c) (remoteConfigFieldParsers rpc ++ commonFieldParsers)
where
go l c' []
+ | remoteConfigRestPassthrough rpc = Right $ M.fromList $
+ l ++ map (uncurry passthrough) (M.toList c')
| M.null c' = Right (M.fromList l)
| otherwise = Left $ "Unexpected fields: " ++
unwords (map fromProposedAccepted (M.keys c'))
case v of
Just v' -> go ((f,v'):l) (M.delete f c') rest
Nothing -> go l (M.delete f c') rest
+
+ passthrough f v = (f, RemoteConfigValue (fromProposedAccepted v))
+
notaccepted (Proposed _) _ = True
notaccepted (Accepted _) _ = False
-optionalStringParser :: RemoteConfigField -> RemoteConfigParser
+optionalStringParser :: RemoteConfigField -> RemoteConfigFieldParser
optionalStringParser f = (f, p)
where
p (Just v) _c = Right (Just (RemoteConfigValue (fromProposedAccepted v)))
p Nothing _c = Right Nothing
-yesNoParser :: RemoteConfigField -> Bool -> RemoteConfigParser
+yesNoParser :: RemoteConfigField -> Bool -> RemoteConfigFieldParser
yesNoParser = genParser yesNo "yes or no"
-trueFalseParser :: RemoteConfigField -> Bool -> RemoteConfigParser
+trueFalseParser :: RemoteConfigField -> Bool -> RemoteConfigFieldParser
trueFalseParser = genParser Git.Config.isTrueFalse "true or false"
genParser
-> String -- ^ description of the value
-> RemoteConfigField
-> t -- ^ fallback value
- -> RemoteConfigParser
+ -> RemoteConfigFieldParser
genParser parse desc f fallback = (f, p)
where
p Nothing _c = Right (Just (RemoteConfigValue fallback))
{- Credentials storage
-
- - Copyright 2012-2014 Joey Hess <id@joeyh.name>
+ - Copyright 2012-2020 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
import Crypto
import Types.Remote (RemoteConfig, RemoteConfigField)
import Types.ProposedAccepted
-import Remote.Helper.Encryptable (remoteCipher, remoteCipher', embedCreds, EncryptionIsSetup, extractCipher, encryptionConfigParser)
+import Remote.Helper.Encryptable (remoteCipher, remoteCipher', embedCreds, EncryptionIsSetup, extractCipher, parseEncryptionConfig)
import Utility.Env (getEnv)
import qualified Data.ByteString.Lazy.Char8 as L
storeconfig creds key Nothing =
return $ M.insert key (Accepted (toB64 $ encodeCredPair creds)) c
- pc = either (const mempty) id
- (parseRemoteConfig c encryptionConfigParser)
+ pc = either (const mempty) id (parseEncryptionConfig c)
{- Gets a remote's credpair, from the environment if set, otherwise
- from the cache in gitAnnexCredsDir, or failing that, from the
{ typename = "directory"
, enumerate = const (findSpecialRemotes "directory")
, generate = gen
- , configParser = [optionalStringParser directoryField]
+ , configParser = mkRemoteConfigParser
+ [optionalStringParser directoryField]
, setup = directorySetup
, exportSupported = exportIsSupported
, importSupported = importIsSupported
-- and will call our gen on them.
, enumerate = const (return [])
, generate = gen
- , configParser = [optionalStringParser gitRepoField]
+ , configParser = mkRemoteConfigParser
+ [optionalStringParser gitRepoField]
, setup = gCryptSetup
, exportSupported = exportUnsupported
, importSupported = importUnsupported
v <- M.lookup u' <$> readRemoteLog
case (Git.remoteName baser, v) of
(Just remotename, Just c') -> do
- pc <- either giveup return $
- parseRemoteConfig c' (configParser remote)
+ pc <- either giveup return
+ . parseRemoteConfig c'
+ =<< configParser remote
setGcryptEncryption pc remotename
storeUUIDIn (remoteConfig baser "uuid") u'
setConfig (Git.GCrypt.remoteConfigKey "gcrypt-id" remotename) gcryptid
| Git.repoLocation r == url -> noop
| otherwise -> error "Another remote with the same name already exists."
- pc <- either giveup return $
- parseRemoteConfig c' (configParser remote)
+ pc <- either giveup return . parseRemoteConfig c'
+ =<< configParser remote
setGcryptEncryption pc remotename
{- Run a git fetch and a push to the git repo in order to get
{ typename = "git"
, enumerate = list
, generate = gen
- , configParser = [optionalStringParser locationField]
+ , configParser = mkRemoteConfigParser
+ [optionalStringParser locationField]
, setup = gitSetup
, exportSupported = exportUnsupported
, importSupported = importUnsupported
-- and will call our gen on them.
, enumerate = const (return [])
, generate = gen
- , configParser = [optionalStringParser urlField]
+ , configParser = mkRemoteConfigParser
+ [optionalStringParser urlField]
, setup = mySetup
, exportSupported = exportUnsupported
, importSupported = importUnsupported
u <- maybe (liftIO genUUID) return mu
(c', _encsetup) <- encryptionSetup c gc
- pc <- either giveup return $ parseRemoteConfig c' (configParser remote)
+ pc <- either giveup return . parseRemoteConfig c' =<< configParser remote
case (isEncrypted pc, Git.GCrypt.urlPrefix `isPrefixOf` url) of
(False, False) -> noop
(True, True) -> Remote.GCrypt.setGcryptEncryption pc remotename
ChunkConfig(..),
noChunks,
describeChunkConfig,
- chunkConfigParser,
+ chunkConfigParsers,
getChunkConfig,
storeChunks,
removeChunks,
noChunks NoChunks = True
noChunks _ = False
-chunkConfigParser :: [RemoteConfigParser]
-chunkConfigParser =
+chunkConfigParsers :: [RemoteConfigFieldParser]
+chunkConfigParsers =
[ optionalStringParser chunksizeField
, optionalStringParser chunkField
]
encryptionSetup,
noEncryptionUsed,
encryptionAlreadySetup,
- encryptionConfigParser,
+ encryptionConfigParsers,
parseEncryptionConfig,
remoteCipher,
remoteCipher',
encryptionAlreadySetup :: EncryptionIsSetup
encryptionAlreadySetup = EncryptionIsSetup
-encryptionConfigParser :: [RemoteConfigParser]
-encryptionConfigParser =
+encryptionConfigParsers :: [RemoteConfigFieldParser]
+encryptionConfigParsers =
[ (encryptionField, \v c -> Just . RemoteConfigValue <$> parseEncryptionMethod (fmap fromProposedAccepted v) c)
, optionalStringParser cipherField
, optionalStringParser cipherkeysField
]
encryptionConfigs :: S.Set RemoteConfigField
-encryptionConfigs = S.fromList (map fst encryptionConfigParser)
+encryptionConfigs = S.fromList (map fst encryptionConfigParsers)
-- Parse only encryption fields, ignoring all others.
parseEncryptionConfig :: RemoteConfig -> Either String ParsedRemoteConfig
-parseEncryptionConfig c = parseRemoteConfig (M.restrictKeys c encryptionConfigs) encryptionConfigParser
+parseEncryptionConfig c = parseRemoteConfig
+ (M.restrictKeys c encryptionConfigs)
+ (RemoteConfigParser encryptionConfigParsers False)
parseEncryptionMethod :: Maybe String -> RemoteConfig -> Either String EncryptionMethod
parseEncryptionMethod (Just "none") _ = Right NoneEncryption
, configParser = configparser
}
where
- configparser = configParser rt ++ exportImportConfigParser
+ configparser = addRemoteConfigParser exportImportConfigParsers
+ <$> configParser rt
setup' st mu cp c gc = do
- pc <- either giveup return $ parseRemoteConfig c configparser
+ pc <- either giveup return . parseRemoteConfig c =<< configparser
let checkconfig supported configured configfield cont =
ifM (supported rt pc gc)
( case st of
| configured pc && isEncrypted pc ->
giveup $ "cannot enable both encryption and " ++ fromProposedAccepted configfield
| otherwise -> cont
- Enable oldc ->
- let oldpc = either mempty id $ parseRemoteConfig oldc configparser
- in if configured pc /= configured oldpc
+ Enable oldc -> do
+ oldpc <- either mempty id . parseRemoteConfig oldc <$> configparser
+ if configured pc /= configured oldpc
then giveup $ "cannot change " ++ fromProposedAccepted configfield ++ " of existing special remote"
else cont
, if configured pc
then giveup "cannot enable importtree=yes without also enabling exporttree=yes"
else setup rt st mu cp c gc
-exportImportConfigParser :: [RemoteConfigParser]
-exportImportConfigParser =
+exportImportConfigParsers :: [RemoteConfigFieldParser]
+exportImportConfigParsers =
[ yesNoParser exportTreeField False
, yesNoParser importTreeField False
]
retreiveKeyFileDummy,
removeKeyDummy,
checkPresentDummy,
- specialRemoteConfigParser,
SpecialRemoteCfg(..),
specialRemoteCfg,
specialRemoteType,
-- Modifies a base RemoteType to support chunking and encryption configs.
specialRemoteType :: RemoteType -> RemoteType
specialRemoteType r = r
- { configParser = configParser r ++ specialRemoteConfigParser
+ { configParser = addRemoteConfigParser specialRemoteConfigParsers
+ <$> configParser r
}
-specialRemoteConfigParser :: [RemoteConfigParser]
-specialRemoteConfigParser = chunkConfigParser ++ encryptionConfigParser
+specialRemoteConfigParsers :: [RemoteConfigFieldParser]
+specialRemoteConfigParsers = chunkConfigParsers ++ encryptionConfigParsers
-- Modifies a base Remote to support both chunking and encryption,
-- which special remotes typically should support.
let cu = fromMaybe u $ remoteAnnexConfigUUID gc
let rs = RemoteStateHandle cu
let c = fromMaybe M.empty $ M.lookup cu m
- let pc = either mempty id (parseRemoteConfig c (configParser t))
+ pc <- either mempty id . parseRemoteConfig c <$> configParser t
generate t g u pc gc rs >>= \case
Nothing -> return Nothing
Just r -> Just <$> adjustExportImport (adjustReadOnly (addHooks r)) rs
-- and will call chainGen on them.
, enumerate = const (return [])
, generate = \_ _ _ _ _ -> return Nothing
- , configParser = []
+ , configParser = mkRemoteConfigParser []
, setup = error "P2P remotes are set up using git-annex p2p"
, exportSupported = exportUnsupported
, importSupported = importUnsupported
{ typename = "rsync"
, enumerate = const (findSpecialRemotes "rsyncurl")
, generate = gen
- , configParser =
+ , configParser = mkRemoteConfigParser
[ yesNoParser shellEscapeField True
, optionalStringParser rsyncUrlField
]
{ typename = "web"
, enumerate = list
, generate = gen
- , configParser = []
+ , configParser = mkRemoteConfigParser []
, setup = error "not supported"
, exportSupported = exportUnsupported
, importSupported = importUnsupported
-- generates a remote of this type
, generate :: Git.Repo -> UUID -> ParsedRemoteConfig -> RemoteGitConfig -> RemoteStateHandle -> a (Maybe (RemoteA a))
-- parse configs of remotes of this type
- , configParser :: [RemoteConfigParser]
+ , configParser :: a RemoteConfigParser
-- initializes or enables a remote
, setup :: SetupStage -> Maybe UUID -> Maybe CredPair -> RemoteConfig -> RemoteGitConfig -> a (RemoteConfig, UUID)
-- check if a remote of this type is able to support export
- Presence of fields that are not included in this list will cause
- a parse failure.
-}
-type RemoteConfigParser = (RemoteConfigField, Maybe (ProposedAccepted String) -> RemoteConfig -> Either String (Maybe RemoteConfigValue))
+type RemoteConfigFieldParser = (RemoteConfigField, Maybe (ProposedAccepted String) -> RemoteConfig -> Either String (Maybe RemoteConfigValue))
+
+data RemoteConfigParser = RemoteConfigParser
+ { remoteConfigFieldParsers :: [RemoteConfigFieldParser]
+ , remoteConfigRestPassthrough :: Bool
+ }
+
+mkRemoteConfigParser :: Monad m => [RemoteConfigFieldParser] -> m RemoteConfigParser
+mkRemoteConfigParser l = pure (RemoteConfigParser l False)
+
+addRemoteConfigParser :: [RemoteConfigFieldParser] -> RemoteConfigParser -> RemoteConfigParser
+addRemoteConfigParser l rpc = rpc { remoteConfigFieldParsers = remoteConfigFieldParsers rpc ++ l }