aboutsummaryrefslogtreecommitdiff
path: root/bpkg/fetch-pkg.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bpkg/fetch-pkg.cxx')
-rw-r--r--bpkg/fetch-pkg.cxx110
1 files changed, 91 insertions, 19 deletions
diff --git a/bpkg/fetch-pkg.cxx b/bpkg/fetch-pkg.cxx
index 81d4131..721e4b8 100644
--- a/bpkg/fetch-pkg.cxx
+++ b/bpkg/fetch-pkg.cxx
@@ -5,8 +5,8 @@
#include <sstream>
-#include <libbutl/filesystem.mxx> // cpfile ()
-#include <libbutl/manifest-parser.mxx>
+#include <libbutl/filesystem.hxx> // cpfile ()
+#include <libbutl/manifest-parser.hxx>
#include <bpkg/checksum.hxx>
#include <bpkg/diagnostics.hxx>
@@ -52,7 +52,7 @@ namespace bpkg
is.close ();
string s (bs.str ());
- string sha256sum (sha256 (s.c_str (), s.size ()));
+ string cs (sha256sum (s.c_str (), s.size ()));
istringstream ts (s); // Text mode.
@@ -60,7 +60,7 @@ namespace bpkg
M m (mp, ignore_unknown);
if (pr.wait ())
- return make_pair (move (m), move (sha256sum));
+ return make_pair (move (m), move (cs));
// Child existed with an error, fall through.
}
@@ -97,20 +97,80 @@ namespace bpkg
if (exists (df))
fail << "file " << df << " already exists";
+ // Currently we only expect fetching a package archive via the HTTP(S)
+ // protocol.
+ //
+ switch (u.scheme)
+ {
+ case repository_protocol::git:
+ case repository_protocol::ssh:
+ case repository_protocol::file: assert (false);
+ case repository_protocol::http:
+ case repository_protocol::https: break;
+ }
+
auto_rmfile arm (df);
- process pr (start_fetch (o,
- u.string (),
- df,
- string () /* user_agent */,
- o.pkg_proxy ()));
- if (!pr.wait ())
+ // Note that a package file may not be present in the repository due to
+ // outdated repository information. Thus, while fetching the file we also
+ // try to retrieve the HTTP status code. If the HTTP status code is
+ // retrieved and is 404 (not found) or the fetch program doesn't support
+ // its retrieval and fails, then we also advise the user to re-fetch the
+ // repositories.
+ //
+ pair<process, uint16_t> ps (
+ start_fetch_http (o,
+ u.string (),
+ df,
+ string () /* user_agent */,
+ o.pkg_proxy ()));
+
+ process& pr (ps.first);
+ uint16_t sc (ps.second);
+
+ // Fail if the fetch process didn't exit normally with 0 code or the HTTP
+ // status code is retrieved and differs from 200.
+ //
+ // Note that the diagnostics may potentially look as follows:
+ //
+ // foo-1.0.0.tar.gz:
+ // ###################################################### 100.0%
+ // error: unable to fetch package https://example.org/1/foo-1.0.0.tar.gz
+ // info: repository metadata could be stale
+ // info: run 'bpkg rep-fetch' (or equivalent) to update
+ //
+ // It's a bit unfortunate that the 100% progress indicator can be shown
+ // for a potential HTTP error and it doesn't seem that we can easily fix
+ // that. Note, however, that this situation is not very common and
+ // probably that's fine.
+ //
+ if (!pr.wait () || (sc != 0 && sc != 200))
{
// While it is reasonable to assuming the child process issued
// diagnostics, some may not mention the URL.
//
- fail << "unable to fetch " << u <<
- info << "re-run with -v for more information";
+ diag_record dr (fail);
+ dr << "unable to fetch package " << u;
+
+ // Print the HTTP status code in the diagnostics on the request failure,
+ // unless it cannot be retrieved or is 404. Note that the fetch program
+ // may even exit successfully on such a failure (see start_fetch_http()
+ // for details) and issue no diagnostics at all.
+ //
+ if (sc != 0 && sc != 200 && sc != 404)
+ dr << info << "HTTP status code " << sc;
+
+ // If not found, advise the user to re-fetch the repositories. Note that
+ // if the status code cannot be retrieved, we assume it could be 404 and
+ // advise.
+ //
+ if (sc == 404 || sc == 0)
+ {
+ dr << info << "repository metadata could be stale" <<
+ info << "run 'bpkg rep-fetch' (or equivalent) to update";
+ }
+ else if (verb < 2)
+ dr << info << "re-run with -v for more information";
}
arm.cancel ();
@@ -146,14 +206,14 @@ namespace bpkg
// and reading the manifest. The file should be opened in the binary
// mode for the first operation and in the text mode for the second one.
//
- string sha256sum;
+ string cs;
if (o != nullptr)
- sha256sum = sha256 (*o, f); // Read file in the binary mode.
+ cs = sha256sum (*o, f); // Read file in the binary mode.
ifdstream ifs (f); // Open file in the text mode.
manifest_parser mp (ifs, f.string ());
- return make_pair (M (mp, ignore_unknown), move (sha256sum));
+ return make_pair (M (mp, ignore_unknown), move (cs));
}
catch (const manifest_parsing& e)
{
@@ -168,8 +228,14 @@ namespace bpkg
pkg_repository_manifests
pkg_fetch_repositories (const dir_path& d, bool iu)
{
- return fetch_manifest<pkg_repository_manifests> (
- nullptr, d / repositories_file, iu).first;
+ pkg_repository_manifests r (
+ fetch_manifest<pkg_repository_manifests> (
+ nullptr, d / repositories_file, iu).first);
+
+ if (r.empty ())
+ r.emplace_back (repository_manifest ()); // Add the base repository.
+
+ return r;
}
pair<pkg_repository_manifests, string/*checksum*/>
@@ -184,9 +250,15 @@ namespace bpkg
path& f (*u.path);
f /= repositories_file;
- return rl.remote ()
+ pair<pkg_repository_manifests, string> r (
+ rl.remote ()
? fetch_manifest<pkg_repository_manifests> (o, u, iu)
- : fetch_manifest<pkg_repository_manifests> (&o, f, iu);
+ : fetch_manifest<pkg_repository_manifests> (&o, f, iu));
+
+ if (r.first.empty ())
+ r.first.emplace_back (repository_manifest ()); // Add the base repository.
+
+ return r;
}
pkg_package_manifests