summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2013-12-27 02:49:10 -0400
committerGravatar Joey Hess <joey@kitenet.net>2013-12-27 02:49:10 -0400
commit8ad91f287cf87b3a5a849d997de35210a0e9f2b7 (patch)
tree0850980711d834864512c2ef04ea0adf7bed0703
parentd0d51528d0d90c218173593db17de1a480e0b15e (diff)
don't send PREPARE before INITREMOTE
That complicated special remote programs, because they had to avoid making PREPARE fail if some configuration is missing, because the remote might not be initialized yet. Instead, complicate git-annex slightly by only sending PREPARE immediately before some other request other than INITREMOTE (or PREPARE of course).
-rw-r--r--Remote/External.hs20
-rw-r--r--Remote/External/Types.hs8
-rw-r--r--doc/design/external_special_remote_protocol.mdwn17
3 files changed, 31 insertions, 14 deletions
diff --git a/Remote/External.hs b/Remote/External.hs
index 1cf199e99..5a09d1de0 100644
--- a/Remote/External.hs
+++ b/Remote/External.hs
@@ -169,6 +169,8 @@ handleRequest external req mp responsehandler =
handleRequest' :: ExternalLock -> External -> Request -> Maybe MeterUpdate -> (Response -> Maybe (Annex a)) -> Annex a
handleRequest' lck external req mp responsehandler = do
+ when (needsPREPARE req) $
+ checkPrepared lck external
sendMessage lck external req
loop
where
@@ -230,15 +232,13 @@ fromExternal lck external extractor a =
void $ liftIO $ atomically $ swapTMVar v st
{- Handle initial protocol startup; check the VERSION
- - the remote sends, and send it the PREPARE request. -}
+ - the remote sends. -}
receiveMessage lck external
(const Nothing)
(checkVersion lck external)
(const Nothing)
- handleRequest' lck external PREPARE Nothing $ \resp ->
- case resp of
- PREPARE_SUCCESS -> Just $ run st
- _ -> Nothing
+
+ run st
run st = a $ extractor st
v = externalState external
@@ -259,6 +259,7 @@ startExternal externaltype = liftIO $ do
{ externalSend = hin
, externalReceive = hout
, externalPid = pid
+ , externalPrepared = False
}
stopExternal :: External -> Annex ()
@@ -282,6 +283,15 @@ checkVersion lck external (VERSION v) = Just $
else sendMessage lck external (ERROR "unsupported VERSION")
checkVersion _ _ _ = Nothing
+checkPrepared :: ExternalLock -> External -> Annex ()
+checkPrepared lck external =
+ fromExternal lck external externalPrepared $ \prepared ->
+ unless prepared $
+ handleRequest' lck external PREPARE Nothing $ \resp ->
+ case resp of
+ PREPARE_SUCCESS -> Just noop
+ _ -> Nothing
+
{- Caches the cost in the git config to avoid needing to start up an
- external special remote every time time just to ask it what its
- cost is. -}
diff --git a/Remote/External/Types.hs b/Remote/External/Types.hs
index 873c5c438..4000f3f49 100644
--- a/Remote/External/Types.hs
+++ b/Remote/External/Types.hs
@@ -18,6 +18,7 @@ module Remote.External.Types (
Sendable(..),
Receivable(..),
Request(..),
+ needsPREPARE,
Response(..),
RemoteRequest(..),
RemoteResponse(..),
@@ -60,6 +61,7 @@ data ExternalState = ExternalState
{ externalSend :: Handle
, externalReceive :: Handle
, externalPid :: ProcessHandle
+ , externalPrepared :: Bool
}
-- Constructor is not exported, and only created by newExternal.
@@ -98,6 +100,12 @@ data Request
| REMOVE Key
deriving (Show)
+-- Does PREPARE need to have been sent before this request?
+needsPREPARE :: Request -> Bool
+needsPREPARE PREPARE = False
+needsPREPARE INITREMOTE = False
+needsPREPARE _ = True
+
instance Sendable Request where
formatMessage PREPARE = ["PREPARE"]
formatMessage INITREMOTE = ["INITREMOTE"]
diff --git a/doc/design/external_special_remote_protocol.mdwn b/doc/design/external_special_remote_protocol.mdwn
index 0e67a4909..cede16e16 100644
--- a/doc/design/external_special_remote_protocol.mdwn
+++ b/doc/design/external_special_remote_protocol.mdwn
@@ -36,8 +36,9 @@ the version of the protocol it is using.
VERSION 1
-Once it knows the version, git-annex will send a message telling the
-special remote to start up.
+Once it knows the version, git-annex will generally
+send a message telling the special remote to start up.
+(Or it might send a INITREMOTE, so don't hardcode this order.)
PREPARE
@@ -84,17 +85,15 @@ send one of the corresponding replies listed in the next section.
The following requests *must* all be supported by the special remote.
-* `PREPARE`
- Tells the special remote it's time to prepare itself to be used.
- Only run once, at startup, always immediately after the special remote
- sends VERSION.
* `INITREMOTE`
- Request that the remote initialized itself. This is where any one-time
+ Request that the remote initialize itself. This is where any one-time
setup tasks can be done, for example creating an Amazon S3 bucket.
- (PREPARE is still sent before this.)
- Note: This may be run repeatedly, as a remote is initialized in
+ Note: This may be run repeatedly over time, as a remote is initialized in
different repositories, or as the configuration of a remote is changed.
So any one-time setup tasks should be done idempotently.
+* `PREPARE`
+ Tells the special remote it's time to prepare itself to be used.
+ Only INITREMOTE can come before this.
* `TRANSFER STORE|RETRIEVE Key File`
Requests the transfer of a key. For Send, the File is the file to upload;
for Receive the File is where to store the download.