refuse to fetch from a remote that has no manifest
Otherwise, it can be confusing to clone from a wrong url, since it fails to download a manifest and so appears as if the remote exists but is empty. Sponsored-by: Jack Hill on Patreon
This commit is contained in:
parent
424afe46d7
commit
3f848564ac
2 changed files with 31 additions and 21 deletions
|
@ -111,7 +111,9 @@ capabilities = do
|
||||||
|
|
||||||
list :: State -> Remote -> Bool -> Annex State
|
list :: State -> Remote -> Bool -> Annex State
|
||||||
list st rmt forpush = do
|
list st rmt forpush = do
|
||||||
manifest <- downloadManifest rmt
|
manifest <- if forpush
|
||||||
|
then downloadManifestWhenPresent rmt
|
||||||
|
else downloadManifestOrFail rmt
|
||||||
l <- forM (inManifest manifest) $ \k -> do
|
l <- forM (inManifest manifest) $ \k -> do
|
||||||
b <- downloadGitBundle rmt k
|
b <- downloadGitBundle rmt k
|
||||||
heads <- inRepo $ Git.Bundle.listHeads b
|
heads <- inRepo $ Git.Bundle.listHeads b
|
||||||
|
@ -168,7 +170,7 @@ fetch st rmt [] = do
|
||||||
|
|
||||||
fetch' :: State -> Remote -> Annex ()
|
fetch' :: State -> Remote -> Annex ()
|
||||||
fetch' st rmt = do
|
fetch' st rmt = do
|
||||||
manifest <- maybe (downloadManifest rmt) pure (manifestCache st)
|
manifest <- maybe (downloadManifestOrFail rmt) pure (manifestCache st)
|
||||||
forM_ (inManifest manifest) $ \k ->
|
forM_ (inManifest manifest) $ \k ->
|
||||||
downloadGitBundle rmt k >>= inRepo . Git.Bundle.unbundle
|
downloadGitBundle rmt k >>= inRepo . Git.Bundle.unbundle
|
||||||
-- Newline indicates end of fetch.
|
-- Newline indicates end of fetch.
|
||||||
|
@ -264,7 +266,8 @@ push st rmt ls = do
|
||||||
-- from it.
|
-- from it.
|
||||||
fullPush :: State -> Remote -> [Ref] -> Annex (Bool, State)
|
fullPush :: State -> Remote -> [Ref] -> Annex (Bool, State)
|
||||||
fullPush st rmt refs = guardPush st $ do
|
fullPush st rmt refs = guardPush st $ do
|
||||||
oldmanifest <- maybe (downloadManifest rmt) pure (manifestCache st)
|
oldmanifest <- maybe (downloadManifestWhenPresent rmt) pure
|
||||||
|
(manifestCache st)
|
||||||
let bs = map Git.Bundle.fullBundleSpec refs
|
let bs = map Git.Bundle.fullBundleSpec refs
|
||||||
bundlekey <- generateAndUploadGitBundle rmt bs oldmanifest
|
bundlekey <- generateAndUploadGitBundle rmt bs oldmanifest
|
||||||
uploadManifest rmt (mkManifest [bundlekey] [])
|
uploadManifest rmt (mkManifest [bundlekey] [])
|
||||||
|
@ -285,7 +288,7 @@ guardPush st a = catchNonAsync a $ \ex -> do
|
||||||
incrementalPush :: State -> Remote -> M.Map Ref Sha -> M.Map Ref Sha -> Annex (Bool, State)
|
incrementalPush :: State -> Remote -> M.Map Ref Sha -> M.Map Ref Sha -> Annex (Bool, State)
|
||||||
incrementalPush st rmt oldtrackingrefs newtrackingrefs = guardPush st $ do
|
incrementalPush st rmt oldtrackingrefs newtrackingrefs = guardPush st $ do
|
||||||
bs <- calc [] (M.toList newtrackingrefs)
|
bs <- calc [] (M.toList newtrackingrefs)
|
||||||
oldmanifest <- maybe (downloadManifest rmt) pure (manifestCache st)
|
oldmanifest <- maybe (downloadManifestWhenPresent rmt) pure (manifestCache st)
|
||||||
bundlekey <- generateAndUploadGitBundle rmt bs oldmanifest
|
bundlekey <- generateAndUploadGitBundle rmt bs oldmanifest
|
||||||
uploadManifest rmt (oldmanifest <> mkManifest [bundlekey] [])
|
uploadManifest rmt (oldmanifest <> mkManifest [bundlekey] [])
|
||||||
return (True, st { manifestCache = Nothing })
|
return (True, st { manifestCache = Nothing })
|
||||||
|
@ -350,13 +353,14 @@ incrementalPush st rmt oldtrackingrefs newtrackingrefs = guardPush st $ do
|
||||||
)
|
)
|
||||||
|
|
||||||
-- When the push deletes all refs from the remote, upload an empty
|
-- When the push deletes all refs from the remote, upload an empty
|
||||||
-- manifest and then drop all bundles that were listed in it.
|
-- manifest and then drop all bundles that were listed in the manifest.
|
||||||
-- The manifest is emptired first so if this is interrupted, only
|
-- The manifest is emptied first so if this is interrupted, only
|
||||||
-- unused bundles will remain in the remote, rather than leaving the
|
-- unused bundles will remain in the remote, rather than leaving the
|
||||||
-- remote with a manifest that refers to missing bundles.
|
-- remote with a manifest that refers to missing bundles.
|
||||||
pushEmpty :: State -> Remote -> Annex (Bool, State)
|
pushEmpty :: State -> Remote -> Annex (Bool, State)
|
||||||
pushEmpty st rmt = do
|
pushEmpty st rmt = do
|
||||||
manifest <- maybe (downloadManifest rmt) pure (manifestCache st)
|
manifest <- maybe (downloadManifestWhenPresent rmt) pure
|
||||||
|
(manifestCache st)
|
||||||
uploadManifest rmt mempty
|
uploadManifest rmt mempty
|
||||||
ok <- allM (dropKey rmt)
|
ok <- allM (dropKey rmt)
|
||||||
(genManifestKey (Remote.uuid rmt) : inManifest manifest)
|
(genManifestKey (Remote.uuid rmt) : inManifest manifest)
|
||||||
|
@ -534,17 +538,27 @@ checkSpecialRemoteProblems rmt
|
||||||
Just "Cannot use this thirdparty-populated special remote as a git remote"
|
Just "Cannot use this thirdparty-populated special remote as a git remote"
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
|
|
||||||
-- Downloads the Manifest, or if it does not exist, returns an empty
|
-- Downloads the Manifest when present in the remote. When not present,
|
||||||
-- Manifest.
|
-- returns an empty Manifest.
|
||||||
|
downloadManifestWhenPresent :: Remote -> Annex Manifest
|
||||||
|
downloadManifestWhenPresent rmt = fromMaybe mempty <$> downloadManifest rmt
|
||||||
|
|
||||||
|
-- Downloads the Manifest, or fails if the remote does not contain it.
|
||||||
|
downloadManifestOrFail :: Remote -> Annex Manifest
|
||||||
|
downloadManifestOrFail rmt =
|
||||||
|
maybe (giveup "No git repository found in this remote.") return
|
||||||
|
=<< downloadManifest rmt
|
||||||
|
|
||||||
|
-- Downloads the Manifest or Nothing if the remote does not contain a
|
||||||
|
-- manifest.
|
||||||
--
|
--
|
||||||
-- Throws errors if the remote cannot be accessed or the download fails,
|
-- Throws errors if the remote cannot be accessed or the download fails,
|
||||||
-- or if the manifest file cannot be parsed.
|
-- or if the manifest file cannot be parsed.
|
||||||
--
|
downloadManifest :: Remote -> Annex (Maybe Manifest)
|
||||||
-- This downloads the manifest to a temporary file, rather than using
|
|
||||||
-- the usual Annex.Transfer.download. The content of manifests is not
|
|
||||||
-- stable, and so it needs to re-download it fresh every time.
|
|
||||||
downloadManifest :: Remote -> Annex Manifest
|
|
||||||
downloadManifest rmt = ifM (Remote.checkPresent rmt mk)
|
downloadManifest rmt = ifM (Remote.checkPresent rmt mk)
|
||||||
|
-- Downloads to a temporary file, rather than using
|
||||||
|
-- the usual Annex.Transfer.download. The content of manifests is
|
||||||
|
-- not stable, and so it needs to re-download it fresh every time.
|
||||||
( withTmpFile "GITMANIFEST" $ \tmp tmph -> do
|
( withTmpFile "GITMANIFEST" $ \tmp tmph -> do
|
||||||
liftIO $ hClose tmph
|
liftIO $ hClose tmph
|
||||||
_ <- Remote.retrieveKeyFile rmt mk
|
_ <- Remote.retrieveKeyFile rmt mk
|
||||||
|
@ -552,10 +566,11 @@ downloadManifest rmt = ifM (Remote.checkPresent rmt mk)
|
||||||
nullMeterUpdate Remote.NoVerify
|
nullMeterUpdate Remote.NoVerify
|
||||||
(outks, inks) <- partitionEithers . map parseline . B8.lines
|
(outks, inks) <- partitionEithers . map parseline . B8.lines
|
||||||
<$> liftIO (B.readFile tmp)
|
<$> liftIO (B.readFile tmp)
|
||||||
mkManifest
|
m <- mkManifest
|
||||||
<$> checkvalid [] inks
|
<$> checkvalid [] inks
|
||||||
<*> checkvalid [] outks
|
<*> checkvalid [] outks
|
||||||
, return mempty
|
return (Just m)
|
||||||
|
, return Nothing
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
mk = genManifestKey (Remote.uuid rmt)
|
mk = genManifestKey (Remote.uuid rmt)
|
||||||
|
|
|
@ -28,11 +28,6 @@ This is implememented and working. Remaining todo list for it:
|
||||||
stored in the repo. Chicken and egg problem cloning from
|
stored in the repo. Chicken and egg problem cloning from
|
||||||
such a remote. Maybe allow advanced users to force it?
|
such a remote. Maybe allow advanced users to force it?
|
||||||
|
|
||||||
* When the remote has no manifest, a pull from it should fail,
|
|
||||||
while a push should succeed. Otherwise, it can be confusing
|
|
||||||
to clone from a wrong url, since it fails to download
|
|
||||||
a manifest and so appears as if the remote is empty.
|
|
||||||
|
|
||||||
* Improve recovery from interrupted push by using outManifest to clean up
|
* Improve recovery from interrupted push by using outManifest to clean up
|
||||||
after it. (Requires populating outManifest.)
|
after it. (Requires populating outManifest.)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue