aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bpkg/fetch-pkg.cxx20
-rw-r--r--bpkg/rep-create.cli11
-rw-r--r--bpkg/rep-create.cxx21
-rw-r--r--bpkg/rep-fetch.cxx3
-rw-r--r--bpkg/types-parsers.cxx29
-rw-r--r--bpkg/types-parsers.hxx15
-rw-r--r--doc/manual.cli45
7 files changed, 132 insertions, 12 deletions
diff --git a/bpkg/fetch-pkg.cxx b/bpkg/fetch-pkg.cxx
index 6d9e921..64abb43 100644
--- a/bpkg/fetch-pkg.cxx
+++ b/bpkg/fetch-pkg.cxx
@@ -168,8 +168,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 +190,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
diff --git a/bpkg/rep-create.cli b/bpkg/rep-create.cli
index be4cc42..9d062ec 100644
--- a/bpkg/rep-create.cli
+++ b/bpkg/rep-create.cli
@@ -36,6 +36,17 @@ namespace bpkg
"Ignore unknown manifest entries."
}
+ butl::standard_version --min-bpkg-version
+ {
+ "<ver>",
+ "Apply backward compatibility workarounds to the generated
+ \cb{packages.manifest} file so that it can be consumed by \cb{bpkg}
+ versions greater or equal to the specified version. If unspecified,
+ then the \cb{min-bpkg-version} value from the \cb{repositories.manifest}
+ file is used, if present. If the manifest value is not specified
+ either, then no backward compatibility workarounds are applied."
+ }
+
string --key
{
"<name>",
diff --git a/bpkg/rep-create.cxx b/bpkg/rep-create.cxx
index d820836..8de8c22 100644
--- a/bpkg/rep-create.cxx
+++ b/bpkg/rep-create.cxx
@@ -162,6 +162,15 @@ namespace bpkg
})
<< " prerequisite repository(s)";});
+ optional<standard_version> rmv (
+ rms.header && rms.header->min_bpkg_version
+ ? rms.header->min_bpkg_version
+ : nullopt);
+
+ optional<standard_version> opv (o.min_bpkg_version_specified ()
+ ? o.min_bpkg_version ()
+ : optional<standard_version> ());
+
// While we could have serialized as we go along, the order of
// packages will be pretty much random and not reproducible. By
// collecting all the manifests in a map we get a sorted list.
@@ -182,6 +191,16 @@ namespace bpkg
manifests.emplace_back (move (m));
}
+ // Issue a warning if --min-bpkg-version option and the repositories
+ // manifest's min-bpkg-version value are both specified and don't match.
+ // Let's issue it after the added repositories are printed to stdout, so
+ // that it doesn't go unnoticed.
+ //
+ if (opv && rmv && *opv != *rmv)
+ warn << "--min-bpkg-version option value " << *opv << " differs from "
+ << "minimum bpkg version " << *rmv << " specified in "
+ << d / repositories_file;
+
// Serialize packages manifest, optionally generate the signature manifest.
//
path p (d / packages_file);
@@ -197,7 +216,7 @@ namespace bpkg
ofdstream ofs (p, fdopen_mode::binary);
manifest_serializer s (ofs, p.string ());
- manifests.serialize (s);
+ manifests.serialize (s, opv ? opv : rmv);
ofs.close ();
}
diff --git a/bpkg/rep-fetch.cxx b/bpkg/rep-fetch.cxx
index 73c9058..cefa799 100644
--- a/bpkg/rep-fetch.cxx
+++ b/bpkg/rep-fetch.cxx
@@ -161,7 +161,8 @@ namespace bpkg
M r;
if (exists (f))
r = parse_manifest<M> (f, iu, rl, fragment);
- else
+
+ if (r.empty ())
r.emplace_back (repository_manifest ()); // Add the base repository.
return r;
diff --git a/bpkg/types-parsers.cxx b/bpkg/types-parsers.cxx
index d5ddb28..97ebafe 100644
--- a/bpkg/types-parsers.cxx
+++ b/bpkg/types-parsers.cxx
@@ -92,6 +92,35 @@ namespace bpkg
}
}
+ void parser<butl::standard_version>::
+ parse (butl::standard_version& x, bool& xs, scanner& s)
+ {
+ using butl::standard_version;
+
+ xs = true;
+
+ const char* o (s.next ());
+
+ if (!s.more ())
+ throw missing_value (o);
+
+ const char* v (s.next ());
+
+ try
+ {
+ // Note that we allow all kinds of versions, so that the caller can
+ // restrict them as they wish after the parsing.
+ //
+ x = standard_version (v,
+ standard_version::allow_earliest |
+ standard_version::allow_stub);
+ }
+ catch (const invalid_argument& e)
+ {
+ throw invalid_value (o, v, e.what ());
+ }
+ }
+
void parser<auth>::
parse (auth& x, bool& xs, scanner& s)
{
diff --git a/bpkg/types-parsers.hxx b/bpkg/types-parsers.hxx
index d687156..007d754 100644
--- a/bpkg/types-parsers.hxx
+++ b/bpkg/types-parsers.hxx
@@ -7,6 +7,8 @@
#ifndef BPKG_TYPES_PARSERS_HXX
#define BPKG_TYPES_PARSERS_HXX
+#include <libbutl/standard-version.hxx>
+
#include <libbpkg/manifest.hxx>
#include <bpkg/types.hxx>
@@ -59,6 +61,19 @@ namespace bpkg
};
template <>
+ struct parser<butl::standard_version>
+ {
+ static void
+ parse (butl::standard_version&, bool&, scanner&);
+
+ static void
+ merge (butl::standard_version& b, const butl::standard_version& a)
+ {
+ b = a;
+ }
+ };
+
+ template <>
struct parser<auth>
{
static void
diff --git a/doc/manual.cli b/doc/manual.cli
index cbca17d..86fe17f 100644
--- a/doc/manual.cli
+++ b/doc/manual.cli
@@ -1772,12 +1772,12 @@ The repository fragment id this repository belongs to.
terminology and semantics.
The repository list manifest (the \c{repositories.manifest} file found in the
-repository root directory) describes the repository. It is a sequence of
-repository manifests consisting of the base repository manifest (that is, the
-manifest for the repository that is being described) as well as manifests for
-its prerequisite and complement repositories. The individual repository
-manifests can appear in any order and the base repository manifest can be
-omitted.
+repository root directory) describes the repository. It starts with an
+optional header manifest optionally followed by a sequence of repository
+manifests consisting of the base repository manifest (that is, the manifest
+for the repository that is being described) as well as manifests for its
+prerequisite and complement repositories. The individual repository manifests
+can appear in any order and the base repository manifest can be omitted.
The \c{fragment} values can only be present in a merged
\c{repositories.manifest} file for a multi-fragment repository.
@@ -1789,6 +1789,8 @@ repository could look like this:
# math/testing
#
: 1
+min-bpkg-version: 0.14.0
+:
email: math-pkg@example.org
summary: Math package repository
:
@@ -1814,6 +1816,37 @@ Then the completement's location would be:
https://pkg.example.org/1/math/stable
\
+The header manifest synopsis is presented next followed by the detailed
+description of each value in subsequent sections.
+
+\
+[min-bpkg-version]: <ver>
+[compression]: <compressions>
+\
+
+\h2#manifest-repository-list-header-min-bpkg-version|\c{min-bpkg-version}|
+
+\
+[min-bpkg-version]: <ver>
+\
+
+The earliest version of \cb{bpkg} that is compatible with this repository.
+Note that if specified, it must be the first value in the header.
+
+
+\h2#manifest-repository-list-header-compression|\c{compression}|
+
+\
+[compression]: <compressions>
+
+<compressions> = <compression> [ <compression>]*
+\
+
+Available compressed variants of the \c{packages.manifest} file. The format is
+a space-separated list of the compression methods. The \c{none} method means
+no compression. Absent \c{compression} value is equivalent to specifying it
+with the \c{none} value.
+
\h#manifest-signature-pkg|Signature Manifest for \cb{pkg} Repositories|