aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bpkg/fetch-git.cxx4
-rw-r--r--bpkg/manifest-utility.cxx1
-rw-r--r--bpkg/manifest-utility.hxx1
-rw-r--r--bpkg/package.cxx77
-rw-r--r--bpkg/package.hxx309
-rw-r--r--bpkg/package.ixx6
-rw-r--r--bpkg/package.xml20
-rw-r--r--bpkg/pkg-build.cxx50
-rw-r--r--bpkg/pkg-checkout.cxx5
-rw-r--r--bpkg/pkg-configure.cxx1
-rw-r--r--bpkg/pkg-fetch.cxx1
-rw-r--r--bpkg/pkg-purge.cxx23
-rw-r--r--bpkg/pkg-status.cxx6
-rw-r--r--bpkg/pkg-unpack.cxx31
-rw-r--r--bpkg/pkg-unpack.hxx3
-rw-r--r--bpkg/pkg-verify.cxx5
-rw-r--r--bpkg/rep-fetch.cxx95
-rw-r--r--tests/common/git/state0/libbar.tarbin71680 -> 71680 bytes
-rw-r--r--tests/common/git/state0/libfoo.tarbin296960 -> 296960 bytes
-rw-r--r--tests/common/git/state0/style-basic.tarbin71680 -> 71680 bytes
-rw-r--r--tests/common/git/state0/style.tarbin133120 -> 133120 bytes
-rw-r--r--tests/common/git/state1/libbaz.tarbin61440 -> 61440 bytes
-rw-r--r--tests/common/git/state1/libfoo.tarbin378880 -> 378880 bytes
-rw-r--r--tests/common/git/state1/style-basic.tarbin71680 -> 71680 bytes
-rw-r--r--tests/common/git/state1/style.tarbin133120 -> 133120 bytes
-rw-r--r--tests/pkg-build.test101
-rw-r--r--tests/rep-fetch.test147
l---------tests/rep-fetch/libhello-1.0.01
28 files changed, 732 insertions, 155 deletions
diff --git a/bpkg/fetch-git.cxx b/bpkg/fetch-git.cxx
index 833c3a7..c22bafb 100644
--- a/bpkg/fetch-git.cxx
+++ b/bpkg/fetch-git.cxx
@@ -1056,8 +1056,8 @@ namespace bpkg
if (verb)
info << "re-cloning " << rl.canonical_name ()
<< " due to location change" <<
- info << "new location " << rl.url () <<
- info << "old location " << u;
+ info << "new location " << rl <<
+ info << "old location " << l;
rm_r (d);
return git_clone (co, rl, destdir);
diff --git a/bpkg/manifest-utility.cxx b/bpkg/manifest-utility.cxx
index b35af4a..4a7d0db 100644
--- a/bpkg/manifest-utility.cxx
+++ b/bpkg/manifest-utility.cxx
@@ -20,6 +20,7 @@ namespace bpkg
const path repositories_file ("repositories.manifest");
const path packages_file ("packages.manifest");
const path signature_file ("signature.manifest");
+ const path manifest_file ("manifest");
package_scheme
parse_package_scheme (const char*& s)
diff --git a/bpkg/manifest-utility.hxx b/bpkg/manifest-utility.hxx
index e7bc149..e7be005 100644
--- a/bpkg/manifest-utility.hxx
+++ b/bpkg/manifest-utility.hxx
@@ -15,6 +15,7 @@ namespace bpkg
extern const path repositories_file; // repositories.manifest
extern const path packages_file; // packages.manifest
extern const path signature_file; // signature.manifest
+ extern const path manifest_file; // manifest
// Package naming schemes.
//
diff --git a/bpkg/package.cxx b/bpkg/package.cxx
index 2e5bffe..966be72 100644
--- a/bpkg/package.cxx
+++ b/bpkg/package.cxx
@@ -8,12 +8,14 @@
#include <algorithm> // find_if()
#include <bpkg/database.hxx>
+#include <bpkg/checksum.hxx>
+#include <bpkg/manifest-utility.hxx>
using namespace std;
namespace bpkg
{
- const version wildcard_version (0, "0", nullopt, 0);
+ const version wildcard_version (0, "0", nullopt, 0, 0);
// available_package_id
//
@@ -158,6 +160,79 @@ namespace bpkg
return os;
}
+ optional<version>
+ package_iteration (const common_options& o,
+ const dir_path& c,
+ transaction& t,
+ const dir_path& d,
+ const string& n,
+ const version& v,
+ bool check_external)
+ {
+ tracer trace ("package_iteration");
+
+ database& db (t.database ());
+ tracer_guard tg (db, trace);
+
+ if (check_external)
+ {
+ using query = query<package_repository>;
+
+ query q (
+ query::package::id.name == n &&
+ compare_version_eq (query::package::id.version, v, true, false));
+
+ for (const auto& pr: db.query<package_repository> (q))
+ {
+ const shared_ptr<repository>& r (pr.repository);
+
+ if (r->location.directory_based ())
+ fail << "external package " << n << '/' << v
+ << " is already available from "
+ << r->location.canonical_name ();
+ }
+ }
+
+ shared_ptr<selected_package> p (db.find<selected_package> (n));
+
+ if (p == nullptr || !p->src_root ||
+ compare_version_ne (v, p->version, true, false))
+ return nullopt;
+
+ string mc (sha256 (o, d / manifest_file));
+
+ assert (p->manifest_checksum);
+
+ bool changed (mc != *p->manifest_checksum);
+
+ // If the manifest didn't changed but the selected package points to an
+ // external source directory, then we also check if the directory have
+ // moved.
+ //
+ if (!changed && p->external ())
+ {
+ dir_path src_root (p->src_root->absolute ()
+ ? *p->src_root
+ : c / *p->src_root);
+
+ // We need to complete and normalize the source directory as it may
+ // generally be completed against the configuration directory (unlikely
+ // but possible), that can be relative and/or not normalized.
+ //
+ src_root.complete ().normalize ();
+
+ changed = src_root != dir_path (d).complete ().normalize ();
+ }
+
+ return !changed
+ ? p->version
+ : version (v.epoch,
+ v.upstream,
+ v.release,
+ v.revision,
+ p->version.iteration + 1);
+ }
+
// state
//
string
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index 5905dd2..8c714c4 100644
--- a/bpkg/package.hxx
+++ b/bpkg/package.hxx
@@ -17,6 +17,7 @@
#include <libbutl/timestamp.mxx>
#include <bpkg/types.hxx>
+#include <bpkg/forward.hxx> // transaction
#include <bpkg/utility.hxx>
#pragma db model version(4, 4, open)
@@ -93,6 +94,7 @@ namespace bpkg
string canonical_upstream;
string canonical_release;
uint16_t revision;
+ uint32_t iteration;
string upstream;
optional<string> release;
};
@@ -134,6 +136,7 @@ namespace bpkg
string canonical_upstream;
string canonical_release;
uint16_t revision;
+ uint32_t iteration;
// By default SQLite3 uses BINARY collation for TEXT columns. So while this
// means we don't need to do anything special to make "absent" (~) and
@@ -147,14 +150,14 @@ namespace bpkg
#pragma db value transient
struct upstream_version: version
{
- #pragma db member(upstream_) virtual(string) \
- get(this.upstream) \
- set(this = bpkg::version (0, std::move (?), std::string (), 0))
+ #pragma db member(upstream_) virtual(string) \
+ get(this.upstream) \
+ set(this = bpkg::version (0, std::move (?), std::string (), 0, 0))
#pragma db member(release_) virtual(optional_string) \
get(this.release) \
set(this = bpkg::version ( \
- 0, std::move (this.upstream), std::move (?), 0))
+ 0, std::move (this.upstream), std::move (?), 0, 0))
upstream_version () = default;
upstream_version (version v): version (move (v)) {}
@@ -164,7 +167,12 @@ namespace bpkg
void
init (const canonical_version& cv, const upstream_version& uv)
{
- *this = version (cv.epoch, uv.upstream, uv.release, cv.revision);
+ *this = version (cv.epoch,
+ uv.upstream,
+ uv.release,
+ cv.revision,
+ cv.iteration);
+
assert (cv.canonical_upstream == canonical_upstream &&
cv.canonical_release == canonical_release);
}
@@ -175,12 +183,14 @@ namespace bpkg
(?).canonical_upstream, \
(?).canonical_release, \
(?).revision, \
+ (?).iteration, \
(?).upstream, \
(?).release}) \
from(bpkg::version ((?).epoch, \
std::move ((?).upstream), \
std::move ((?).release), \
- (?).revision))
+ (?).revision, \
+ (?).iteration))
using optional_version = optional<version>;
using _optional_version = optional<_version>;
@@ -191,6 +201,7 @@ namespace bpkg
(?)->canonical_upstream, \
(?)->canonical_release, \
(?)->revision, \
+ (?)->iteration, \
(?)->upstream, \
(?)->release} \
: bpkg::_optional_version ()) \
@@ -198,7 +209,8 @@ namespace bpkg
? bpkg::version ((?)->epoch, \
std::move ((?)->upstream), \
std::move ((?)->release), \
- (?)->revision) \
+ (?)->revision, \
+ (?)->iteration) \
: bpkg::optional_version ())
// repository_location
@@ -279,7 +291,6 @@ namespace bpkg
operator size_t () const {return result;}
};
-
// package_location
//
#pragma db value
@@ -596,6 +607,11 @@ namespace bpkg
optional<dir_path> src_root;
bool purge_src;
+ // The checksum of the manifest file located in the source directory.
+ // Must be present if the source directory is present.
+ //
+ optional<string> manifest_checksum;
+
// Path to the output directory of this package, if any. It is
// always relative to the configuration directory, and is <name>
// for external packages and <name>-<version> for others. It is
@@ -656,6 +672,47 @@ namespace bpkg
ostream&
operator<< (ostream&, const selected_package&);
+ // Check if the directory containing the specified package version should be
+ // considered its iteration. Return the version of this iteration if that's
+ // the case and nullopt otherwise.
+ //
+ // Notes:
+ //
+ // - The package directory is considered an iteration of the package if this
+ // upstream version and revision is already present (selected) in the
+ // configuration and has a source directory. If that's the case, then the
+ // specified directory path and the checksum of the manifest file it
+ // contains are compared to the ones of the package present in the
+ // configuration. If both match, then the present package version
+ // (including its iteration, if any) is returned. Otherwise (the package
+ // has moved and/or the packaging information has changed), the present
+ // package version with the incremented iteration number is returned. Note
+ // that the directory path is matched only for the external selected
+ // packages.
+ //
+ // - Only a single package iteration is valid per version in the
+ // configuration. This, in particular, means that a package of the
+ // specific upstream version and revision shouldn't come from multiple
+ // external (source) directories.
+ //
+ // If requested, the function checks if an external package of this
+ // upstream version and revision is already available in the configuration
+ // and fails if that's the case.
+ //
+ // - The manifest file located in the specified directory is not parsed, and
+ // so is not checked to match the specified package name and version.
+ //
+ class common_options;
+
+ optional<version>
+ package_iteration (const common_options&,
+ const dir_path& configuration,
+ transaction&,
+ const dir_path&,
+ const string& name,
+ const version&,
+ bool check_external);
+
// certificate
//
// Information extracted from a repository X.509 certificate. The actual
@@ -809,17 +866,18 @@ namespace bpkg
// Return a list of packages available from this repository.
//
- #pragma db view object(repository) \
- table("available_package_locations" = "pl" inner: \
- "pl.repository = " + repository::name) \
- object(available_package = package inner: \
- "pl.name = " + package::id.name + "AND" + \
- "pl.version_epoch = " + package::id.version.epoch + "AND" + \
- "pl.version_canonical_upstream = " + \
- package::id.version.canonical_upstream + "AND" + \
- "pl.version_canonical_release = " + \
- package::id.version.canonical_release + "AND" + \
- "pl.version_revision = " + package::id.version.revision)
+ #pragma db view object(repository) \
+ table("available_package_locations" = "pl" inner: \
+ "pl.repository = " + repository::name) \
+ object(available_package = package inner: \
+ "pl.name = " + package::id.name + "AND" + \
+ "pl.version_epoch = " + package::id.version.epoch + "AND" + \
+ "pl.version_canonical_upstream = " + \
+ package::id.version.canonical_upstream + "AND" + \
+ "pl.version_canonical_release = " + \
+ package::id.version.canonical_release + "AND" + \
+ "pl.version_revision = " + package::id.version.revision + "AND" + \
+ "pl.version_iteration = " + package::id.version.iteration)
struct repository_package
{
shared_ptr<available_package> package; // Must match the alias (see above).
@@ -827,18 +885,47 @@ namespace bpkg
operator const shared_ptr<available_package> () const {return package;}
};
+ // Return a list of repositories the packages come from.
+ //
+ #pragma db view object(repository) \
+ table("available_package_locations" = "pl" inner: \
+ "pl.repository = " + repository::name) \
+ object(available_package = package inner: \
+ "pl.name = " + package::id.name + "AND" + \
+ "pl.version_epoch = " + package::id.version.epoch + "AND" + \
+ "pl.version_canonical_upstream = " + \
+ package::id.version.canonical_upstream + "AND" + \
+ "pl.version_canonical_release = " + \
+ package::id.version.canonical_release + "AND" + \
+ "pl.version_revision = " + package::id.version.revision + "AND" + \
+ "pl.version_iteration = " + package::id.version.iteration)
+ struct package_repository
+ {
+ #pragma db column(package::id)
+ available_package_id package_id;
+
+ using repository_type = bpkg::repository;
+ shared_ptr<repository_type> repository;
+ };
+
// Version comparison operators.
//
// They allow comparing objects that have epoch, canonical_upstream,
- // canonical_release, and revision data members. The idea is that this
- // works for both query members of types version and canonical_version
+ // canonical_release, revision, and iteration data members. The idea is that
+ // this works for both query members of types version and canonical_version
// as well as for comparing canonical_version to version.
//
+ // Note that if the comparison operation ignores the revision, then it also
+ // unconditionally ignores the iteration (that semantically extends the
+ // revision).
+ //
template <typename T1, typename T2>
inline auto
- compare_version_eq (const T1& x, const T2& y, bool revision)
+ compare_version_eq (const T1& x, const T2& y, bool revision, bool iteration)
-> decltype (x.epoch == y.epoch)
{
+ assert (revision || !iteration); // !revision && iteration is meaningless.
+
// Since we don't quite know what T1 and T2 are (and where the resulting
// expression will run), let's not push our luck with something like
// (!revision || x.revision == y.revision).
@@ -847,9 +934,11 @@ namespace bpkg
x.canonical_upstream == y.canonical_upstream &&
x.canonical_release == y.canonical_release);
- return revision
- ? r && x.revision == y.revision
- : r;
+ return !revision
+ ? r
+ : !iteration
+ ? r && x.revision == y.revision
+ : r && x.revision == y.revision && x.iteration == y.iteration;
}
/*
@@ -865,68 +954,111 @@ namespace bpkg
template <typename T1, typename T2>
inline auto
- compare_version_ne (const T1& x, const T2& y, bool revision)
+ compare_version_ne (const T1& x, const T2& y, bool revision, bool iteration)
-> decltype (x.epoch == y.epoch)
{
+ assert (revision || !iteration); // !revision && iteration is meaningless.
+
auto r (x.epoch != y.epoch ||
x.canonical_upstream != y.canonical_upstream ||
x.canonical_release != y.canonical_release);
- return revision
- ? r || x.revision != y.revision
- : r;
+ return !revision
+ ? r
+ : !iteration
+ ? r || x.revision != y.revision
+ : r || x.revision != y.revision || x.iteration != y.iteration;
}
template <typename T1, typename T2>
inline auto
operator!= (const T1& x, const T2& y) -> decltype (x.epoch != y.epoch)
{
- return compare_version_ne (x, y, true);
+ return compare_version_ne (x, y, true, true);
}
template <typename T1, typename T2>
inline auto
- compare_version_lt (const T1& x, const T2& y, bool revision)
+ compare_version_lt (const T1& x, const T2& y, bool revision, bool iteration)
-> decltype (x.epoch == y.epoch)
{
+ assert (revision || !iteration); // !revision && iteration is meaningless.
+
auto r (
x.epoch < y.epoch ||
(x.epoch == y.epoch && x.canonical_upstream < y.canonical_upstream) ||
(x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
x.canonical_release < y.canonical_release));
- return revision
- ? r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release == y.canonical_release && x.revision < y.revision)
- : r;
+ if (revision)
+ {
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision < y.revision);
+
+ if (iteration)
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision == y.revision &&
+ x.iteration < y.iteration);
+ }
+
+ return r;
}
template <typename T1, typename T2>
inline auto
operator< (const T1& x, const T2& y) -> decltype (x.epoch < y.epoch)
{
- return compare_version_lt (x, y, true);
+ return compare_version_lt (x, y, true, true);
}
template <typename T1, typename T2>
inline auto
- compare_version_le (const T1& x, const T2& y, bool revision)
+ compare_version_le (const T1& x, const T2& y, bool revision, bool iteration)
-> decltype (x.epoch == y.epoch)
{
+ assert (revision || !iteration); // !revision && iteration is meaningless.
+
auto r (
x.epoch < y.epoch ||
(x.epoch == y.epoch && x.canonical_upstream < y.canonical_upstream));
- return revision
- ? r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release < y.canonical_release) ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release == y.canonical_release && x.revision <= y.revision)
- : r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release <= y.canonical_release);
+ if (!revision)
+ {
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release <= y.canonical_release);
+ }
+ else
+ {
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release < y.canonical_release);
+
+ if (!iteration)
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision <= y.revision);
+ else
+ r = r ||
+
+ (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision < y.revision) ||
+
+ (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision == y.revision &&
+ x.iteration <= y.iteration);
+ }
+
+ return r;
}
/*
@@ -942,54 +1074,93 @@ namespace bpkg
template <typename T1, typename T2>
inline auto
- compare_version_gt (const T1& x, const T2& y, bool revision)
+ compare_version_gt (const T1& x, const T2& y, bool revision, bool iteration)
-> decltype (x.epoch == y.epoch)
{
+ assert (revision || !iteration); // !revision && iteration is meaningless.
+
auto r (
x.epoch > y.epoch ||
(x.epoch == y.epoch && x.canonical_upstream > y.canonical_upstream) ||
(x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
x.canonical_release > y.canonical_release));
- return revision
- ? r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release == y.canonical_release && x.revision > y.revision)
- : r;
+ if (revision)
+ {
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision > y.revision);
+
+ if (iteration)
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision == y.revision &&
+ x.iteration > y.iteration);
+ }
+
+ return r;
}
template <typename T1, typename T2>
inline auto
operator> (const T1& x, const T2& y) -> decltype (x.epoch > y.epoch)
{
- return compare_version_gt (x, y, true);
+ return compare_version_gt (x, y, true, true);
}
template <typename T1, typename T2>
inline auto
- compare_version_ge (const T1& x, const T2& y, bool revision)
+ compare_version_ge (const T1& x, const T2& y, bool revision, bool iteration)
-> decltype (x.epoch == y.epoch)
{
+ assert (revision || !iteration); // !revision && iteration is meaningless.
+
auto r (
x.epoch > y.epoch ||
(x.epoch == y.epoch && x.canonical_upstream > y.canonical_upstream));
- return revision
- ? r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release > y.canonical_release) ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release == y.canonical_release && x.revision >= y.revision)
- : r ||
- (x.epoch == y.epoch && x.canonical_upstream == y.canonical_upstream &&
- x.canonical_release >= y.canonical_release);
+ if (!revision)
+ {
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release >= y.canonical_release);
+ }
+ else
+ {
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release > y.canonical_release);
+
+ if (!iteration)
+ r = r || (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision >= y.revision);
+ else
+ r = r ||
+
+ (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision > y.revision) ||
+
+ (x.epoch == y.epoch &&
+ x.canonical_upstream == y.canonical_upstream &&
+ x.canonical_release == y.canonical_release &&
+ x.revision == y.revision &&
+ x.iteration >= y.iteration);
+ }
+
+ return r;
}
template <typename T1, typename T2>
inline auto
operator>= (const T1& x, const T2& y) -> decltype (x.epoch >= y.epoch)
{
- return compare_version_ge (x, y, true);
+ return compare_version_ge (x, y, true, true);
}
template <typename T>
@@ -1001,16 +1172,20 @@ namespace bpkg
+ x.epoch + "DESC,"
+ x.canonical_upstream + "DESC,"
+ x.canonical_release + "DESC,"
- + x.revision + "DESC";
+ + x.revision + "DESC,"
+ + x.iteration + "DESC";
}
+/*
+ Currently unused (and probably should stay that way).
template <typename T>
inline auto
order_by_revision_desc (const T& x) -> //decltype ("ORDER BY" + x.epoch)
decltype (x.revision == 0)
{
- return "ORDER BY" + x.revision + "DESC";
+ return "ORDER BY" + x.revision + "DESC," + x.iteration + "DESC";
}
+*/
}
#include <bpkg/package.ixx>
diff --git a/bpkg/package.ixx b/bpkg/package.ixx
index 26f63ff..5834e2e 100644
--- a/bpkg/package.ixx
+++ b/bpkg/package.ixx
@@ -9,7 +9,11 @@ namespace bpkg
inline available_package_id::
available_package_id (string n, const bpkg::version& v)
: name (move (n)),
- version {v.epoch, v.canonical_upstream, v.canonical_release, v.revision}
+ version {v.epoch,
+ v.canonical_upstream,
+ v.canonical_release,
+ v.revision,
+ v.iteration}
{
}
}
diff --git a/bpkg/package.xml b/bpkg/package.xml
index bc995be..10014e7 100644
--- a/bpkg/package.xml
+++ b/bpkg/package.xml
@@ -52,6 +52,7 @@
<column name="version_canonical_upstream" type="TEXT" null="true"/>
<column name="version_canonical_release" type="TEXT" null="true" options="COLLATE BINARY"/>
<column name="version_revision" type="INTEGER" null="true"/>
+ <column name="version_iteration" type="INTEGER" null="true"/>
<column name="version_upstream" type="TEXT" null="true"/>
<column name="version_release" type="TEXT" null="true"/>
<column name="sha256sum" type="TEXT" null="true"/>
@@ -61,6 +62,7 @@
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
</primary-key>
</table>
<table name="available_package_locations" kind="container">
@@ -69,6 +71,7 @@
<column name="version_canonical_upstream" type="TEXT" null="true"/>
<column name="version_canonical_release" type="TEXT" null="true" options="COLLATE BINARY"/>
<column name="version_revision" type="INTEGER" null="true"/>
+ <column name="version_iteration" type="INTEGER" null="true"/>
<column name="repository" type="TEXT" null="true"/>
<column name="fragment" type="TEXT" null="true"/>
<column name="location" type="TEXT" null="true"/>
@@ -78,12 +81,14 @@
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
<references table="available_package">
<column name="name"/>
<column name="version_epoch"/>
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
</references>
</foreign-key>
<index name="available_package_locations_object_id_i">
@@ -92,6 +97,7 @@
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
</index>
<foreign-key name="repository_fk" deferrable="DEFERRED">
<column name="repository"/>
@@ -106,6 +112,7 @@
<column name="version_canonical_upstream" type="TEXT" null="true"/>
<column name="version_canonical_release" type="TEXT" null="true" options="COLLATE BINARY"/>
<column name="version_revision" type="INTEGER" null="true"/>
+ <column name="version_iteration" type="INTEGER" null="true"/>
<column name="index" type="INTEGER" null="true"/>
<column name="conditional" type="INTEGER" null="true"/>
<column name="buildtime" type="INTEGER" null="true"/>
@@ -116,12 +123,14 @@
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
<references table="available_package">
<column name="name"/>
<column name="version_epoch"/>
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
</references>
</foreign-key>
<index name="available_package_dependencies_object_id_i">
@@ -130,6 +139,7 @@
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
</index>
<index name="available_package_dependencies_index_i">
<column name="index"/>
@@ -141,6 +151,7 @@
<column name="version_canonical_upstream" type="TEXT" null="true"/>
<column name="version_canonical_release" type="TEXT" null="true" options="COLLATE BINARY"/>
<column name="version_revision" type="INTEGER" null="true"/>
+ <column name="version_iteration" type="INTEGER" null="true"/>
<column name="dependency_index" type="INTEGER" null="true"/>
<column name="index" type="INTEGER" null="true"/>
<column name="dep_name" type="TEXT" null="true"/>
@@ -148,12 +159,14 @@
<column name="dep_min_version_canonical_upstream" type="TEXT" null="true"/>
<column name="dep_min_version_canonical_release" type="TEXT" null="true"/>
<column name="dep_min_version_revision" type="INTEGER" null="true"/>
+ <column name="dep_min_version_iteration" type="INTEGER" null="true"/>
<column name="dep_min_version_upstream" type="TEXT" null="true"/>
<column name="dep_min_version_release" type="TEXT" null="true"/>
<column name="dep_max_version_epoch" type="INTEGER" null="true"/>
<column name="dep_max_version_canonical_upstream" type="TEXT" null="true"/>
<column name="dep_max_version_canonical_release" type="TEXT" null="true"/>
<column name="dep_max_version_revision" type="INTEGER" null="true"/>
+ <column name="dep_max_version_iteration" type="INTEGER" null="true"/>
<column name="dep_max_version_upstream" type="TEXT" null="true"/>
<column name="dep_max_version_release" type="TEXT" null="true"/>
<column name="dep_min_open" type="INTEGER" null="true"/>
@@ -164,12 +177,14 @@
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
<references table="available_package">
<column name="name"/>
<column name="version_epoch"/>
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
</references>
</foreign-key>
<index name="available_package_dependency_alternatives_object_id_i">
@@ -178,6 +193,7 @@
<column name="version_canonical_upstream"/>
<column name="version_canonical_release"/>
<column name="version_revision"/>
+ <column name="version_iteration"/>
</index>
</table>
<table name="selected_package" kind="object">
@@ -186,6 +202,7 @@
<column name="version_canonical_upstream" type="TEXT" null="true"/>
<column name="version_canonical_release" type="TEXT" null="true"/>
<column name="version_revision" type="INTEGER" null="true"/>
+ <column name="version_iteration" type="INTEGER" null="true"/>
<column name="version_upstream" type="TEXT" null="true"/>
<column name="version_release" type="TEXT" null="true"/>
<column name="state" type="TEXT" null="true"/>
@@ -198,6 +215,7 @@
<column name="purge_archive" type="INTEGER" null="true"/>
<column name="src_root" type="TEXT" null="true"/>
<column name="purge_src" type="INTEGER" null="true"/>
+ <column name="manifest_checksum" type="TEXT" null="true"/>
<column name="out_root" type="TEXT" null="true"/>
<primary-key>
<column name="name"/>
@@ -210,12 +228,14 @@
<column name="min_version_canonical_upstream" type="TEXT" null="true"/>
<column name="min_version_canonical_release" type="TEXT" null="true"/>
<column name="min_version_revision" type="INTEGER" null="true"/>
+ <column name="min_version_iteration" type="INTEGER" null="true"/>
<column name="min_version_upstream" type="TEXT" null="true"/>
<column name="min_version_release" type="TEXT" null="true"/>
<column name="max_version_epoch" type="INTEGER" null="true"/>
<column name="max_version_canonical_upstream" type="TEXT" null="true"/>
<column name="max_version_canonical_release" type="TEXT" null="true"/>
<column name="max_version_revision" type="INTEGER" null="true"/>
+ <column name="max_version_iteration" type="INTEGER" null="true"/>
<column name="max_version_upstream" type="TEXT" null="true"/>
<column name="max_version_release" type="TEXT" null="true"/>
<column name="min_open" type="INTEGER" null="true"/>
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index 4621fb9..9d58cc2 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -85,7 +85,11 @@ namespace bpkg
// subsequent revision of a package version are just as (un)satisfactory
// as the first one.
//
- query qs (compare_version_eq (vm, wildcard_version, false));
+ // Also note that we always compare ignoring the iteration, as it can
+ // not be specified in the manifest/command line. This way the latest
+ // iteration will always be picked up.
+ //
+ query qs (compare_version_eq (vm, wildcard_version, false, false));
if (c->min_version &&
c->max_version &&
@@ -93,7 +97,7 @@ namespace bpkg
{
const version& v (*c->min_version);
- q = q && (compare_version_eq (vm, v, v.revision != 0) || qs);
+ q = q && (compare_version_eq (vm, v, v.revision != 0, false) || qs);
}
else
{
@@ -104,9 +108,9 @@ namespace bpkg
const version& v (*c->min_version);
if (c->min_open)
- qr = compare_version_gt (vm, v, v.revision != 0);
+ qr = compare_version_gt (vm, v, v.revision != 0, false);
else
- qr = compare_version_ge (vm, v, v.revision != 0);
+ qr = compare_version_ge (vm, v, v.revision != 0, false);
}
if (c->max_version)
@@ -114,9 +118,9 @@ namespace bpkg
const version& v (*c->max_version);
if (c->max_open)
- qr = qr && compare_version_lt (vm, v, v.revision != 0);
+ qr = qr && compare_version_lt (vm, v, v.revision != 0, false);
else
- qr = qr && compare_version_le (vm, v, v.revision != 0);
+ qr = qr && compare_version_le (vm, v, v.revision != 0, false);
}
q = q && (qr || qs);
@@ -177,8 +181,7 @@ namespace bpkg
// Copy the possibly fixed up version from the selected package.
//
- if (sp->external ())
- m.version = sp->version;
+ m.version = sp->version;
return make_pair (make_shared<available_package> (move (m)), move (ar));
}
@@ -1463,19 +1466,22 @@ namespace bpkg
package_manifest m (pkg_verify (d, true, diag));
+ // This is a package directory.
+ //
+ l4 ([&]{trace << "directory " << d;});
+ n = m.name;
+
// Fix-up the package version to properly decide if we need to
- // upgrade/downgrade the package.
+ // upgrade/downgrade the package. Note that throwing failed
+ // from here on will be fatal.
//
- optional<version> pv (package_version (o, d));
+ if (optional<version> v = package_version (o, d))
+ m.version = move (*v);
- if (pv)
- m.version = move (*pv);
+ if (optional<version> v = package_iteration (
+ o, c, t, d, n, m.version, true /* check_external */))
+ m.version = move (*v);
- // This is a package directory (note that we shouldn't throw
- // failed from here on).
- //
- l4 ([&]{trace << "directory " << d;});
- n = m.name;
v = m.version;
ap = make_shared<available_package> (move (m));
ar = root;
@@ -1491,7 +1497,12 @@ namespace bpkg
}
catch (const failed&)
{
- // Not a valid package directory.
+ // If the package name is detected then this is a valid package
+ // directory, but something went wrong afterwards, and we are
+ // done in this case.
+ //
+ if (!n.empty ())
+ throw;
}
}
}
@@ -2094,7 +2105,8 @@ namespace bpkg
}
case repository_basis::directory:
{
- sp = pkg_unpack (c,
+ sp = pkg_unpack (o,
+ c,
t,
ap->id.name,
p.available_version (),
diff --git a/bpkg/pkg-checkout.cxx b/bpkg/pkg-checkout.cxx
index 14f84cb..6e4a7a5 100644
--- a/bpkg/pkg-checkout.cxx
+++ b/bpkg/pkg-checkout.cxx
@@ -9,6 +9,7 @@
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
+#include <bpkg/checksum.hxx>
#include <bpkg/diagnostics.hxx>
#include <bpkg/manifest-utility.hxx>
@@ -162,6 +163,8 @@ namespace bpkg
false /* quiet */,
strings ({"config.dist.root=" + c.representation ()}));
+ string mc (sha256 (o, d / manifest_file));
+
if (p != nullptr)
{
// Clean up the source directory and archive of the package we are
@@ -175,6 +178,7 @@ namespace bpkg
p->repository = rl;
p->src_root = d.leaf ();
p->purge_src = true;
+ p->manifest_checksum = move (mc);
db.update (p);
}
@@ -194,6 +198,7 @@ namespace bpkg
false,
d.leaf (), // Source root.
true, // Purge directory.
+ move (mc),
nullopt, // No output directory yet.
{}}); // No prerequisites captured yet.
diff --git a/bpkg/pkg-configure.cxx b/bpkg/pkg-configure.cxx
index 2bb1b20..e23fca1 100644
--- a/bpkg/pkg-configure.cxx
+++ b/bpkg/pkg-configure.cxx
@@ -209,6 +209,7 @@ namespace bpkg
false, // No auto-purge (does not get there).
nullopt, // No source directory.
false,
+ nullopt, // No manifest checksum.
nullopt, // No output directory.
{}}); // No prerequisites.
diff --git a/bpkg/pkg-fetch.cxx b/bpkg/pkg-fetch.cxx
index 664c92f..71bd968 100644
--- a/bpkg/pkg-fetch.cxx
+++ b/bpkg/pkg-fetch.cxx
@@ -79,6 +79,7 @@ namespace bpkg
purge,
nullopt, // No source directory yet.
false,
+ nullopt, // No manifest checksum.
nullopt, // No output directory yet.
{}}); // No prerequisites captured yet.
diff --git a/bpkg/pkg-purge.cxx b/bpkg/pkg-purge.cxx
index fa5ce01..e1cd113 100644
--- a/bpkg/pkg-purge.cxx
+++ b/bpkg/pkg-purge.cxx
@@ -37,19 +37,30 @@ namespace bpkg
if (exists (d)) // Don't complain if someone did our job for us.
rm_r (d);
- p->src_root = nullopt;
p->purge_src = false;
}
- if (p->purge_archive && archive)
+ // Let's forget about the possibly non-purged source directory, as the
+ // selected package may now be reused for unrelated package version.
+ //
+ p->src_root = nullopt;
+ p->manifest_checksum = nullopt;
+
+ if (archive)
{
- path a (p->archive->absolute () ? *p->archive : c / *p->archive);
+ if (p->purge_archive)
+ {
+ path a (p->archive->absolute () ? *p->archive : c / *p->archive);
- if (exists (a))
- rm (a);
+ if (exists (a))
+ rm (a);
+ p->purge_archive = false;
+ }
+
+ // Let's forget about the possibly non-purged archive (see above).
+ //
p->archive = nullopt;
- p->purge_archive = false;
}
}
catch (const failed&)
diff --git a/bpkg/pkg-status.cxx b/bpkg/pkg-status.cxx
index b440ad9..e5144ca 100644
--- a/bpkg/pkg-status.cxx
+++ b/bpkg/pkg-status.cxx
@@ -65,7 +65,8 @@ namespace bpkg
if (!p.version.empty ())
q = q && compare_version_eq (query::id.version,
p.version,
- p.version.revision != 0);
+ p.version.revision != 0,
+ false);
// And if we found an existing package, then only look for versions
// greater than what already exists. Note that for a system wildcard
@@ -233,7 +234,8 @@ namespace bpkg
if (!p.version.empty ())
q = q && compare_version_eq (query::version,
p.version,
- p.version.revision != 0);
+ p.version.revision != 0,
+ false);
p.selected = db.query_one<selected_package> (q);
}
diff --git a/bpkg/pkg-unpack.cxx b/bpkg/pkg-unpack.cxx
index d9d54ea..41c72f4 100644
--- a/bpkg/pkg-unpack.cxx
+++ b/bpkg/pkg-unpack.cxx
@@ -15,6 +15,7 @@
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
+#include <bpkg/checksum.hxx>
#include <bpkg/diagnostics.hxx>
#include <bpkg/manifest-utility.hxx>
@@ -60,8 +61,11 @@ namespace bpkg
}
}
+ // Select the external package in this configuration.
+ //
static shared_ptr<selected_package>
- pkg_unpack (dir_path c,
+ pkg_unpack (const common_options& o,
+ dir_path c,
transaction& t,
string n,
version v,
@@ -74,6 +78,8 @@ namespace bpkg
database& db (t.database ());
tracer_guard tg (db, trace);
+ string mc (sha256 (o, d / manifest_file));
+
// Make the package and configuration paths absolute and normalized.
// If the package is inside the configuration, use the relative path.
// This way we can move the configuration around.
@@ -99,6 +105,7 @@ namespace bpkg
p->repository = move (rl);
p->src_root = move (d);
p->purge_src = purge;
+ p->manifest_checksum = move (mc);
db.update (p);
}
@@ -116,12 +123,15 @@ namespace bpkg
false, // Don't purge archive.
move (d),
purge,
+ move (mc),
nullopt, // No output directory yet.
{}}); // No prerequisites captured yet.
db.persist (p);
}
+ assert (p->external ());
+
t.commit ();
return p;
}
@@ -150,15 +160,18 @@ namespace bpkg
// Fix-up the package version.
//
- optional<version> v (package_version (o, d));
+ if (optional<version> v = package_version (o, d))
+ m.version = move (*v);
- if (v)
+ if (optional<version> v = package_iteration (
+ o, c, t, d, m.name, m.version, true /* check_external */))
m.version = move (*v);
// Use the special root repository as the repository of this
// package.
//
- return pkg_unpack (c,
+ return pkg_unpack (o,
+ c,
t,
move (m.name),
move (m.version),
@@ -168,7 +181,8 @@ namespace bpkg
}
shared_ptr<selected_package>
- pkg_unpack (const dir_path& c,
+ pkg_unpack (const common_options& o,
+ const dir_path& c,
transaction& t,
string n,
version v,
@@ -224,7 +238,8 @@ namespace bpkg
const repository_location& rl (pl->repository->location);
- return pkg_unpack (c,
+ return pkg_unpack (o,
+ c,
t,
move (n),
move (v),
@@ -386,6 +401,8 @@ namespace bpkg
p->src_root = d.leaf (); // For now assuming to be in configuration.
p->purge_src = true;
+ p->manifest_checksum = sha256 (co, d / manifest_file);
+
p->state = package_state::unpacked;
db.update (p);
@@ -444,7 +461,7 @@ namespace bpkg
//
p = v.empty ()
? pkg_unpack (o, c, t, n)
- : pkg_unpack (c, t, move (n), move (v), o.replace ());
+ : pkg_unpack (o, c, t, move (n), move (v), o.replace ());
}
if (verb && !o.no_result ())
diff --git a/bpkg/pkg-unpack.hxx b/bpkg/pkg-unpack.hxx
index a04d197..83acb97 100644
--- a/bpkg/pkg-unpack.hxx
+++ b/bpkg/pkg-unpack.hxx
@@ -40,7 +40,8 @@ namespace bpkg
// repository and commit the transaction.
//
shared_ptr<selected_package>
- pkg_unpack (const dir_path& configuration,
+ pkg_unpack (const common_options&,
+ const dir_path& configuration,
transaction&,
string name,
version,
diff --git a/bpkg/pkg-verify.cxx b/bpkg/pkg-verify.cxx
index 3d96136..a220480 100644
--- a/bpkg/pkg-verify.cxx
+++ b/bpkg/pkg-verify.cxx
@@ -9,6 +9,7 @@
#include <bpkg/archive.hxx>
#include <bpkg/diagnostics.hxx>
+#include <bpkg/manifest-utility.hxx>
using namespace std;
using namespace butl;
@@ -20,7 +21,7 @@ namespace bpkg
try
{
dir_path pd (package_dir (af));
- path mf (pd / path ("manifest"));
+ path mf (pd / manifest_file);
// If diag is false, we need to make tar not print any diagnostics. There
// doesn't seem to be an option to suppress this and the only way is to
@@ -115,7 +116,7 @@ namespace bpkg
{
// Parse the manifest.
//
- path mf (d / path ("manifest"));
+ path mf (d / manifest_file);
if (!exists (mf))
{
diff --git a/bpkg/rep-fetch.cxx b/bpkg/rep-fetch.cxx
index 343f97b..9558301 100644
--- a/bpkg/rep-fetch.cxx
+++ b/bpkg/rep-fetch.cxx
@@ -201,7 +201,7 @@ namespace bpkg
};
dir_path d (repo_dir / path_cast<dir_path> (*sm.location));
- path f (d / path ("manifest"));
+ path f (d / manifest_file);
if (!exists (f))
failure ("no manifest file");
@@ -272,20 +272,6 @@ namespace bpkg
ignore_unknown,
rl));
- // @@ Here we will need to go through packages and check if there is the
- // selected package of the same version (without regards to the
- // iteration component), and having the different package manifest
- // hash. If that's the case then set the manifest version iteration
- // component as the selected package version iteation + 1.
- //
- // @@ It also seems that the manifest hash should be stored in the (new)
- // member of the package_location struct. Later this value will be
- // transmitted into the selected package objects by pkg_unpack().
- //
- // @@ Should we later check and fail if any available package contains
- // several package locations with different non-zero (for those that
- // come from the directory repo) manifest hashes?
- //
return rep_fetch_data {move (rms), move (fps), nullptr};
}
@@ -689,6 +675,29 @@ namespace bpkg
{
package_manifest& pm (fp.manifest);
+ // Fix-up the external package version iteration number.
+ //
+ if (rl.directory_based ())
+ {
+ // Note that we can't check if the external package of this upstream
+ // version and revision is already available in the configuration
+ // until we fetch all the repositories, as some of the available
+ // packages are still due to be removed.
+ //
+ optional<version> v (
+ package_iteration (
+ co,
+ conf,
+ t,
+ path_cast<dir_path> (rl.path () / *fp.manifest.location),
+ pm.name,
+ pm.version,
+ false /* check_external */));
+
+ if (v)
+ pm.version = move (*v);
+ }
+
// We might already have this package in the database.
//
bool persist (false);
@@ -757,6 +766,11 @@ namespace bpkg
bool shallow,
const optional<string>& reason)
{
+ tracer trace ("rep_fetch(repos)");
+
+ database& db (t.database ());
+ tracer_guard tg (db, trace);
+
// As a fist step we fetch repositories recursively building the list of
// the former prerequisites and complements to be considered for removal.
//
@@ -774,13 +788,62 @@ namespace bpkg
repositories fetched;
repositories removed;
+ // Fetch the requested repositories, recursively.
+ //
for (const lazy_shared_ptr<repository>& r: repos)
rep_fetch (o, conf, t, r.load (), fetched, removed, shallow, reason);
- // Finally, remove dangling repositories.
+ // Remove dangling repositories.
//
for (const shared_ptr<repository>& r: removed)
rep_remove (conf, t, r);
+
+ // Finally, make sure that the external packages are available from a
+ // single repository.
+ //
+ // Sort the packages by name and version. This way the external packages
+ // with the same upstream version and revision will be adjacent.
+ //
+ using query = query<package_repository>;
+ const auto& qv (query::package::id.version);
+
+ query q ("ORDER BY" + query::package::id.name + "," +
+ qv.epoch + "," +
+ qv.canonical_upstream + "," +
+ qv.canonical_release + "," +
+ qv.revision + "," +
+ qv.iteration);
+
+ available_package_id ap;
+ shared_ptr<repository> rp;
+
+ for (const auto& pr: db.query<package_repository> (q))
+ {
+ const shared_ptr<repository>& r (pr.repository);
+ if (!r->location.directory_based ())
+ continue;
+
+ // Fail if the external package is of the same upstream version and
+ // revision as the previous one.
+ //
+ const available_package_id& id (pr.package_id);
+
+ if (id.name == ap.name &&
+ compare_version_eq (id.version, ap.version, true, false))
+ {
+ shared_ptr<available_package> p (db.load<available_package> (id));
+ const version& v (p->version);
+
+ fail << "external package " << id.name << '/'
+ << version (v.epoch, v.upstream, v.release, v.revision, 0)
+ << " is available from two repositories" <<
+ info << "repository " << rp->location <<
+ info << "repository " << r->location;
+ }
+
+ ap = id;
+ rp = r;
+ }
}
catch (const failed&)
{
diff --git a/tests/common/git/state0/libbar.tar b/tests/common/git/state0/libbar.tar
index 4861d35..bbb6f81 100644
--- a/tests/common/git/state0/libbar.tar
+++ b/tests/common/git/state0/libbar.tar
Binary files differ
diff --git a/tests/common/git/state0/libfoo.tar b/tests/common/git/state0/libfoo.tar
index 2707476..6f9af32 100644
--- a/tests/common/git/state0/libfoo.tar
+++ b/tests/common/git/state0/libfoo.tar
Binary files differ
diff --git a/tests/common/git/state0/style-basic.tar b/tests/common/git/state0/style-basic.tar
index 9444ab8..6a7a1f2 100644
--- a/tests/common/git/state0/style-basic.tar
+++ b/tests/common/git/state0/style-basic.tar
Binary files differ
diff --git a/tests/common/git/state0/style.tar b/tests/common/git/state0/style.tar
index 7989e77..6295f34 100644
--- a/tests/common/git/state0/style.tar
+++ b/tests/common/git/state0/style.tar
Binary files differ
diff --git a/tests/common/git/state1/libbaz.tar b/tests/common/git/state1/libbaz.tar
index b2bf286..ee8ad3e 100644
--- a/tests/common/git/state1/libbaz.tar
+++ b/tests/common/git/state1/libbaz.tar
Binary files differ
diff --git a/tests/common/git/state1/libfoo.tar b/tests/common/git/state1/libfoo.tar
index 859637a..4221cdd 100644
--- a/tests/common/git/state1/libfoo.tar
+++ b/tests/common/git/state1/libfoo.tar
Binary files differ
diff --git a/tests/common/git/state1/style-basic.tar b/tests/common/git/state1/style-basic.tar
index a8a3a88..8bc8b85 100644
--- a/tests/common/git/state1/style-basic.tar
+++ b/tests/common/git/state1/style-basic.tar
Binary files differ
diff --git a/tests/common/git/state1/style.tar b/tests/common/git/state1/style.tar
index 8ef9104..feedcaa 100644
--- a/tests/common/git/state1/style.tar
+++ b/tests/common/git/state1/style.tar
Binary files differ
diff --git a/tests/pkg-build.test b/tests/pkg-build.test
index fefaf00..e70bb1a 100644
--- a/tests/pkg-build.test
+++ b/tests/pkg-build.test
@@ -57,34 +57,17 @@
# | |-- libbar-1.2.0.tar.gz
# | `-- repositories.manifest
# |
-# `-- git
-# | |-- libbar.git -> style-basic.git (prerequisite)
-# | |-- libbaz.git
-# | `-- style-basic.git
+# |-- libhello-1.0.0
+# | |-- build
+# | | |-- bootstrap.build
+# | | |-- export.build
+# | | `-- root.build
+# | `-- *
# |
-# `-- libhello-1.0.0
-# |-- build
-# | |-- bootstrap.build
-# | |-- export.build
-# | `-- root.build
-# |-- buildfile
-# |-- hello
-# | |-- buildfile
-# | |-- export
-# | |-- hello
-# | `-- hello.cxx
-# |-- INSTALL
-# |-- manifest
-# |-- tests
-# | |-- build
-# | | |-- bootstrap.build
-# | | `-- root.build
-# | |-- buildfile
-# | `-- test
-# | |-- buildfile
-# | |-- driver.cxx
-# | `-- test.out
-# `-- version
+# `-- git
+# |-- libbar.git -> style-basic.git (prerequisite)
+# |-- libbaz.git
+# `-- style-basic.git
# Prepare repositories used by tests if running in the local mode.
#
@@ -114,6 +97,7 @@ pkg_purge += -d cfg
pkg_status += -d cfg
pkg_unpack += -d cfg 2>!
rep_add += -d cfg 2>!
+rep_remove += -d cfg 2>!
rep_fetch += -d cfg --auth all --trust-yes 2>!
: libfoo
@@ -805,7 +789,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>!
disfigured libfoo/1.0.0
using libfoo/1.1.0 (external)
configured libfoo/1.1.0
- %info: .+dir\{libfoo-1.1.0.\} is up to date%
+ %info: .+dir\{libfoo.\} is up to date%
updated libfoo/1.1.0
EOE
@@ -1565,6 +1549,9 @@ rep_fetch += -d cfg --auth all --trust-yes 2>!
+$clone_cfg
+ # @@ Uncomment the following tests when -p option is supported for the cp
+ # builtin.
+ #\
: dir-repo
:
: Test that libhello is built incrementally. May re-link due to the
@@ -1593,6 +1580,11 @@ rep_fetch += -d cfg --auth all --trust-yes 2>!
{
+$clone_cfg
+ # To avoid 'external package is already available' failure for the
+ # nested tests.
+ #
+ +$rep_remove --all
+
: arg
:
{
@@ -1627,6 +1619,7 @@ rep_fetch += -d cfg --auth all --trust-yes 2>!
test -d cfg/libhello-1.0.1/ == 1
}
}
+ #\
: archive
:
@@ -1700,6 +1693,58 @@ rep_fetch += -d cfg --auth all --trust-yes 2>!
-$pkg_purge libhello 2>'purged libhello/1.0.0'
}
+: iter
+:
+{
+ test.arguments += --yes # Is a command-specific option.
+
+ : already-available
+ :
+ {
+ $clone_root_cfg;
+ $rep_add $src/libfoo-1.1.0 --type dir && $rep_fetch;
+
+ $* $src/libfoo-1.1.0/ 2>>~%EOE% != 0
+ %error: external package libfoo/1.1.0 is already available from dir:.+libfoo-1.1.0%
+ EOE
+ }
+
+ : upgrade
+ :
+ {
+ $clone_root_cfg;
+
+ $* $src/libfoo-1.1.0/ 2>>~%EOE%;
+ using libfoo/1.1.0 (external)
+ configured libfoo/1.1.0
+ %info: .+dir\{libfoo.\} is up to date%
+ updated libfoo/1.1.0
+ EOE
+
+ cp -r $src/libfoo-1.1.0 libfoo;
+
+ $* libfoo/ 2>>~%EOE%;
+ disfigured libfoo/1.1.0
+ using libfoo/1.1.0#1 (external)
+ configured libfoo/1.1.0#1
+ %info: .+dir\{libfoo.\} is up to date%
+ updated libfoo/1.1.0#1
+ EOE
+
+ $rep_add $src/libfoo-1.1.0 --type dir && $rep_fetch;
+
+ $* libfoo 2>>~%EOE%;
+ disfigured libfoo/1.1.0#1
+ using libfoo/1.1.0#2 (external)
+ configured libfoo/1.1.0#2
+ %info: .+dir\{libfoo.\} is up to date%
+ updated libfoo/1.1.0#2
+ EOE
+
+ $pkg_disfigure libfoo 2>'disfigured libfoo/1.1.0#2'
+ }
+}
+
: git-rep
:
if ($git_supported != true)
diff --git a/tests/rep-fetch.test b/tests/rep-fetch.test
index 1ee0d4b..535627d 100644
--- a/tests/rep-fetch.test
+++ b/tests/rep-fetch.test
@@ -32,6 +32,13 @@
# | |-- libhello-1.0.0.tar.gz
# | `-- repositories.manifest
# |
+# |-- libhello-1.0.0
+# | |-- build
+# | | |-- bootstrap.build
+# | | |-- export.build
+# | | `-- root.build
+# | `-- *
+# |
# |-- circle
# | |-- extra -> stable (prerequisite)
# | | |-- libbar-1.1.0+1.tar.gz
@@ -102,9 +109,14 @@
$git_extract $src/git/state1/style-basic.tar &$out_git/state1/***
end
-rep_add += -d cfg 2>!
-rep_list += -d cfg --prerequisites --complements
-pkg_status += -d cfg
+rep_add += -d cfg 2>!
+rep_list += -d cfg --prerequisites --complements
+rep_remove += -d cfg 2>!
+pkg_status += -d cfg
+pkg_fetch += -d cfg 2>!
+pkg_unpack += -d cfg 2>!
+pkg_checkout += -d cfg 2>!
+pkg_purge += -d cfg
: no-repos
:
@@ -403,6 +415,135 @@ if ($remote != true)
}
}
+: iter
+:
+{
+ rep_add += --type dir
+
+ : multiple-repos
+ :
+ {
+ cp -r $src/libhello-1.0.0 libhello1;
+ cp -r $src/libhello-1.0.0 libhello2;
+
+ $clone_root_cfg && $rep_add libhello1 libhello2;
+
+ $* 2>>~%EOE% != 0
+ %fetching dir:.+libhello1%
+ %fetching dir:.+libhello2%
+ error: external package libhello/1.0.0 is available from two repositories
+ % info: repository .+libhello1%
+ % info: repository .+libhello2%
+ EOE
+ }
+
+ : inc
+ :
+ {
+ : path-changed
+ :
+ {
+ $clone_root_cfg && $rep_add $src/libhello-1.0.0;
+
+ $* 2>!;
+ $pkg_unpack libhello/1.0.0;
+
+ $rep_remove --all;
+
+ cp -r $src/libhello-1.0.0 libhello;
+ $rep_add libhello;
+
+ $* 2>!;
+
+ $pkg_status libhello >'unpacked 1.0.0; available 1.0.0#1 sys:?'
+ }
+
+ : manifest-changed
+ :
+ {
+ cp -r $src/libhello-1.0.0 libhello;
+
+ $clone_root_cfg && $rep_add libhello;
+
+ $* 2>!;
+ $pkg_unpack libhello/1.0.0;
+
+ echo "" >+ libhello/manifest;
+ $* 2>!;
+
+ $pkg_status libhello >'unpacked 1.0.0; available 1.0.0#1 sys:?'
+ }
+
+ : pkg-rep
+ {
+ +$clone_root_cfg
+
+ +$* --auth all --trust-yes $rep/hello &cfg/.bpkg/certs/** 2>!
+ +$pkg_fetch libhello/1.0.0
+ +$pkg_unpack libhello
+
+ : unchanged-external
+ :
+ {
+ $clone_cfg && $rep_add $src/libhello-1.0.0;
+ $* 2>!;
+
+ $pkg_status libhello >'unpacked 1.0.0; available sys:?'
+ }
+
+ : changed-external
+ :
+ {
+ cp -r $src/libhello-1.0.0 libhello;
+ echo "" >+ libhello/manifest;
+
+ $clone_cfg && $rep_add libhello;
+ $* 2>!;
+
+ $pkg_status libhello >'unpacked 1.0.0; available 1.0.0#1 sys:?'
+ }
+
+ -$pkg_purge libhello 2>'purged libhello/1.0.0'
+ }
+
+ : git-rep
+ :
+ if ($remote != true)
+ {
+ rep = $canonicalize([dir_path] $out_git/state0);
+
+ $clone_root_cfg;
+
+ $* "$rep/style.git#master" 2>! &cfg/.bpkg/repos/*/***;
+ $pkg_checkout "style/1.0.0" 2>!;
+
+ $rep_add $rep/style.git;
+ $* 2>!;
+
+ $pkg_status style >"unpacked 1.0.0; available sys:?";
+
+ $pkg_purge style 2>"purged style/1.0.0"
+ }
+ }
+
+ : no-inc
+ :
+ {
+ $clone_root_cfg;
+
+ $pkg_unpack -e $src/libhello-1.0.0;
+
+ $rep_add $src/libhello-1.0.0;
+
+ $* 2>>~%EOE%;
+ %fetching dir:.+libhello-1.0.0%
+ 1 package(s) in 1 repository(s)
+ EOE
+
+ $pkg_status libhello >'unpacked 1.0.0; available sys:?'
+ }
+}
+
: git-rep
:
if ($git_supported != true)
diff --git a/tests/rep-fetch/libhello-1.0.0 b/tests/rep-fetch/libhello-1.0.0
new file mode 120000
index 0000000..614ff24
--- /dev/null
+++ b/tests/rep-fetch/libhello-1.0.0
@@ -0,0 +1 @@
+../common/libhello-1.0.0/ \ No newline at end of file