diff options
Diffstat (limited to 'bpkg/fetch-pkg.cxx')
-rw-r--r-- | bpkg/fetch-pkg.cxx | 110 |
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 |