aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Remote/Directory.hs67
-rw-r--r--Remote/External.hs102
-rw-r--r--Remote/External/Types.hs13
-rw-r--r--Remote/Helper/Export.hs3
-rw-r--r--Remote/S3.hs2
-rw-r--r--Remote/WebDAV.hs17
-rw-r--r--Types/Remote.hs11
-rw-r--r--doc/design/external_special_remote_protocol.mdwn15
-rwxr-xr-xdoc/special_remotes/external/example.sh9
9 files changed, 154 insertions, 85 deletions
diff --git a/Remote/Directory.hs b/Remote/Directory.hs
index c3ebeb899..24f35868b 100644
--- a/Remote/Directory.hs
+++ b/Remote/Directory.hs
@@ -47,26 +47,29 @@ gen r u c gc = do
let chunkconfig = getChunkConfig c
return $ Just $ specialRemote c
(prepareStore dir chunkconfig)
- (retrieve dir chunkconfig)
- (simplyPrepare $ remove dir)
- (simplyPrepare $ checkKey dir chunkconfig)
+ (retrieveKeyFileM dir chunkconfig)
+ (simplyPrepare $ removeKeyM dir)
+ (simplyPrepare $ checkPresentM dir chunkconfig)
Remote
{ uuid = u
, cost = cst
, name = Git.repoDescribe r
, storeKey = storeKeyDummy
, retrieveKeyFile = retreiveKeyFileDummy
- , retrieveKeyFileCheap = retrieveCheap dir chunkconfig
+ , retrieveKeyFileCheap = retrieveKeyFileCheapM dir chunkconfig
, removeKey = removeKeyDummy
, lockContent = Nothing
, checkPresent = checkPresentDummy
, checkPresentCheap = True
, exportActions = return $ ExportActions
- { storeExport = storeExportDirectory dir
- , retrieveExport = retrieveExportDirectory dir
- , removeExport = removeExportDirectory dir
- , checkPresentExport = checkPresentExportDirectory dir
- , renameExport = renameExportDirectory dir
+ { storeExport = storeExportM dir
+ , retrieveExport = retrieveExportM dir
+ , removeExport = removeExportM dir
+ , checkPresentExport = checkPresentExportM dir
+ -- Not needed because removeExportLocation
+ -- auto-removes empty directories.
+ , removeExportDirectory = Nothing
+ , renameExport = renameExportM dir
}
, whereisKey = Nothing
, remoteFsck = Nothing
@@ -166,17 +169,17 @@ finalizeStoreGeneric tmp dest = do
mapM_ preventWrite =<< dirContents dest
preventWrite dest
-retrieve :: FilePath -> ChunkConfig -> Preparer Retriever
-retrieve d (LegacyChunks _) = Legacy.retrieve locations d
-retrieve d _ = simplyPrepare $ byteRetriever $ \k sink ->
+retrieveKeyFileM :: FilePath -> ChunkConfig -> Preparer Retriever
+retrieveKeyFileM d (LegacyChunks _) = Legacy.retrieve locations d
+retrieveKeyFileM d _ = simplyPrepare $ byteRetriever $ \k sink ->
sink =<< liftIO (L.readFile =<< getLocation d k)
-retrieveCheap :: FilePath -> ChunkConfig -> Key -> AssociatedFile -> FilePath -> Annex Bool
+retrieveKeyFileCheapM :: FilePath -> ChunkConfig -> Key -> AssociatedFile -> FilePath -> Annex Bool
-- no cheap retrieval possible for chunks
-retrieveCheap _ (UnpaddedChunks _) _ _ _ = return False
-retrieveCheap _ (LegacyChunks _) _ _ _ = return False
+retrieveKeyFileCheapM _ (UnpaddedChunks _) _ _ _ = return False
+retrieveKeyFileCheapM _ (LegacyChunks _) _ _ _ = return False
#ifndef mingw32_HOST_OS
-retrieveCheap d NoChunks k _af f = liftIO $ catchBoolIO $ do
+retrieveKeyFileCheapM d NoChunks k _af f = liftIO $ catchBoolIO $ do
file <- absPath =<< getLocation d k
ifM (doesFileExist file)
( do
@@ -185,11 +188,11 @@ retrieveCheap d NoChunks k _af f = liftIO $ catchBoolIO $ do
, return False
)
#else
-retrieveCheap _ _ _ _ _ = return False
+retrieveKeyFileCheapM _ _ _ _ _ = return False
#endif
-remove :: FilePath -> Remover
-remove d k = liftIO $ removeDirGeneric d (storeDir d k)
+removeKeyM :: FilePath -> Remover
+removeKeyM d k = liftIO $ removeDirGeneric d (storeDir d k)
{- Removes the directory, which must be located under the topdir.
-
@@ -216,9 +219,9 @@ removeDirGeneric topdir dir = do
then return ok
else doesDirectoryExist topdir <&&> (not <$> doesDirectoryExist dir)
-checkKey :: FilePath -> ChunkConfig -> CheckPresent
-checkKey d (LegacyChunks _) k = Legacy.checkKey d locations k
-checkKey d _ k = checkPresentGeneric d (locations d k)
+checkPresentM :: FilePath -> ChunkConfig -> CheckPresent
+checkPresentM d (LegacyChunks _) k = Legacy.checkKey d locations k
+checkPresentM d _ k = checkPresentGeneric d (locations d k)
checkPresentGeneric :: FilePath -> [FilePath] -> Annex Bool
checkPresentGeneric d ps = liftIO $
@@ -230,8 +233,8 @@ checkPresentGeneric d ps = liftIO $
)
)
-storeExportDirectory :: FilePath -> FilePath -> Key -> ExportLocation -> MeterUpdate -> Annex Bool
-storeExportDirectory d src _k loc p = liftIO $ catchBoolIO $ do
+storeExportM :: FilePath -> FilePath -> Key -> ExportLocation -> MeterUpdate -> Annex Bool
+storeExportM d src _k loc p = liftIO $ catchBoolIO $ do
createDirectoryIfMissing True (takeDirectory dest)
-- Write via temp file so that checkPresentGeneric will not
-- see it until it's fully stored.
@@ -240,27 +243,27 @@ storeExportDirectory d src _k loc p = liftIO $ catchBoolIO $ do
where
dest = exportPath d loc
-retrieveExportDirectory :: FilePath -> Key -> ExportLocation -> FilePath -> MeterUpdate -> Annex Bool
-retrieveExportDirectory d _k loc dest p = liftIO $ catchBoolIO $ do
+retrieveExportM :: FilePath -> Key -> ExportLocation -> FilePath -> MeterUpdate -> Annex Bool
+retrieveExportM d _k loc dest p = liftIO $ catchBoolIO $ do
withMeteredFile src p (L.writeFile dest)
return True
where
src = exportPath d loc
-removeExportDirectory :: FilePath -> Key -> ExportLocation -> Annex Bool
-removeExportDirectory d _k loc = liftIO $ do
+removeExportM :: FilePath -> Key -> ExportLocation -> Annex Bool
+removeExportM d _k loc = liftIO $ do
nukeFile src
removeExportLocation d loc
return True
where
src = exportPath d loc
-checkPresentExportDirectory :: FilePath -> Key -> ExportLocation -> Annex Bool
-checkPresentExportDirectory d _k loc =
+checkPresentExportM :: FilePath -> Key -> ExportLocation -> Annex Bool
+checkPresentExportM d _k loc =
checkPresentGeneric d [exportPath d loc]
-renameExportDirectory :: FilePath -> Key -> ExportLocation -> ExportLocation -> Annex Bool
-renameExportDirectory d _k oldloc newloc = liftIO $ catchBoolIO $ do
+renameExportM :: FilePath -> Key -> ExportLocation -> ExportLocation -> Annex Bool
+renameExportM d _k oldloc newloc = liftIO $ catchBoolIO $ do
createDirectoryIfMissing True (takeDirectory dest)
renameFile src dest
removeExportLocation d oldloc
diff --git a/Remote/External.hs b/Remote/External.hs
index fd4fd0649..b1204f776 100644
--- a/Remote/External.hs
+++ b/Remote/External.hs
@@ -71,11 +71,12 @@ gen r u c gc
exportsupported <- checkExportSupported' external
let exportactions = if exportsupported
then return $ ExportActions
- { storeExport = storeExportExternal external
- , retrieveExport = retrieveExportExternal external
- , removeExport = removeExportExternal external
- , checkPresentExport = checkPresentExportExternal external
- , renameExport = renameExportExternal external
+ { storeExport = storeExportM external
+ , retrieveExport = retrieveExportM external
+ , removeExport = removeExportM external
+ , checkPresentExport = checkPresentExportM external
+ , removeExportDirectory = Just $ removeExportDirectoryM external
+ , renameExport = renameExportM external
}
else exportUnsupported
-- Cheap exportSupported that replaces the expensive
@@ -84,13 +85,13 @@ gen r u c gc
then exportIsSupported
else exportUnsupported
mk cst avail
- (store external)
- (retrieve external)
- (remove external)
- (checkKey external)
- (Just (whereis external))
- (Just (claimurl external))
- (Just (checkurl external))
+ (storeKeyM external)
+ (retrieveKeyFileM external)
+ (removeKeyM external)
+ (checkPresentM external)
+ (Just (whereisKeyM external))
+ (Just (claimUrlM external))
+ (Just (checkUrlM external))
exportactions
cheapexportsupported
where
@@ -170,8 +171,8 @@ checkExportSupported' external = safely $
UNSUPPORTED_REQUEST -> Just $ return False
_ -> Nothing
-store :: External -> Storer
-store external = fileStorer $ \k f p ->
+storeKeyM :: External -> Storer
+storeKeyM external = fileStorer $ \k f p ->
handleRequestKey external (\sk -> TRANSFER Upload sk f) k (Just p) $ \resp ->
case resp of
TRANSFER_SUCCESS Upload k' | k == k' ->
@@ -182,8 +183,8 @@ store external = fileStorer $ \k f p ->
return False
_ -> Nothing
-retrieve :: External -> Retriever
-retrieve external = fileRetriever $ \d k p ->
+retrieveKeyFileM :: External -> Retriever
+retrieveKeyFileM external = fileRetriever $ \d k p ->
handleRequestKey external (\sk -> TRANSFER Download sk d) k (Just p) $ \resp ->
case resp of
TRANSFER_SUCCESS Download k'
@@ -192,8 +193,8 @@ retrieve external = fileRetriever $ \d k p ->
| k == k' -> Just $ giveup errmsg
_ -> Nothing
-remove :: External -> Remover
-remove external k = safely $
+removeKeyM :: External -> Remover
+removeKeyM external k = safely $
handleRequestKey external REMOVE k Nothing $ \resp ->
case resp of
REMOVE_SUCCESS k'
@@ -204,8 +205,8 @@ remove external k = safely $
return False
_ -> Nothing
-checkKey :: External -> CheckPresent
-checkKey external k = either giveup id <$> go
+checkPresentM :: External -> CheckPresent
+checkPresentM external k = either giveup id <$> go
where
go = handleRequestKey external CHECKPRESENT k Nothing $ \resp ->
case resp of
@@ -217,15 +218,15 @@ checkKey external k = either giveup id <$> go
| k' == k -> Just $ return $ Left errmsg
_ -> Nothing
-whereis :: External -> Key -> Annex [String]
-whereis external k = handleRequestKey external WHEREIS k Nothing $ \resp -> case resp of
+whereisKeyM :: External -> Key -> Annex [String]
+whereisKeyM external k = handleRequestKey external WHEREIS k Nothing $ \resp -> case resp of
WHEREIS_SUCCESS s -> Just $ return [s]
WHEREIS_FAILURE -> Just $ return []
UNSUPPORTED_REQUEST -> Just $ return []
_ -> Nothing
-storeExportExternal :: External -> FilePath -> Key -> ExportLocation -> MeterUpdate -> Annex Bool
-storeExportExternal external f k loc p = safely $
+storeExportM :: External -> FilePath -> Key -> ExportLocation -> MeterUpdate -> Annex Bool
+storeExportM external f k loc p = safely $
handleRequestExport external loc req k (Just p) $ \resp -> case resp of
TRANSFER_SUCCESS Upload k' | k == k' ->
Just $ return True
@@ -240,8 +241,8 @@ storeExportExternal external f k loc p = safely $
where
req sk = TRANSFEREXPORT Upload sk f
-retrieveExportExternal :: External -> Key -> ExportLocation -> FilePath -> MeterUpdate -> Annex Bool
-retrieveExportExternal external k loc d p = safely $
+retrieveExportM :: External -> Key -> ExportLocation -> FilePath -> MeterUpdate -> Annex Bool
+retrieveExportM external k loc d p = safely $
handleRequestExport external loc req k (Just p) $ \resp -> case resp of
TRANSFER_SUCCESS Download k'
| k == k' -> Just $ return True
@@ -256,8 +257,22 @@ retrieveExportExternal external k loc d p = safely $
where
req sk = TRANSFEREXPORT Download sk d
-removeExportExternal :: External -> Key -> ExportLocation -> Annex Bool
-removeExportExternal external k loc = safely $
+checkPresentExportM :: External -> Key -> ExportLocation -> Annex Bool
+checkPresentExportM external k loc = either giveup id <$> go
+ where
+ go = handleRequestExport external loc CHECKPRESENTEXPORT k Nothing $ \resp -> case resp of
+ CHECKPRESENT_SUCCESS k'
+ | k' == k -> Just $ return $ Right True
+ CHECKPRESENT_FAILURE k'
+ | k' == k -> Just $ return $ Right False
+ CHECKPRESENT_UNKNOWN k' errmsg
+ | k' == k -> Just $ return $ Left errmsg
+ UNSUPPORTED_REQUEST -> Just $ return $
+ Left "CHECKPRESENTEXPORT not implemented by external special remote"
+ _ -> Nothing
+
+removeExportM :: External -> Key -> ExportLocation -> Annex Bool
+removeExportM external k loc = safely $
handleRequestExport external loc REMOVEEXPORT k Nothing $ \resp -> case resp of
REMOVE_SUCCESS k'
| k == k' -> Just $ return True
@@ -270,22 +285,17 @@ removeExportExternal external k loc = safely $
return False
_ -> Nothing
-checkPresentExportExternal :: External -> Key -> ExportLocation -> Annex Bool
-checkPresentExportExternal external k loc = either giveup id <$> go
+removeExportDirectoryM :: External -> ExportDirectory -> Annex Bool
+removeExportDirectoryM external dir = safely $
+ handleRequest external req Nothing $ \resp -> case resp of
+ REMOVEEXPORTDIRECTORY_SUCCESS -> Just $ return True
+ REMOVEEXPORTDIRECTORY_FAILURE -> Just $ return False
+ UNSUPPORTED_REQUEST -> Just $ return True
where
- go = handleRequestExport external loc CHECKPRESENTEXPORT k Nothing $ \resp -> case resp of
- CHECKPRESENT_SUCCESS k'
- | k' == k -> Just $ return $ Right True
- CHECKPRESENT_FAILURE k'
- | k' == k -> Just $ return $ Right False
- CHECKPRESENT_UNKNOWN k' errmsg
- | k' == k -> Just $ return $ Left errmsg
- UNSUPPORTED_REQUEST -> Just $ return $
- Left "CHECKPRESENTEXPORT not implemented by external special remote"
- _ -> Nothing
+ req = REMOVEEXPORTDIRECTORY dir
-renameExportExternal :: External -> Key -> ExportLocation -> ExportLocation -> Annex Bool
-renameExportExternal external k src dest = safely $
+renameExportM :: External -> Key -> ExportLocation -> ExportLocation -> Annex Bool
+renameExportM external k src dest = safely $
handleRequestExport external src req k Nothing $ \resp -> case resp of
RENAMEEXPORT_SUCCESS k'
| k' == k -> Just $ return True
@@ -619,16 +629,16 @@ getAvailability external r gc =
return avail
defavail = return GloballyAvailable
-claimurl :: External -> URLString -> Annex Bool
-claimurl external url =
+claimUrlM :: External -> URLString -> Annex Bool
+claimUrlM external url =
handleRequest external (CLAIMURL url) Nothing $ \req -> case req of
CLAIMURL_SUCCESS -> Just $ return True
CLAIMURL_FAILURE -> Just $ return False
UNSUPPORTED_REQUEST -> Just $ return False
_ -> Nothing
-checkurl :: External -> URLString -> Annex UrlContents
-checkurl external url =
+checkUrlM :: External -> URLString -> Annex UrlContents
+checkUrlM external url =
handleRequest external (CHECKURL url) Nothing $ \req -> case req of
CHECKURL_CONTENTS sz f -> Just $ return $ UrlContents sz
(if null f then Nothing else Just $ mkSafeFilePath f)
diff --git a/Remote/External/Types.hs b/Remote/External/Types.hs
index 343004a85..01e44b3a7 100644
--- a/Remote/External/Types.hs
+++ b/Remote/External/Types.hs
@@ -36,7 +36,7 @@ import Types.StandardGroups (PreferredContentExpression)
import Utility.Metered (BytesProcessed(..))
import Types.Transfer (Direction(..))
import Config.Cost (Cost)
-import Types.Remote (RemoteConfig, ExportLocation(..))
+import Types.Remote (RemoteConfig, ExportLocation(..), ExportDirectory(..))
import Types.Availability (Availability(..))
import Types.Key
import Utility.Url (URLString)
@@ -121,6 +121,7 @@ data Request
| TRANSFEREXPORT Direction SafeKey FilePath
| CHECKPRESENTEXPORT SafeKey
| REMOVEEXPORT SafeKey
+ | REMOVEEXPORTDIRECTORY ExportDirectory
| RENAMEEXPORT SafeKey ExportLocation
deriving (Show)
@@ -160,6 +161,8 @@ instance Proto.Sendable Request where
[ "CHECKPRESENTEXPORT", Proto.serialize key ]
formatMessage (REMOVEEXPORT key) =
[ "REMOVEEXPORT", Proto.serialize key ]
+ formatMessage (REMOVEEXPORTDIRECTORY dir) =
+ [ "REMOVEEXPORTDIRECTORY", Proto.serialize dir ]
formatMessage (RENAMEEXPORT key newloc) =
[ "RENAMEEXPORT"
, Proto.serialize key
@@ -190,6 +193,8 @@ data Response
| WHEREIS_FAILURE
| EXPORTSUPPORTED_SUCCESS
| EXPORTSUPPORTED_FAILURE
+ | REMOVEEXPORTDIRECTORY_SUCCESS
+ | REMOVEEXPORTDIRECTORY_FAILURE
| RENAMEEXPORT_SUCCESS Key
| RENAMEEXPORT_FAILURE Key
| UNSUPPORTED_REQUEST
@@ -218,6 +223,8 @@ instance Proto.Receivable Response where
parseCommand "WHEREIS-FAILURE" = Proto.parse0 WHEREIS_FAILURE
parseCommand "EXPORTSUPPORTED-SUCCESS" = Proto.parse0 EXPORTSUPPORTED_SUCCESS
parseCommand "EXPORTSUPPORTED-FAILURE" = Proto.parse0 EXPORTSUPPORTED_FAILURE
+ parseCommand "REMOVEEXPORTDIRECTORY-SUCCESS" = Proto.parse0 REMOVEEXPORTDIRECTORY_SUCCESS
+ parseCommand "REMOVEEXPORTDIRECTORY-FAILURE" = Proto.parse0 REMOVEEXPORTDIRECTORY_FAILURE
parseCommand "RENAMEEXPORT-SUCCESS" = Proto.parse1 RENAMEEXPORT_SUCCESS
parseCommand "RENAMEEXPORT-FAILURE" = Proto.parse1 RENAMEEXPORT_FAILURE
parseCommand "UNSUPPORTED-REQUEST" = Proto.parse0 UNSUPPORTED_REQUEST
@@ -352,3 +359,7 @@ instance Proto.Serializable URI where
instance Proto.Serializable ExportLocation where
serialize (ExportLocation loc) = loc
deserialize = Just . ExportLocation
+
+instance Proto.Serializable ExportDirectory where
+ serialize (ExportDirectory loc) = loc
+ deserialize = Just . ExportDirectory
diff --git a/Remote/Helper/Export.hs b/Remote/Helper/Export.hs
index f7cfb6da3..44fa47ca5 100644
--- a/Remote/Helper/Export.hs
+++ b/Remote/Helper/Export.hs
@@ -32,8 +32,9 @@ instance HasExportUnsupported (Annex (ExportActions Annex)) where
warning "store export is unsupported"
return False
, retrieveExport = \_ _ _ _ -> return False
- , removeExport = \_ _ -> return False
, checkPresentExport = \_ _ -> return False
+ , removeExport = \_ _ -> return False
+ , removeExportDirectory = Just $ \_ -> return False
, renameExport = \_ _ _ -> return False
}
diff --git a/Remote/S3.hs b/Remote/S3.hs
index 8b6fe6103..228a8047e 100644
--- a/Remote/S3.hs
+++ b/Remote/S3.hs
@@ -92,6 +92,8 @@ gen r u c gc = do
, retrieveExport = retrieveExportS3 info h
, removeExport = removeExportS3 info h
, checkPresentExport = checkPresentExportS3 info h
+ -- S3 does not have directories.
+ , removeExportDirectory = Nothing
, renameExport = renameExportS3 info h
}
, whereisKey = Just (getWebUrls info c)
diff --git a/Remote/WebDAV.hs b/Remote/WebDAV.hs
index 8c72365e6..61fc70324 100644
--- a/Remote/WebDAV.hs
+++ b/Remote/WebDAV.hs
@@ -73,8 +73,10 @@ gen r u c gc = new <$> remoteCost gc expensiveRemoteCost
, exportActions = withDAVHandle this $ \mh -> return $ ExportActions
{ storeExport = storeExportDav mh
, retrieveExport = retrieveExportDav mh
- , removeExport = removeExportDav mh
, checkPresentExport = checkPresentExportDav this mh
+ , removeExport = removeExportDav mh
+ , removeExportDirectory = Just $
+ removeExportDirectoryDav mh
, renameExport = renameExportDav mh
}
, whereisKey = Nothing
@@ -189,10 +191,6 @@ retrieveExportDav mh _k loc d p = runExport mh $ \_dav -> do
retrieveHelper (exportLocation loc) d p
return True
-removeExportDav :: Maybe DavHandle -> Key -> ExportLocation -> Annex Bool
-removeExportDav mh _k loc = runExport mh $ \_dav ->
- removeHelper (exportLocation loc)
-
checkPresentExportDav :: Remote -> Maybe DavHandle -> Key -> ExportLocation -> Annex Bool
checkPresentExportDav r mh _k loc = case mh of
Nothing -> giveup $ name r ++ " not configured"
@@ -200,6 +198,15 @@ checkPresentExportDav r mh _k loc = case mh of
v <- goDAV h $ existsDAV (exportLocation loc)
either giveup return v
+removeExportDav :: Maybe DavHandle -> Key -> ExportLocation -> Annex Bool
+removeExportDav mh _k loc = runExport mh $ \_dav ->
+ removeHelper (exportLocation loc)
+
+removeExportDirectoryDav :: Maybe DavHandle -> ExportDirectory -> Annex Bool
+removeExportDirectoryDav mh (ExportDirectory dir) = runExport mh $ \_dav ->
+ safely (inLocation dir delContentM)
+ >>= maybe (return False) (const $ return True)
+
renameExportDav :: Maybe DavHandle -> Key -> ExportLocation -> ExportLocation -> Annex Bool
renameExportDav Nothing _ _ _ = return False
renameExportDav (Just h) _k src dest
diff --git a/Types/Remote.hs b/Types/Remote.hs
index 272693296..798bf1af5 100644
--- a/Types/Remote.hs
+++ b/Types/Remote.hs
@@ -19,6 +19,7 @@ module Types.Remote
, Verification(..)
, unVerified
, ExportLocation(..)
+ , ExportDirectory(..)
, isExportSupported
, ExportActions(..)
)
@@ -164,6 +165,9 @@ unVerified a = do
newtype ExportLocation = ExportLocation FilePath
deriving (Show, Eq)
+newtype ExportDirectory = ExportDirectory FilePath
+ deriving (Show, Eq)
+
isExportSupported :: RemoteA a -> a Bool
isExportSupported r = exportSupported (remotetype r) (config r) (gitconfig r)
@@ -178,6 +182,13 @@ data ExportActions a = ExportActions
, retrieveExport :: Key -> ExportLocation -> FilePath -> MeterUpdate -> a Bool
-- Removes an exported file (succeeds if the contents are not present)
, removeExport :: Key -> ExportLocation -> a Bool
+ -- Removes an exported directory. Typically the directory will be
+ -- empty, but it could possbly contain files or other directories,
+ -- and it's ok to delete those. If the remote does not use
+ -- directories, or automatically cleans up empty directories,
+ -- this can be Nothing. Should not fail if the directory was
+ -- already removed.
+ , removeExportDirectory :: Maybe (ExportDirectory -> a Bool)
-- Checks if anything is exported to the remote at the specified
-- ExportLocation.
-- Throws an exception if the remote cannot be accessed.
diff --git a/doc/design/external_special_remote_protocol.mdwn b/doc/design/external_special_remote_protocol.mdwn
index 95ef13041..401c42d6c 100644
--- a/doc/design/external_special_remote_protocol.mdwn
+++ b/doc/design/external_special_remote_protocol.mdwn
@@ -176,6 +176,17 @@ replying with `UNSUPPORTED-REQUEST` is acceptable.
`REMOVE-FAILURE`.
If the content was already not present in the remote, it should
respond with `REMOVE-SUCCESS`.
+* `REMOVEEXPORTDIRECTORY Directory`
+ Requests the remote remove an exported directory.
+ If the remote does not use directories, or automatically cleans up
+ empty directories, this does not need to be implemented.
+ The directory will be in the form of a relative path, and may contain path
+ separators, whitespace, and other special characters.
+ Typically the directory will be empty, but it could possbly contain
+ files or other directories, and it's ok to remove those.
+ The remote responds with either `REMOVEEXPORTDIRECTORY-SUCCESS`
+ or `REMOVEEXPORTDIRECTORY-FAILURE`.
+ Should not fail if the directory was already removed.
* `RENAMEEXPORT Key NewName`
Requests the remote rename a file stored on it from the previously
provided Name to the NewName.
@@ -261,6 +272,10 @@ while it's handling a request.
Indicates that a `RENAMEEXPORT` was done successfully.
* `RENAMEEXPORT-FAILURE Key`
Indicates that a `RENAMEEXPORT` failed for whatever reason.
+* `REMOVEEXPORTDIRECTORY-SUCCESS`
+ Indicates that a `REMOVEEXPORTDIRECTORY` was done successfully.
+* `REMOVEEXPORTDIRECTORY-FAILURE`
+ Indicates that a `REMOVEEXPORTDIRECTORY` failed for whatever reason.
* `UNSUPPORTED-REQUEST`
Indicates that the special remote does not know how to handle a request.
diff --git a/doc/special_remotes/external/example.sh b/doc/special_remotes/external/example.sh
index 81b4b6806..c7fb78c02 100755
--- a/doc/special_remotes/external/example.sh
+++ b/doc/special_remotes/external/example.sh
@@ -264,6 +264,15 @@ while read line; do
key="$2"
doremove "$key" "$exportlocation"
;;
+ REMOVEEXPORTDIRECTORY)
+ shift 1
+ dir="$@"
+ if [ ! -d "$dir" ] || rm -rf "$mydirectory/$dir"; then
+ echo REMOVEEXPORTDIRECTORY-SUCCESS
+ else
+ echo REMOVEEXPORTDIRECTORY-FAILURE
+ fi
+ ;;
RENAMEEXPORT)
key="$2"
shift 2