aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bpkg/auth.cxx1
-rw-r--r--bpkg/checksum.cxx2
-rw-r--r--bpkg/checksum.hxx6
-rw-r--r--bpkg/database.cxx4
-rw-r--r--bpkg/fetch-pkg.cxx10
-rw-r--r--bpkg/manifest-utility.cxx1
-rw-r--r--bpkg/package-configuration.cxx491
-rw-r--r--bpkg/package-configuration.hxx206
-rw-r--r--bpkg/package-skeleton.cxx2588
-rw-r--r--bpkg/package-skeleton.hxx275
-rw-r--r--bpkg/package.cxx34
-rw-r--r--bpkg/package.hxx119
-rw-r--r--bpkg/package.xml7
-rw-r--r--bpkg/pkg-build.cli11
-rw-r--r--bpkg/pkg-build.cxx5709
-rw-r--r--bpkg/pkg-configure.cxx196
-rw-r--r--bpkg/pkg-configure.hxx15
-rw-r--r--bpkg/pkg-drop.cxx12
-rw-r--r--bpkg/pkg-fetch.cxx6
-rw-r--r--bpkg/pkg-status.cxx2
-rw-r--r--bpkg/rep-create.cxx18
-rw-r--r--bpkg/rep-info.cxx1
-rw-r--r--bpkg/types.hxx7
-rw-r--r--bpkg/utility.hxx4
-rw-r--r--tests/common/dependency-alternatives/t11a/bac-1.0.0.tar.gzbin0 -> 472 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bar-0.1.0.tar.gzbin0 -> 462 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bar-1.0.0.tar.gzbin0 -> 454 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bas-1.0.0.tar.gzbin0 -> 465 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bat-1.0.0.tar.gzbin0 -> 452 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bax-1.0.0.tar.gzbin0 -> 435 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/baz-0.1.0.tar.gzbin0 -> 421 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/baz-1.0.0.tar.gzbin0 -> 413 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bex-1.0.0.tar.gzbin0 -> 357 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bix-1.0.0.tar.gzbin0 -> 414 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/biz-1.0.0.tar.gzbin0 -> 449 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/boo-1.0.0.tar.gzbin0 -> 460 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/box-0.1.0.tar.gzbin0 -> 402 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/box-1.0.0.tar.gzbin0 -> 415 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/buc-1.0.0.tar.gzbin0 -> 465 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bus-1.0.0.tar.gzbin0 -> 464 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/bux-1.0.0.tar.gzbin0 -> 454 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/buz-1.0.0.tar.gzbin0 -> 449 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/dex-1.0.0.tar.gzbin0 -> 465 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/dix-1.0.0.tar.gzbin0 -> 472 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/diz-1.0.0.tar.gzbin0 -> 473 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/dox-1.0.0.tar.gzbin0 -> 445 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fex-1.0.0.tar.gzbin0 -> 455 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fix-0.1.0.tar.gzbin0 -> 421 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fix-1.0.0.tar.gzbin0 -> 450 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/foo-0.1.0.tar.gzbin0 -> 454 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/foo-1.0.0.tar.gzbin0 -> 456 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fox-1.0.0.tar.gzbin0 -> 399 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/fux-1.0.0.tar.gzbin0 -> 419 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libbar-0.1.0.tar.gzbin0 -> 409 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libbar-1.0.0.tar.gzbin0 -> 406 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libbaz-0.1.0.tar.gzbin0 -> 412 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libbaz-1.0.0.tar.gzbin0 -> 410 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libbox-0.1.0.tar.gzbin0 -> 411 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libbox-1.0.0.tar.gzbin0 -> 408 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libfoo-0.1.0.tar.gzbin0 -> 411 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gzbin0 -> 409 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t11a/tax-1.0.0.tar.gzbin0 -> 462 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tex-0.1.0.tar.gzbin0 -> 451 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tex-0.2.0.tar.gzbin0 -> 462 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tex-0.3.0.tar.gzbin0 -> 466 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tex-1.0.0.tar.gzbin0 -> 461 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tez-1.0.0.tar.gzbin0 -> 481 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tix-0.1.0.tar.gzbin0 -> 407 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tix-1.0.0.tar.gzbin0 -> 460 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tiz-1.0.0.tar.gzbin0 -> 464 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/toz-0.1.0.tar.gzbin0 -> 406 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/toz-0.2.0.tar.gzbin0 -> 464 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/toz-1.0.0.tar.gzbin0 -> 482 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/tux-1.0.0.tar.gzbin0 -> 469 bytes
-rw-r--r--tests/common/dependency-alternatives/t13a/bar-1.0.0.tar.gzbin0 -> 530 bytes
-rw-r--r--tests/common/dependency-alternatives/t13a/baz-1.0.0.tar.gzbin0 -> 527 bytes
-rw-r--r--tests/common/dependency-alternatives/t13a/biz-1.0.0.tar.gzbin0 -> 450 bytes
-rw-r--r--tests/common/dependency-alternatives/t13a/liba-1.0.0.tar.gzbin0 -> 456 bytes
-rw-r--r--tests/common/dependency-alternatives/t13a/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13b/bar-1.0.0.tar.gzbin0 -> 439 bytes
-rw-r--r--tests/common/dependency-alternatives/t13b/baz-1.0.0.tar.gzbin0 -> 439 bytes
-rw-r--r--tests/common/dependency-alternatives/t13b/biz-1.0.0.tar.gzbin0 -> 399 bytes
-rw-r--r--tests/common/dependency-alternatives/t13b/liba-1.0.0.tar.gzbin0 -> 431 bytes
-rw-r--r--tests/common/dependency-alternatives/t13b/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13c/bar-1.0.0.tar.gzbin0 -> 468 bytes
-rw-r--r--tests/common/dependency-alternatives/t13c/baz-1.0.0.tar.gzbin0 -> 403 bytes
-rw-r--r--tests/common/dependency-alternatives/t13c/liba-1.0.0.tar.gzbin0 -> 401 bytes
-rw-r--r--tests/common/dependency-alternatives/t13c/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13d/bar-1.0.0.tar.gzbin0 -> 539 bytes
-rw-r--r--tests/common/dependency-alternatives/t13d/baz-1.0.0.tar.gzbin0 -> 407 bytes
-rw-r--r--tests/common/dependency-alternatives/t13d/liba-1.0.0.tar.gzbin0 -> 401 bytes
-rw-r--r--tests/common/dependency-alternatives/t13d/libb-1.0.0.tar.gzbin0 -> 347 bytes
-rw-r--r--tests/common/dependency-alternatives/t13d/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13e/bar-1.0.0.tar.gzbin0 -> 443 bytes
-rw-r--r--tests/common/dependency-alternatives/t13e/baz-1.0.0.tar.gzbin0 -> 448 bytes
-rw-r--r--tests/common/dependency-alternatives/t13e/biz-1.0.0.tar.gzbin0 -> 395 bytes
-rw-r--r--tests/common/dependency-alternatives/t13e/liba-1.0.0.tar.gzbin0 -> 422 bytes
-rw-r--r--tests/common/dependency-alternatives/t13e/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13f/bar-1.0.0.tar.gzbin0 -> 511 bytes
-rw-r--r--tests/common/dependency-alternatives/t13f/baz-1.0.0.tar.gzbin0 -> 458 bytes
-rw-r--r--tests/common/dependency-alternatives/t13f/liba-1.0.0.tar.gzbin0 -> 421 bytes
-rw-r--r--tests/common/dependency-alternatives/t13f/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13g/bar-1.0.0.tar.gzbin0 -> 533 bytes
-rw-r--r--tests/common/dependency-alternatives/t13g/baz-1.0.0.tar.gzbin0 -> 497 bytes
-rw-r--r--tests/common/dependency-alternatives/t13g/biz-1.0.0.tar.gzbin0 -> 538 bytes
-rw-r--r--tests/common/dependency-alternatives/t13g/box-1.0.0.tar.gzbin0 -> 535 bytes
-rw-r--r--tests/common/dependency-alternatives/t13g/liba-1.0.0.tar.gzbin0 -> 402 bytes
-rw-r--r--tests/common/dependency-alternatives/t13g/libb-1.0.0.tar.gzbin0 -> 347 bytes
-rw-r--r--tests/common/dependency-alternatives/t13g/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13h/bar-1.0.0.tar.gzbin0 -> 492 bytes
-rw-r--r--tests/common/dependency-alternatives/t13h/baz-1.0.0.tar.gzbin0 -> 416 bytes
-rw-r--r--tests/common/dependency-alternatives/t13h/liba-1.0.0.tar.gzbin0 -> 421 bytes
-rw-r--r--tests/common/dependency-alternatives/t13h/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13i/bar-1.0.0.tar.gzbin0 -> 481 bytes
-rw-r--r--tests/common/dependency-alternatives/t13i/baz-1.0.0.tar.gzbin0 -> 501 bytes
-rw-r--r--tests/common/dependency-alternatives/t13i/liba-1.0.0.tar.gzbin0 -> 421 bytes
-rw-r--r--tests/common/dependency-alternatives/t13i/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13j/bar-1.0.0.tar.gzbin0 -> 508 bytes
-rw-r--r--tests/common/dependency-alternatives/t13j/baz-1.0.0.tar.gzbin0 -> 398 bytes
-rw-r--r--tests/common/dependency-alternatives/t13j/biz-1.0.0.tar.gzbin0 -> 503 bytes
-rw-r--r--tests/common/dependency-alternatives/t13j/liba-1.0.0.tar.gzbin0 -> 494 bytes
-rw-r--r--tests/common/dependency-alternatives/t13j/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13k/bar-1.0.0.tar.gzbin0 -> 505 bytes
-rw-r--r--tests/common/dependency-alternatives/t13k/baz-1.0.0.tar.gzbin0 -> 417 bytes
-rw-r--r--tests/common/dependency-alternatives/t13k/liba-1.0.0.tar.gzbin0 -> 421 bytes
-rw-r--r--tests/common/dependency-alternatives/t13k/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13l/bar-1.0.0.tar.gzbin0 -> 433 bytes
-rw-r--r--tests/common/dependency-alternatives/t13l/baz-1.0.0.tar.gzbin0 -> 439 bytes
-rw-r--r--tests/common/dependency-alternatives/t13l/liba-1.0.0.tar.gzbin0 -> 404 bytes
-rw-r--r--tests/common/dependency-alternatives/t13l/libb-1.0.0.tar.gzbin0 -> 354 bytes
-rw-r--r--tests/common/dependency-alternatives/t13l/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13m/bar-1.0.0.tar.gzbin0 -> 401 bytes
-rw-r--r--tests/common/dependency-alternatives/t13m/baz-1.0.0.tar.gzbin0 -> 531 bytes
-rw-r--r--tests/common/dependency-alternatives/t13m/bix-1.0.0.tar.gzbin0 -> 407 bytes
-rw-r--r--tests/common/dependency-alternatives/t13m/biz-1.0.0.tar.gzbin0 -> 411 bytes
-rw-r--r--tests/common/dependency-alternatives/t13m/box-1.0.0.tar.gzbin0 -> 414 bytes
-rw-r--r--tests/common/dependency-alternatives/t13m/liba-1.0.0.tar.gzbin0 -> 422 bytes
-rw-r--r--tests/common/dependency-alternatives/t13m/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13n/bar-1.0.0.tar.gzbin0 -> 482 bytes
-rw-r--r--tests/common/dependency-alternatives/t13n/liba-1.0.0.tar.gzbin0 -> 351 bytes
-rw-r--r--tests/common/dependency-alternatives/t13n/libb-1.0.0.tar.gzbin0 -> 354 bytes
-rw-r--r--tests/common/dependency-alternatives/t13n/repositories.manifest1
-rw-r--r--tests/common/dependency-alternatives/t13o/bar-1.0.0.tar.gzbin0 -> 497 bytes
-rw-r--r--tests/common/dependency-alternatives/t13o/baz-1.0.0.tar.gzbin0 -> 398 bytes
-rw-r--r--tests/common/dependency-alternatives/t13o/bix-1.0.0.tar.gzbin0 -> 406 bytes
-rw-r--r--tests/common/dependency-alternatives/t13o/biz-1.0.0.tar.gzbin0 -> 407 bytes
-rw-r--r--tests/common/dependency-alternatives/t13o/liba-1.0.0.tar.gzbin0 -> 351 bytes
-rw-r--r--tests/common/dependency-alternatives/t13o/repositories.manifest1
-rw-r--r--tests/common/satisfy/t12a/libbar-0.1.0.tar.gzbin0 -> 386 bytes
-rw-r--r--tests/common/satisfy/t12a/libbaz-1.0.0.tar.gzbin0 -> 442 bytes
-rw-r--r--tests/common/satisfy/t12a/repositories.manifest1
-rw-r--r--tests/common/satisfy/t12b/bar-1.0.0.tar.gzbin0 -> 372 bytes
-rw-r--r--tests/common/satisfy/t12b/baz-0.1.0.tar.gzbin0 -> 359 bytes
-rw-r--r--tests/common/satisfy/t12b/baz-1.0.0.tar.gzbin0 -> 366 bytes
-rw-r--r--tests/common/satisfy/t12b/foo-0.1.0.tar.gzbin0 -> 357 bytes
-rw-r--r--tests/common/satisfy/t12b/foo-1.0.0.tar.gzbin0 -> 368 bytes
-rw-r--r--tests/common/satisfy/t12b/libbar-1.0.0.tar.gzbin0 -> 393 bytes
-rw-r--r--tests/common/satisfy/t12b/libbaz-0.1.0.tar.gzbin0 -> 443 bytes
-rw-r--r--tests/common/satisfy/t12b/repositories.manifest4
-rw-r--r--tests/pkg-build.testscript8763
l---------tests/pkg-build/t11a1
l---------tests/pkg-build/t12a1
l---------tests/pkg-build/t12b1
l---------tests/pkg-build/t13a1
l---------tests/pkg-build/t13b1
l---------tests/pkg-build/t13c1
l---------tests/pkg-build/t13d1
l---------tests/pkg-build/t13e1
l---------tests/pkg-build/t13f1
l---------tests/pkg-build/t13g1
l---------tests/pkg-build/t13h1
l---------tests/pkg-build/t13i1
l---------tests/pkg-build/t13j1
l---------tests/pkg-build/t13k1
l---------tests/pkg-build/t13l1
l---------tests/pkg-build/t13m1
l---------tests/pkg-build/t13n1
l---------tests/pkg-build/t13o1
179 files changed, 17434 insertions, 1093 deletions
diff --git a/bpkg/auth.cxx b/bpkg/auth.cxx
index 85cf5fa..663054d 100644
--- a/bpkg/auth.cxx
+++ b/bpkg/auth.cxx
@@ -7,7 +7,6 @@
#include <limits> // numeric_limits
#include <iterator> // ostreambuf_iterator
-#include <libbutl/sha256.hxx>
#include <libbutl/base64.hxx>
#include <libbutl/openssl.hxx>
#include <libbutl/timestamp.hxx>
diff --git a/bpkg/checksum.cxx b/bpkg/checksum.cxx
index 65ed377..b761d0b 100644
--- a/bpkg/checksum.cxx
+++ b/bpkg/checksum.cxx
@@ -331,7 +331,7 @@ namespace bpkg
}
string
- sha256 (const common_options& o, const path& f)
+ sha256sum (const common_options& o, const path& f)
{
if (!exists (f))
fail << "file " << f << " does not exist";
diff --git a/bpkg/checksum.hxx b/bpkg/checksum.hxx
index 73f52e8..54e5b3c 100644
--- a/bpkg/checksum.hxx
+++ b/bpkg/checksum.hxx
@@ -4,8 +4,6 @@
#ifndef BPKG_CHECKSUM_HXX
#define BPKG_CHECKSUM_HXX
-#include <libbutl/sha256.hxx>
-
#include <bpkg/types.hxx>
#include <bpkg/utility.hxx>
@@ -16,7 +14,7 @@ namespace bpkg
// Calculate SHA256 sum of the specified memory buffer in binary mode.
//
inline string
- sha256 (const char* buf, size_t n) {return butl::sha256 (buf, n).string ();}
+ sha256sum (const char* buf, size_t n) {return sha256 (buf, n).string ();}
// The same but for a file. Issue diagnostics and throw failed if anything
// goes wrong.
@@ -26,7 +24,7 @@ namespace bpkg
// optimized for the platform.
//
string
- sha256 (const common_options&, const path& file);
+ sha256sum (const common_options&, const path& file);
}
#endif // BPKG_CHECKSUM_HXX
diff --git a/bpkg/database.cxx b/bpkg/database.cxx
index b0a673e..d96c53b 100644
--- a/bpkg/database.cxx
+++ b/bpkg/database.cxx
@@ -10,8 +10,6 @@
#include <odb/schema-catalog.hxx>
#include <odb/sqlite/exceptions.hxx>
-#include <libbutl/sha256.hxx>
-
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/diagnostics.hxx>
@@ -706,7 +704,7 @@ namespace bpkg
//
std::string schema;
{
- butl::sha256 h (d.string ());
+ sha256 h (d.string ());
for (size_t n (4);; ++n)
{
diff --git a/bpkg/fetch-pkg.cxx b/bpkg/fetch-pkg.cxx
index 64abb43..ca4767f 100644
--- a/bpkg/fetch-pkg.cxx
+++ b/bpkg/fetch-pkg.cxx
@@ -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.
}
@@ -146,14 +146,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)
{
diff --git a/bpkg/manifest-utility.cxx b/bpkg/manifest-utility.cxx
index f690a40..d205c2d 100644
--- a/bpkg/manifest-utility.cxx
+++ b/bpkg/manifest-utility.cxx
@@ -6,7 +6,6 @@
#include <cstring> // strcspn()
#include <libbutl/b.hxx>
-#include <libbutl/sha256.hxx>
#include <bpkg/package.hxx> // wildcard_version
#include <bpkg/diagnostics.hxx>
diff --git a/bpkg/package-configuration.cxx b/bpkg/package-configuration.cxx
new file mode 100644
index 0000000..e8ea13a
--- /dev/null
+++ b/bpkg/package-configuration.cxx
@@ -0,0 +1,491 @@
+// file : bpkg/package-configuration.cxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <bpkg/package-configuration.hxx>
+
+#include <sstream>
+
+#include <bpkg/package-skeleton.hxx>
+
+namespace bpkg
+{
+ using build2::config::variable_origin;
+
+ string
+ serialize_cmdline (const string& name, const optional<build2::names>& value)
+ {
+ using namespace build2;
+
+ string r (name + '=');
+
+ if (!value)
+ r += "[null]";
+ else
+ {
+ if (!value->empty ())
+ {
+ // Note: we need to use command-line (effective) quoting.
+ //
+ ostringstream os;
+ to_stream (os, *value, quote_mode::effective, '@');
+ r += os.str ();
+ }
+ }
+
+ return r;
+ }
+
+ void package_configuration::
+ print (diag_record& dr,
+ const char* indent,
+ const dependent_config_variable_values* ovrs) const
+ {
+ bool first (true);
+ for (const config_variable_value& v: *this)
+ {
+ if (v.origin != variable_origin::buildfile &&
+ v.origin != variable_origin::override_)
+ continue;
+
+ if (first)
+ first = false;
+ else
+ dr << '\n';
+
+ dr << indent;
+
+ if (ovrs != nullptr && v.origin == variable_origin::buildfile)
+ {
+ if (const dependent_config_variable_value* ov = ovrs->find (v.name))
+ {
+ dr << ov->serialize_cmdline () << " (set by " << ov->dependent << ')';
+ continue;
+ }
+ }
+
+ dr << v.serialize_cmdline () << " (";
+
+ if (v.origin == variable_origin::buildfile)
+ dr << "set by " << *v.dependent;
+ else
+ dr << "user configuration";
+
+ dr << ')';
+ }
+ }
+
+ void
+ to_checksum (sha256& cs, const config_variable_value& v)
+ {
+ using namespace build2;
+
+ cs.append (v.name);
+ cs.append (static_cast<uint8_t> (v.origin));
+ if (v.type)
+ cs.append (*v.type);
+
+ if (v.origin != variable_origin::undefined)
+ {
+ if (v.value)
+ for (const name& n: *v.value)
+ to_checksum (cs, n);
+
+ if (v.origin == variable_origin::buildfile)
+ {
+ cs.append (v.dependent->string ());
+ cs.append (v.confirmed);
+ }
+ }
+ }
+
+ bool
+ negotiate_configuration (
+ package_configurations& cfgs,
+ package_skeleton& dept,
+ pair<size_t, size_t> pos,
+ const small_vector<reference_wrapper<package_skeleton>, 1>& depcs)
+ {
+ assert (!dept.system);
+
+ pos.first--; pos.second--; // Convert to 0-base.
+
+ const dependency_alternative& da (
+ dept.available->dependencies[pos.first][pos.second]);
+
+ assert (da.require || da.prefer);
+
+ // Step 1: save a snapshot of the old configuration while unsetting values
+ // that have this dependent as the originator and reloading the defaults.
+ //
+ // The idea behind unsetting values previously (first) set by this
+ // dependent is to allow it to "change its mind" based on other changes in
+ // the configuration (e.g., some expensive feature got enabled by another
+ // dependent which this dependent might as well use).
+ //
+ // This works well if the default values of configuration variables are
+ // independent. However, consider this example:
+ //
+ // dependency:
+ //
+ // config [bool] config.foo.x ?= false
+ // config [bool] config.foo.buf ?= ($config.foo.x ? 8196 : 4096)
+ //
+ // dependent:
+ //
+ // config.foo.x = true
+ // config.foo.buf = ($config.foo.buf < 6144 ? 6144 : $config.foo.buf)
+ //
+ // Here if we unset both x and buf to their defaults, we will get an
+ // incorrect result.
+ //
+ // The long-term solution here is to track dependencies between
+ // configuration variables (which we can do as part of the config
+ // directive via our parser::lookup_variable() hook and save this
+ // information in the config module's saved_variables list). Then, we
+ // "levelize" all the variables and have an inner "refinement" loop over
+ // these levels. Specifically, we first unset all of them. Then we unset
+ // all except the first level (which contains configuration variables that
+ // don't depend on any others). And so on.
+ //
+ // And until we implement this, we expect the dependent to take such
+ // configuration variable dependencies into account. For example:
+ //
+ // config.foo.x = true
+ // config.foo.buf = ($config.foo.buf < 6144
+ // ? ($config.foo.x ? 8196 : 6144)
+ // : $config.foo.buf)
+ //
+ // Another issue with this "originating dependent" logic is that it will
+ // be tricky to scale to containers where we would need to track
+ // originating dependents for individual elements of a value rather than
+ // the whole value as we do now. As an example, consider some "set of
+ // enabled backends" configuration variable. Technically, this doesn't
+ // seem insurmountable if we make some assumptions (e.g., if a value
+ // contains multiple elements, then it is such a set-like value; or
+ // we could use actual type names).
+ //
+ // For now we recommend to use multiple bool configurations to handle such
+ // cases (and, in fact, we currently don't have any set/map-like types,
+ // which we may want to add in the future). However, one could come up
+ // with some open-ended configuration list that will be difficult to
+ // support with bool. For example, we may need to support a set of buffer
+ // sizes or some such.
+ //
+ // Our assumptions regarding require:
+ //
+ // - Can only set bool configuration variables and only to true.
+ //
+ // - Should not have any conditions on the state of other configuration
+ // variables, including their origin (but can have other conditions,
+ // for example on the target platform).
+ //
+ // This means that we don't need to set the default values, but will need
+ // the type information as well as overrides. So what we will do is only
+ // call reload_defaults() for the first time to load types/override. Note
+ // that this assumes the set of configuration variables cannot change
+ // based on the values of other configuration variables (we have a note
+ // in the manual instructing the user not to do this).
+ //
+ // The dependency could also be system in which case there could be no
+ // skeleton information to load the types/defaults from. In this case we
+ // can handle require in the "lax mode" (based on the above assumptions)
+ // but not prefer.
+ //
+ // While at it, also collect the configurations to pass to dependent's
+ // evaluate_*() calls.
+ //
+ dependent_config_variable_values old_cfgs;
+ package_skeleton::dependency_configurations depc_cfgs;
+ depc_cfgs.reserve (depcs.size ());
+
+ for (package_skeleton& depc: depcs)
+ {
+ package_configuration& cfg (cfgs[depc.package]);
+
+ for (config_variable_value& v: cfg)
+ {
+ if (v.origin == variable_origin::buildfile)
+ {
+ if (*v.dependent == dept.package)
+ {
+ old_cfgs.push_back (
+ dependent_config_variable_value {
+ v.name, move (v.value), move (*v.dependent)});
+
+ // Note that we will not reload it to default in case of require.
+ //
+ v.undefine ();
+ }
+ else
+ old_cfgs.push_back (
+ dependent_config_variable_value {v.name, v.value, *v.dependent});
+ }
+ }
+
+ if (depc.available == nullptr)
+ {
+ assert (depc.system);
+
+ if (da.prefer)
+ fail << "unable to negotiate configuration for system dependency "
+ << depc.package << " without configuration information" <<
+ info << "consider specifying system dependency version that has "
+ << "corresponding available package" <<
+ info << "dependent " << dept.package << " has prefer/accept clauses "
+ << "that cannot be evaluated without configuration information";
+
+ if (!cfg.system)
+ {
+ // Note that we still need the overrides.
+ //
+ depc.load_overrides (cfg);
+ cfg.system = true;
+ }
+
+ continue;
+ }
+ else
+ assert (!cfg.system);
+
+ if (da.prefer || cfg.empty ())
+ depc.reload_defaults (cfg);
+ }
+
+ // Note that we need to collect the dependency configurations as a
+ // separate loop so that the stored references are not invalidated by
+ // operator[] (which is really a push_back() into a vector).
+ //
+ for (package_skeleton& depc: depcs)
+ depc_cfgs.push_back (cfgs[depc.package]);
+
+ // Step 2: execute the prefer/accept or requires clauses.
+ //
+ if (!(da.require
+ ? dept.evaluate_require (depc_cfgs, *da.require, pos)
+ : dept.evaluate_prefer_accept (depc_cfgs,
+ *da.prefer, *da.accept, pos)))
+ {
+ diag_record dr (fail);
+
+ dr << "unable to negotiate acceptable configuration with dependent "
+ << dept.package << " for dependencies ";
+
+ for (size_t i (0); i != depcs.size (); ++i)
+ dr << (i == 0 ? "" : ", ") << depcs[i].get ().package;
+
+ dr << info << "configuration before negotiation:\n";
+
+ // Note that we won't print this dependent's values (which we have unset
+ // above), but that seems like a good thing since they are not the cause
+ // of this impasse.
+ //
+ for (const package_configuration& cfg: depc_cfgs)
+ cfg.print (dr, " "); // Note 4 spaces since in nested info.
+ }
+
+ // Check if anything changed by comparing to entries in old_cfgs.
+ //
+ // While at it, also detect if we have any changes where one dependent
+ // overrides a value set by another dependent (see below).
+ //
+ bool cycle (false);
+ {
+ optional<size_t> n (0); // Number of unchanged.
+
+ for (package_skeleton& depc: depcs)
+ {
+ package_configuration& cfg (cfgs[depc.package]);
+
+ for (config_variable_value& v: cfg)
+ {
+ if (v.origin == variable_origin::buildfile)
+ {
+ if (const dependent_config_variable_value* ov =
+ old_cfgs.find (v.name))
+ {
+ if (ov->value == v.value)
+ {
+ // If the value hasn't change, so shouldn't the originating
+ // dependent.
+ //
+ assert (ov->dependent == *v.dependent);
+
+ if (n)
+ ++*n;
+
+ continue;
+ }
+ else
+ {
+ // Note that it's possible the same dependent overrides its
+ // old value (e.g., because a conditional default changed to a
+ // better value).
+ //
+ if (ov->dependent != *v.dependent)
+ cycle = true;
+ }
+ }
+
+ n = nullopt;
+
+ if (cycle)
+ break;
+ }
+ }
+
+ if (!n && cycle)
+ break;
+ }
+
+ // If we haven't seen any changed and we've seen the same number, then
+ // nothing has changed.
+ //
+ if (n && *n == old_cfgs.size ())
+ return false;
+ }
+
+ // Besides the dependent returning false from its accept clause, there is
+ // another manifestation of the inability to negotiate an acceptable
+ // configuration: two dependents keep changing the same configuration to
+ // mutually unacceptable values. To detect this, we need to look for
+ // negotiation cycles.
+ //
+ // Specifically, given a linear change history in the form:
+ //
+ // O->N ... O->N ... O->N
+ //
+ // We need to look for a possibility of turning it into a cycle:
+ //
+ // O->N ... O->N
+ // \ ... /
+ //
+ // Where O->N is a change that involves one dependent overriding a value
+ // set by another dependent and `...` are identical history segments.
+ //
+ if (!cycle)
+ return true;
+
+ // Populate new_cfgs.
+ //
+ dependent_config_variable_values new_cfgs;
+ for (package_skeleton& depc: depcs)
+ {
+ package_configuration& cfg (cfgs[depc.package]);
+
+ for (config_variable_value& v: cfg)
+ {
+ if (v.origin == variable_origin::buildfile)
+ {
+ new_cfgs.push_back (
+ dependent_config_variable_value {v.name, v.value, *v.dependent});
+ }
+ }
+ }
+
+ // Sort both.
+ //
+ {
+ auto cmp = [] (const dependent_config_variable_value& x,
+ const dependent_config_variable_value& y)
+ {
+ return x.name < y.name;
+ };
+
+ sort (old_cfgs.begin (), old_cfgs.end (), cmp);
+ sort (new_cfgs.begin (), new_cfgs.end (), cmp);
+ }
+
+ // Look backwards for identical O->N changes and see if we can come
+ // up with two identical segments between them.
+ //
+ cycle = false;
+
+ auto& change_history (cfgs.change_history_);
+
+ for (size_t n (change_history.size ()), i (n); i != 0; i -= 2)
+ {
+ if (change_history[i - 2] == old_cfgs &&
+ change_history[i - 1] == new_cfgs)
+ {
+ size_t d (n - i); // Segment length.
+
+ // See if there is an identical segment before this that also starts
+ // with O->N.
+ //
+ if (i < 2 + d + 2)
+ break; // Not long enough to possibly find anything.
+
+ size_t j (i - 2 - d); // Earlier O->N.
+
+ if (change_history[j - 2] == old_cfgs &&
+ change_history[j - 1] == new_cfgs)
+ {
+ if (equal (change_history.begin () + j,
+ change_history.begin () + j + d,
+ change_history.begin () + i))
+ {
+ cycle = true;
+ break;
+ }
+ }
+
+ // Otherwise, keep looking for a potentially longer segment.
+ }
+ }
+
+ if (!cycle)
+ {
+ change_history.push_back (move (old_cfgs));
+ change_history.push_back (move (new_cfgs));
+
+ return true;
+ }
+
+ diag_record dr (fail);
+
+ dr << "unable to negotiate acceptable configuration between dependents "
+ << dept.package;
+
+ // Analyze the O->N changes and determine the problematic dependent(s).
+ // Do we actually know for sure they are all problematic? Well, they
+ // repeatedly changed the values to the ones we don't like, so I guess so.
+ //
+ small_vector<reference_wrapper<const package_key>, 1> depts; // Duplicates.
+ for (const dependent_config_variable_value& nv: new_cfgs)
+ {
+ if (nv.dependent == dept.package)
+ {
+ if (const dependent_config_variable_value* ov = old_cfgs.find (nv.name))
+ {
+ if (ov->value != nv.value && ov->dependent != nv.dependent)
+ {
+ if (find_if (depts.begin (), depts.end (),
+ [ov] (reference_wrapper<const package_key> pk)
+ {
+ return ov->dependent == pk.get ();
+ }) == depts.end ())
+ {
+ dr << ", " << ov->dependent;
+ depts.push_back (ov->dependent);
+ }
+ }
+ }
+ }
+ }
+
+ dr << " for dependencies ";
+
+ for (size_t i (0); i != depcs.size (); ++i)
+ dr << (i == 0 ? "" : ", ") << depcs[i].get ().package;
+
+ dr << info << "configuration before negotiation:\n";
+ for (const package_configuration& cfg: depc_cfgs)
+ cfg.print (dr, " ", &old_cfgs);
+
+ dr << info << "configuration after negotiation:\n";
+ for (const package_configuration& cfg: depc_cfgs)
+ cfg.print (dr, " ");
+
+ dr << endf;
+ }
+}
diff --git a/bpkg/package-configuration.hxx b/bpkg/package-configuration.hxx
new file mode 100644
index 0000000..73f05ff
--- /dev/null
+++ b/bpkg/package-configuration.hxx
@@ -0,0 +1,206 @@
+// file : bpkg/package-configuration.hxx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BPKG_PACKAGE_CONFIGURATION_HXX
+#define BPKG_PACKAGE_CONFIGURATION_HXX
+
+#include <libbuild2/types.hxx> // build2::names
+#include <libbuild2/config/types.hxx> // build2::config::variable_origin
+
+#include <bpkg/types.hxx>
+#include <bpkg/utility.hxx>
+
+#include <bpkg/package.hxx>
+
+using namespace std;
+
+namespace bpkg
+{
+ class package_skeleton;
+
+ // Serialize the variable value as a command line override.
+ //
+ string
+ serialize_cmdline (const string& name, const optional<build2::names>& value);
+
+ struct config_variable_value
+ {
+ string name;
+
+ // The variable_origin values have the following meaning:
+ //
+ // default -- default value from the config directive
+ // buildfile -- dependent configuration (config_source::dependent)
+ // override -- user configuration (config_source::user)
+ // undefined -- none of the above
+ //
+ build2::config::variable_origin origin;
+
+ // Variable type name with absent signifying untyped.
+ //
+ optional<string> type;
+
+ // If origin is not undefined, then this is the reversed variable value
+ // with absent signifying NULL.
+ //
+ optional<build2::names> value;
+
+ // If origin is buildfile, then this is the "originating dependent" which
+ // first set this variable to this value.
+ //
+ optional<package_key> dependent;
+
+ // If origin is buildfile, then this flag indicates whether the
+ // originating dependent has been encountered during the negotiation
+ // retry.
+ //
+ bool confirmed;
+
+ public:
+ void
+ undefine ()
+ {
+ origin = build2::config::variable_origin::undefined;
+ value = nullopt;
+ dependent = nullopt;
+ confirmed = false;
+ }
+
+ string
+ serialize_cmdline () const
+ {
+ return bpkg::serialize_cmdline (name, value);
+ }
+ };
+
+ void
+ to_checksum (sha256&, const config_variable_value&);
+
+ // A subset of config_variable_value for variable values set by the
+ // dependents (origin is buildfile). Used to track change history.
+ //
+ struct dependent_config_variable_value
+ {
+ string name;
+ optional<build2::names> value;
+ package_key dependent;
+
+ public:
+ string
+ serialize_cmdline () const
+ {
+ return bpkg::serialize_cmdline (name, value);
+ }
+ };
+
+ inline bool
+ operator== (const dependent_config_variable_value& x,
+ const dependent_config_variable_value& y)
+ {
+ return x.name == y.name && x.value == y.value && x.dependent == y.dependent;
+ }
+
+ class dependent_config_variable_values:
+ public small_vector<dependent_config_variable_value, 1>
+ {
+ public:
+ const dependent_config_variable_value*
+ find (const string& name) const
+ {
+ auto i (find_if (begin (), end (),
+ [&name] (const dependent_config_variable_value& v)
+ {
+ return v.name == name;
+ }));
+ return i != end () ? &*i : nullptr;
+ }
+ };
+
+ class package_configuration: public vector<config_variable_value>
+ {
+ public:
+ package_key package;
+ bool system = false; // True if system package without skeleton info.
+
+ explicit
+ package_configuration (package_key p): package (move (p)) {}
+
+ config_variable_value*
+ find (const string& name)
+ {
+ auto i (find_if (begin (), end (),
+ [&name] (const config_variable_value& v)
+ {
+ return v.name == name;
+ }));
+ return i != end () ? &*i : nullptr;
+ }
+
+ const config_variable_value*
+ find (const string& name) const
+ {
+ auto i (find_if (begin (), end (),
+ [&name] (const config_variable_value& v)
+ {
+ return v.name == name;
+ }));
+ return i != end () ? &*i : nullptr;
+ }
+
+ // Print buildfile and override configuration variable values as command
+ // line overrides one per line with the specified indentation. After each
+ // variable also print in parenthesis its origin. If overrides is not
+ // NULL, then it is used to override the value/dependent information.
+ //
+ void
+ print (diag_record&, const char* indent,
+ const dependent_config_variable_values* overrides = nullptr) const;
+ };
+
+ class package_configurations: public small_vector<package_configuration, 1>
+ {
+ public:
+ // Note: may invalidate references.
+ //
+ package_configuration&
+ operator[] (const package_key& p)
+ {
+ auto i (find_if (begin (), end (),
+ [&p] (const package_configuration& pc)
+ {
+ return pc.package == p;
+ }));
+ if (i != end ())
+ return *i;
+
+ push_back (package_configuration (p));
+ return back ();
+ }
+
+ void
+ clear ()
+ {
+ small_vector<package_configuration, 1>::clear ();
+ change_history_.clear ();
+ }
+
+ // Implementation details.
+ //
+ public:
+ // Note: dependent_config_variable_values must be sorted by name.
+ //
+ small_vector<dependent_config_variable_values, 2> change_history_;
+ };
+
+ // Negotiate the configuration for the specified dependencies of the
+ // specified dependent. Return true if the configuration has changed.
+ //
+ bool
+ negotiate_configuration (
+ package_configurations&,
+ package_skeleton& dependent,
+ pair<size_t, size_t> position,
+ const small_vector<reference_wrapper<package_skeleton>, 1>& dependencies);
+}
+
+#endif // BPKG_PACKAGE_CONFIGURATION_HXX
diff --git a/bpkg/package-skeleton.cxx b/bpkg/package-skeleton.cxx
index e0d85ed..8b4b09f 100644
--- a/bpkg/package-skeleton.cxx
+++ b/bpkg/package-skeleton.cxx
@@ -20,6 +20,8 @@
#include <libbuild2/lexer.hxx>
#include <libbuild2/parser.hxx>
+#include <libbuild2/config/utility.hxx>
+
#include <bpkg/package.hxx>
#include <bpkg/database.hxx>
#include <bpkg/manifest-utility.hxx>
@@ -38,6 +40,119 @@ namespace bpkg
void
build2_init (const common_options&);
+}
+
+namespace bpkg
+{
+ // Check whether the specified configuration variable override has a project
+ // variable (i.e., its name starts with config.<project>). If the last
+ // argument is not NULL, then set it to the length of the variable portion.
+ //
+ // Note that some user-specified variables may have qualifications
+ // (global, scope, etc) but there is no reason to expect any project
+ // configuration variables to use such qualifications (since they can
+ // only apply to one project). So we ignore all qualified variables.
+ //
+ static inline bool
+ project_override (const string& v, const string& p, size_t* l = nullptr)
+ {
+ size_t n (p.size ());
+
+ if (v.compare (0, n, p) == 0)
+ {
+ if (v[n] == '.')
+ {
+ if (l != nullptr)
+ *l = v.find_first_of ("=+ \t", n + 1);
+
+ return true;
+ }
+ else if (strchr ("=+ \t", v[n]) != nullptr)
+ {
+ if (l != nullptr)
+ *l = n;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // Check whether the specified configuration variable name is a project
+ // variable (i.e., its name starts with config.<project>).
+ //
+ static inline bool
+ project_variable (const string& v, const string& p)
+ {
+ size_t n (p.size ());
+ return v.compare (0, n, p) == 0 && (v[n] == '.' || v[n] == '\0');
+ }
+
+ // Customized buildfile parser that is used to detect and diagnose
+ // references to undefined dependency configuration variables.
+ //
+ class buildfile_parser: public build2::parser
+ {
+ public:
+ buildfile_parser (build2::context& ctx,
+ const strings& dvps,
+ optional<size_t> dvps_pending = {})
+ : parser (ctx),
+ dependency_var_prefixes_ (dvps),
+ dependency_var_prefixes_pending_ (dvps_pending) {}
+
+ protected:
+ virtual build2::lookup
+ lookup_variable (build2::name&& qual,
+ string&& name,
+ const build2::location& loc) override
+ {
+ using namespace build2;
+ using build2::fail;
+ using build2::info;
+
+ // To avoid making copies of the name, pre-check if it is from one
+ // of the dependencies.
+ //
+ optional<string> dep;
+ if (!pre_parse_ && qual.empty ())
+ {
+ auto b (dependency_var_prefixes_.begin ());
+ auto e (dependency_var_prefixes_pending_
+ ? b + *dependency_var_prefixes_pending_
+ : dependency_var_prefixes_.end ());
+
+ if (find_if (b, e,
+ [&name] (const string& p)
+ {
+ return project_variable (name, p);
+ }) != e)
+ dep = name;
+ }
+
+ lookup l (parser::lookup_variable (move (qual), move (name), loc));
+
+ if (dep && !l.defined ())
+ fail (loc) << "undefined dependency configuration variable " << *dep <<
+ info << "was " << *dep << " set in earlier prefer or require clause?";
+
+ return l;
+ }
+
+ private:
+ const strings& dependency_var_prefixes_;
+ optional<size_t> dependency_var_prefixes_pending_;
+ };
+
+ static void
+ create_context (package_skeleton&, const strings&);
+
+ // Note: cannot be package_skeleton member function due to iterator return
+ // (build2 stuff is only forward-declared in the header).
+ //
+ static build2::scope_map::iterator
+ bootstrap (package_skeleton&, const strings&);
package_skeleton::
~package_skeleton ()
@@ -46,8 +161,36 @@ namespace bpkg
package_skeleton::
package_skeleton (package_skeleton&& v)
+ : package (move (v.package)),
+ system (v.system),
+ available (move (v.available)),
+ co_ (v.co_),
+ db_ (v.db_),
+ var_prefix_ (move (v.var_prefix_)),
+ config_vars_ (move (v.config_vars_)),
+ disfigure_ (v.disfigure_),
+ config_srcs_ (v.config_srcs_),
+ src_root_ (move (v.src_root_)),
+ out_root_ (move (v.out_root_)),
+ created_ (v.created_),
+ verified_ (v.verified_),
+ loaded_old_config_ (v.loaded_old_config_),
+ develop_ (v.develop_),
+ ctx_ (move (v.ctx_)),
+ rs_ (v.rs_),
+ cmd_vars_ (move (v.cmd_vars_)),
+ cmd_vars_cache_ (v.cmd_vars_cache_),
+ dependent_vars_ (move (v.dependent_vars_)),
+ dependent_orgs_ (move (v.dependent_orgs_)),
+ reflect_ (move (v.reflect_)),
+ dependency_reflect_ (move (v.dependency_reflect_)),
+ dependency_reflect_index_ (v.dependency_reflect_index_),
+ dependency_reflect_pending_ (v.dependency_reflect_pending_),
+ dependency_var_prefixes_ (move (v.dependency_var_prefixes_)),
+ dependency_var_prefixes_pending_ (v.dependency_var_prefixes_pending_),
+ prefer_accept_ (v.prefer_accept_)
{
- *this = move (v);
+ v.db_ = nullptr;
}
package_skeleton& package_skeleton::
@@ -55,22 +198,36 @@ namespace bpkg
{
if (this != &v)
{
+ package = move (v.package);
+ system = v.system;
+ available = move (v.available);
co_ = v.co_;
db_ = v.db_;
- available_ = v.available_;
+ var_prefix_ = move (v.var_prefix_);
config_vars_ = move (v.config_vars_);
+ disfigure_ = v.disfigure_;
+ config_srcs_ = v.config_srcs_;
src_root_ = move (v.src_root_);
out_root_ = move (v.out_root_);
created_ = v.created_;
+ verified_ = v.verified_;
+ loaded_old_config_ = v.loaded_old_config_;
+ develop_ = v.develop_;
ctx_ = move (v.ctx_);
rs_ = v.rs_;
cmd_vars_ = move (v.cmd_vars_);
- reflect_names_ = move (v.reflect_names_);
- reflect_vars_ = move (v.reflect_vars_);
- reflect_frag_ = move (v.reflect_frag_);
+ cmd_vars_cache_ = v.cmd_vars_cache_;
+ dependent_vars_ = move (v.dependent_vars_);
+ dependent_orgs_ = move (v.dependent_orgs_);
+ reflect_ = move (v.reflect_);
+ dependency_reflect_ = move (v.dependency_reflect_);
+ dependency_reflect_index_ = v.dependency_reflect_index_;
+ dependency_reflect_pending_ = v.dependency_reflect_pending_;
+ dependency_var_prefixes_ = move (v.dependency_var_prefixes_);
+ dependency_var_prefixes_pending_ = v.dependency_var_prefixes_pending_;
+ prefer_accept_ = v.prefer_accept_;
v.db_ = nullptr;
- v.available_ = nullptr;
}
return *this;
@@ -78,34 +235,135 @@ namespace bpkg
package_skeleton::
package_skeleton (const package_skeleton& v)
- : co_ (v.co_),
+ : package (v.package),
+ system (v.system),
+ available (v.available),
+ co_ (v.co_),
db_ (v.db_),
- available_ (v.available_),
+ var_prefix_ (v.var_prefix_),
config_vars_ (v.config_vars_),
+ disfigure_ (v.disfigure_),
+ config_srcs_ (v.config_srcs_),
src_root_ (v.src_root_),
out_root_ (v.out_root_),
created_ (v.created_),
+ verified_ (v.verified_),
+ loaded_old_config_ (v.loaded_old_config_),
+ develop_ (v.develop_),
cmd_vars_ (v.cmd_vars_),
- reflect_names_ (v.reflect_names_),
- reflect_vars_ (v.reflect_vars_),
- reflect_frag_ (v.reflect_frag_)
+ cmd_vars_cache_ (v.cmd_vars_cache_),
+ dependent_vars_ (v.dependent_vars_),
+ dependent_orgs_ (v.dependent_orgs_),
+ reflect_ (v.reflect_),
+ dependency_reflect_ (v.dependency_reflect_),
+ dependency_reflect_index_ (v.dependency_reflect_index_),
+ dependency_reflect_pending_ (v.dependency_reflect_pending_),
+ dependency_var_prefixes_ (v.dependency_var_prefixes_),
+ dependency_var_prefixes_pending_ (v.dependency_var_prefixes_pending_),
+ prefer_accept_ (v.prefer_accept_)
{
// The idea here is to create an "unloaded" copy but with enough state
// that it can be loaded if necessary.
+ //
+ // Note that there is a bit of a hole in this logic with regards to the
+ // prefer_accept_ semantics but it looks like we cannot plausible trigger
+ // it (which is fortified with an assert in evaluate_reflect(); note that
+ // doing it here would be overly strict since this may have a left-over
+ // prefer_accept_ position).
+ }
+
+ void package_skeleton::
+ reset ()
+ {
+ assert (db_ != nullptr); // Cannot be called after collect_config().
+
+ rs_ = nullptr;
+ ctx_ = nullptr; // Free.
+
+ cmd_vars_.clear ();
+ cmd_vars_cache_ = false;
+
+ dependent_vars_.clear ();
+ dependent_orgs_.clear ();
+
+ reflect_.clear ();
+
+ dependency_reflect_.clear ();
+ dependency_reflect_index_ = 0;
+ dependency_reflect_pending_ = 0;
+
+ dependency_var_prefixes_.clear ();
+ dependency_var_prefixes_pending_ = 0;
+
+ prefer_accept_ = nullopt;
}
package_skeleton::
package_skeleton (const common_options& co,
- database& db,
- const available_package& ap,
+ package_key pk,
+ bool sys,
+ shared_ptr<const available_package> ap,
strings cvs,
+ bool df,
+ const vector<config_variable>* css,
optional<dir_path> src_root,
optional<dir_path> out_root)
- : co_ (&co), db_ (&db), available_ (&ap), config_vars_ (move (cvs))
+ : package (move (pk)),
+ system (sys),
+ available (move (ap)),
+ co_ (&co),
+ db_ (&package.db.get ()),
+ var_prefix_ ("config." + package.name.variable ()),
+ config_vars_ (move (cvs)),
+ disfigure_ (df),
+ config_srcs_ (df ? nullptr : css)
{
- // Should not be created for stubs.
+ if (available != nullptr)
+ assert (available->bootstrap_build); // Should have skeleton info.
+ else
+ assert (system);
+
+ // We are only interested in old user configuration variables.
+ //
+ if (config_srcs_ != nullptr)
+ {
+ if (find_if (config_srcs_->begin (), config_srcs_->end (),
+ [] (const config_variable& v)
+ {
+ return v.source == config_source::user;
+ }) == config_srcs_->end ())
+ config_srcs_ = nullptr;
+ }
+
+ // We don't need to load old user configuration if there isn't any and
+ // there is no new project configuration specified by the user.
+ //
+ // Note that at first it may seem like we shouldn't do this for any system
+ // packages but if we want to verify the user configuration, why not do so
+ // for system if we can (i.e., have skeleton info)?
//
- assert (available_->bootstrap_build);
+ if (available == nullptr)
+ loaded_old_config_ = true;
+ else
+ loaded_old_config_ =
+ (config_srcs_ == nullptr) &&
+ find_if (config_vars_.begin (), config_vars_.end (),
+ [this] (const string& v)
+ {
+ // For now tighten it even further so that we can continue
+ // using repositories without package skeleton information
+ // (bootstrap.build, root.build). See load_old_config() for
+ // details.
+ //
+#if 0
+ return project_override (v, var_prefix_);
+#else
+ size_t vn;
+ size_t pn (var_prefix_.size ());
+ return (project_override (v, var_prefix_, &vn) &&
+ v.compare (pn, vn - pn, ".develop") == 0);
+#endif
+ }) == config_vars_.end ();
if (src_root)
{
@@ -118,6 +376,380 @@ namespace bpkg
assert (!out_root);
}
+ // Serialize a variable assignment for a command line override.
+ //
+ static string
+ serialize_cmdline (const string& var, const build2::value& val,
+ build2::names& storage)
+ {
+ using namespace build2;
+
+ string r (var + '=');
+
+ if (val.null)
+ r += "[null]";
+ else
+ {
+ storage.clear ();
+ names_view nv (reverse (val, storage));
+
+ if (!nv.empty ())
+ {
+ // Note: we need to use command-line (effective) quoting.
+ //
+ ostringstream os;
+ to_stream (os, nv, quote_mode::effective, '@');
+ r += os.str ();
+ }
+ }
+
+ return r;
+ }
+
+ // Reverse value to names.
+ //
+ static optional<build2::names>
+ reverse_value (const build2::value& val)
+ {
+ using namespace build2;
+
+ if (val.null)
+ return nullopt;
+
+ names storage;
+ names_view nv (reverse (val, storage));
+
+ return (nv.data () == storage.data ()
+ ? move (storage)
+ : names (nv.begin (), nv.end ()));
+ }
+
+ // Return the dependent (origin==buildfile) configuration variables as
+ // command line overrides. If the second argument is not NULL, then populate
+ // it with the corresponding originating dependents.
+ //
+ static strings
+ dependent_cmd_vars (const package_configuration& cfg,
+ vector<package_key>* orgs = nullptr)
+ {
+ using build2::config::variable_origin;
+
+ strings r;
+
+ for (const config_variable_value& v: cfg)
+ {
+ if (v.origin == variable_origin::buildfile)
+ {
+ r.push_back (v.serialize_cmdline ());
+
+ if (orgs != nullptr)
+ orgs->push_back (*v.dependent);
+ }
+ }
+
+ return r;
+ }
+
+ void package_skeleton::
+ reload_defaults (package_configuration& cfg)
+ {
+ // Should only be called before dependent_config()/evaluate_*().
+ //
+ assert (dependent_vars_.empty () &&
+ reflect_.empty () &&
+ dependency_reflect_.empty () &&
+ available != nullptr &&
+ ctx_ == nullptr);
+
+ if (!loaded_old_config_)
+ load_old_config ();
+
+ try
+ {
+ using namespace build2;
+
+ // This is what needs to happen to the variables of different origins in
+ // the passed configuration:
+ //
+ // default -- reloaded
+ // buildfile/dependent -- made command line override
+ // override/user -- should match what's in config_vars_
+ // undefined -- reloaded
+ //
+ // Note also that on the first call we will have no configuration. And
+ // so to keep things simple, we merge variable of the buildfile origin
+ // into cmd_vars and then rebuild things from scratch. Note, however,
+ // that below we need to sort out these merged overrides into user and
+ // dependent, so we keep the old configuration for reference.
+ //
+ // Note also that dependent values do not clash with user overrides by
+ // construction (in evaluate_{prefer_accept,require}()): we do not add
+ // as dependent variables that have the override origin.
+ //
+ scope& rs (
+ *bootstrap (
+ *this, merge_cmd_vars (dependent_cmd_vars (cfg)))->second.front ());
+
+ // Load project's root.build.
+ //
+ load_root (rs);
+
+ package_configuration old (move (cfg));
+ cfg.package = move (old.package);
+
+ // Note that a configuration variable may not have a default value so we
+ // cannot just iterate over all the config.<name>** values set on the
+ // root scope. Our options seem to be either iterating over the variable
+ // pool or forcing the config module with config.config.module=true and
+ // then using its saved variables map. Since the amount of stuff we load
+ // is quite limited, there shouldn't be too many variables in the pool.
+ // So let's go with the simpler approach for now.
+ //
+ // Though the saved variables map approach would have been more accurate
+ // since that's the variables that were introduced with the config
+ // directive. Potentially the user could just have a buildfile
+ // config.<name>** variable but it feels like that should be harmless
+ // (we will return it but nobody will presumably use that information).
+ // Also, if/when we start tracking the configuration variable
+ // dependencies (i.e., which default value depend on which config
+ // variable), then the saved variables map seem like the natural place
+ // to keep this information.
+ //
+ for (const variable& var: rs.ctx.var_pool)
+ {
+ if (!project_variable (var.name, var_prefix_))
+ continue;
+
+ using config::variable_origin;
+
+ pair<variable_origin, lookup> ol (config::origin (rs, var));
+
+ switch (ol.first)
+ {
+ case variable_origin::default_:
+ case variable_origin::override_:
+ case variable_origin::undefined:
+ {
+ config_variable_value v {var.name, ol.first, {}, {}, {}, false};
+
+ // Override could mean user override from config_vars_ or the
+ // dependent override that we have merged above.
+ //
+ if (v.origin == variable_origin::override_)
+ {
+ if (config_variable_value* ov = old.find (v.name))
+ {
+ if (ov->origin == variable_origin::buildfile)
+ {
+ v.origin = variable_origin::buildfile;
+ v.dependent = move (ov->dependent);
+ v.confirmed = ov->confirmed;
+ }
+ else
+ assert (ov->origin == variable_origin::override_);
+ }
+ }
+
+ // Save value.
+ //
+ if (v.origin != variable_origin::undefined)
+ v.value = reverse_value (*ol.second);
+
+ // Save type.
+ //
+ if (var.type != nullptr)
+ v.type = var.type->name;
+
+ cfg.push_back (move (v));
+ break;
+ }
+ case variable_origin::buildfile:
+ {
+ // Feel like this shouldn't happen since we have disfigured them.
+ //
+ assert (false);
+ break;
+ }
+ }
+ }
+
+ verified_ = true; // Managed to load without errors.
+ ctx_ = nullptr;
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
+ }
+
+ void package_skeleton::
+ load_overrides (package_configuration& cfg)
+ {
+ // Should only be called before dependent_config()/evaluate_*() and only
+ // on system package without skeleton info.
+ //
+ assert (dependent_vars_.empty () &&
+ reflect_.empty () &&
+ dependency_reflect_.empty () &&
+ available == nullptr &&
+ system);
+
+ if (find_if (config_vars_.begin (), config_vars_.end (),
+ [this] (const string& v)
+ {
+ return project_override (v, var_prefix_);
+ }) == config_vars_.end ())
+ return;
+
+ try
+ {
+ using namespace build2;
+ using build2::fail;
+ using build2::endf;
+
+ using config::variable_origin;
+
+ // Create the build context.
+ //
+ create_context (*this, strings {});
+ context& ctx (*ctx_);
+
+ scope& gs (ctx.global_scope.rw ());
+ auto& vp (ctx.var_pool.rw ());
+
+ for (const string& v: config_vars_)
+ {
+ size_t vn;
+ if (!project_override (v, var_prefix_, &vn))
+ continue;
+
+ const variable& var (vp.insert (string (v, 0, vn)));
+
+ // Parse the value part (note that all evaluate_require() cares about
+ // is whether the value is true or not, but we do need accurate values
+ // for diagnostics).
+ //
+ size_t p (v.find ('=', vn));
+ assert (p != string::npos);
+ if (v[p + 1] == '+')
+ ++p;
+
+ optional<names> val;
+ {
+ // Similar to context() ctor.
+ //
+ istringstream is (string (v, p + 1));
+ is.exceptions (istringstream::failbit | istringstream::badbit);
+
+ path_name in ("<cmdline>");
+ lexer lex (is, in, 1 /* line */, "\'\"\\$("); // Effective.
+
+ parser par (ctx);
+ pair<value, token> r (
+ par.parse_variable_value (lex, gs, &build2::work, var));
+
+ if (r.second.type != token_type::eos)
+ fail << "invalid command line variable override '" << v << "'";
+
+ val = reverse_value (r.first);
+ }
+
+ // @@ Should we do anything with append/prepend?
+ //
+ if (config_variable_value* v = cfg.find (var.name))
+ v->value = move (val);
+ else
+ cfg.push_back (
+ config_variable_value {
+ var.name, variable_origin::override_, {}, move (val), {}, false});
+ }
+
+ ctx_ = nullptr; // Free.
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
+ }
+
+ pair<bool, string> package_skeleton::
+ verify_sensible (const package_configuration& cfg)
+ {
+ // Should only be called before dependent_config()/evaluate_*().
+ //
+ assert (dependent_vars_.empty () &&
+ reflect_.empty () &&
+ dependency_reflect_.empty () &&
+ available != nullptr &&
+ ctx_ == nullptr);
+
+ if (!loaded_old_config_)
+ load_old_config ();
+
+ try
+ {
+ using namespace build2;
+
+ // For now we treat any failure to load root.build as bad configuration,
+ // which is not very precise. One idea to make this more precise would
+ // be to invent some kind of tagging for "bad configuration" diagnostics
+ // (e.g., either via an attribute or via special config.assert directive
+ // or some such).
+ //
+ // For now we rely on load_defaults() and load_old_config() to "flush"
+ // out any unrelated errors (e.g., one of the modules configuration is
+ // bad, etc). However, if that did not happen naturally, then we must do
+ // it ourselves.
+ //
+ if (!verified_)
+ {
+ scope& rs (
+ *bootstrap (*this, merge_cmd_vars (strings {}))->second.front ());
+ load_root (rs);
+
+ verified_ = true;
+ ctx_ = nullptr;
+ }
+
+ scope& rs (
+ *bootstrap (
+ *this, merge_cmd_vars (dependent_cmd_vars (cfg)))->second.front ());
+
+ // Load project's root.build while redirecting the diagnostics stream.
+ //
+ ostringstream ds;
+ auto dg (make_guard ([ods = diag_stream] () {diag_stream = ods;}));
+ diag_stream = &ds;
+
+ pair<bool, string> r;
+ try
+ {
+ load_root (rs);
+ r.first = true;
+ }
+ catch (const build2::failed&)
+ {
+ r.first = false;
+ r.second = trim (ds.str ());
+ }
+
+ ctx_ = nullptr;
+ return r;
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
+ }
+
+ void package_skeleton::
+ dependent_config (const package_configuration& cfg)
+ {
+ assert (dependent_vars_.empty ()); // Must be called at most once.
+
+ dependent_vars_ = dependent_cmd_vars (cfg, &dependent_orgs_);
+ }
+
// Print the location of a depends value in the specified manifest file.
//
// Note that currently we only use this function for the external packages.
@@ -126,7 +758,7 @@ namespace bpkg
// the temp directory is not cleaned in case of an error. Maybe one day.
//
static void
- depends_location (const diag_record& dr,
+ depends_location (const build2::diag_record& dr,
const path& mf,
size_t depends_index)
{
@@ -146,10 +778,10 @@ namespace bpkg
{
if (nv.name == "depends" && i++ == depends_index)
{
- dr << info (location (p.name (),
- nv.value_line,
- nv.value_column))
- << "depends value defined here";
+ dr << build2::info (build2::location (mf,
+ nv.value_line,
+ nv.value_column))
+ << "in depends manifest value defined here";
break;
}
}
@@ -160,16 +792,29 @@ namespace bpkg
}
bool package_skeleton::
- evaluate_enable (const string& cond, size_t depends_index)
+ evaluate_enable (const string& cond, pair<size_t, size_t> indexes)
{
+ size_t depends_index (indexes.first);
+
try
{
using namespace build2;
using build2::fail;
+ using build2::info;
using build2::endf;
+ // Drop the state from the previous evaluation of prefer/accept.
+ //
+ if (prefer_accept_)
+ {
+ ctx_ = nullptr;
+ prefer_accept_ = nullopt;
+ }
+
scope& rs (load ());
+ // Evaluate the enable condition.
+ //
istringstream is ('(' + cond + ')');
is.exceptions (istringstream::failbit | istringstream::badbit);
@@ -183,21 +828,24 @@ namespace bpkg
uint64_t il (1);
auto df = build2::make_diag_frame (
- [&cond, &rs, depends_index] (const diag_record& dr)
+ [this, &cond, &rs, depends_index] (const build2::diag_record& dr)
{
dr << info << "enable condition: (" << cond << ")";
// For external packages we have the manifest so print the location
// of the depends value in questions.
//
- if (!rs.out_eq_src ())
+ if (rs.out_eq_src ())
+ dr << info << "in depends manifest value of package "
+ << package.name;
+ else
depends_location (dr,
rs.src_path () / manifest_file,
depends_index);
});
lexer l (is, in, il /* start line */);
- parser p (rs.ctx);
+ buildfile_parser p (rs.ctx, dependency_var_prefixes_);
value v (p.parse_eval (l, rs, rs, parser::pattern_mode::expand));
try
@@ -217,9 +865,13 @@ namespace bpkg
}
}
+#if 1
+
void package_skeleton::
- evaluate_reflect (const string& refl, size_t depends_index)
+ evaluate_reflect (const string& refl, pair<size_t, size_t> indexes)
{
+ size_t depends_index (indexes.first);
+
// The reflect configuration variables are essentially overrides that will
// be passed on the command line when we configure the package. They could
// clash with configuration variables specified by the user (config_vars_)
@@ -227,6 +879,11 @@ namespace bpkg
// also argue we should diagnose this case and fail not to cause more
// confusion.
//
+ // They could also clash with dependent configuration. Probably should be
+ // handled in the same way (it's just another type of "user"). Yes, since
+ // dependent_vars_ are entered as cmd line overrides, this is how they are
+ // treated.
+ //
// It seems like the most straightforward way to achieve the desired
// semantics with the mechanisms that we have (in other words, without
// inventing another "level" of overrides) is to evaluate the reflect
@@ -234,19 +891,327 @@ namespace bpkg
// variables set by root.build in conditions, (2) override default values
// of configuration variables (and those loaded from config.build), and
// (3) be overriden by configuration variables specified by the user.
- // Naturally, this approach is not without a few corner cases:
+ // Naturally, this approach is probably not without a few corner cases.
+ //
+ // We may also have configuration values from the previous reflect clause
+ // which we want to "factor in" before evaluating the next clause (enable,
+ // reflect etc.; so that they can use the previously reflected values or
+ // values that are derived from them in root.build). It seems like we have
+ // two options here: either enter them as true overrides similar to
+ // config_vars_ or just evaluate them similar to loading config.build
+ // (which, BTW, we might have, in case of an external package). The big
+ // problem with the former approach is that it will then prevent any
+ // further reflect clauses from modifying the same values.
+ //
+ // So overall it feels like we have iterative/compartmentalized
+ // configuration process. A feedback loop, in a sense. And it's the
+ // responsibility of the package author (who is in control of both
+ // root.build and manifest) to arrange for suitable compartmentalization.
//
- // 1. Append in the reflect clause may not produce the desired result
- // (i.e., it will append to the default value in root.build) rather
- // than overriding it, as would have happen if it were a real variable
- // override.
+ try
+ {
+ // Note: similar in many respects to evaluate_enable().
+ //
+ using namespace build2;
+ using config::variable_origin;
+ using build2::diag_record;
+ using build2::fail;
+ using build2::info;
+ using build2::endf;
+
+ // Drop the state from the previous evaluation of prefer/accept if it's
+ // from the wrong position.
+ //
+ optional<size_t> dependency_var_prefixes_pending;
+ if (prefer_accept_)
+ {
+ if (*prefer_accept_ != indexes)
+ {
+ ctx_ = nullptr;
+ prefer_accept_ = nullopt;
+ }
+ else
+ {
+ // This could theoretically happen if we make a copy of the skeleton
+ // after evaluate_prefer_accept() and then attempt to continue with
+ // the call on the copy to evaluate_reflect() passing the same
+ // position. But it doesn't appear our usage should trigger this.
+ //
+ assert (ctx_ != nullptr);
+
+ dependency_var_prefixes_pending = dependency_var_prefixes_pending_;
+ }
+ }
+
+ scope& rs (load ());
+
+ // Collect all the set config.<name>.* variables on the first pass and
+ // filter out unchanged on the second.
+ //
+ // Note: a lot of this code is inspired by the config module.
+ //
+ struct rvar
+ {
+ const variable* var;
+ const value* val;
+ size_t ver;
+ };
+
+ class rvars: public vector<rvar>
+ {
+ public:
+ pair<iterator, bool>
+ insert (const rvar& v)
+ {
+ auto i (find_if (begin (), end (),
+ [&v] (const rvar& o) {return v.var == o.var;}));
+ if (i != end ())
+ return make_pair (i, false);
+
+ push_back (v);
+ return make_pair (--end (), true);
+ }
+ };
+
+ rvars vars;
+
+ auto process = [this, &rs, &vars] (bool collect)
+ {
+ // @@ TODO: would be nice to verify no bogus variables are set (can
+ // probably only be done via the saved variables map).
+
+ for (auto p (rs.vars.lookup_namespace (var_prefix_));
+ p.first != p.second;
+ ++p.first)
+ {
+ const variable& var (p.first->first);
+
+ // This can be one of the overrides (__override, __prefix, etc),
+ // which we skip.
+ //
+ if (var.override ())
+ continue;
+
+ // What happens to version if overriden? A: appears to be still
+ // incremented!
+ //
+ const variable_map::value_data& val (p.first->second);
+
+ if (collect)
+ vars.insert (rvar {&var, nullptr, val.version});
+ else
+ {
+ auto p (vars.insert (rvar {&var, &val, 0}));
+
+ if (!p.second)
+ {
+ auto i (p.first);
+
+ if (i->ver == val.version)
+ vars.erase (i); // Unchanged.
+ else
+ i->val = &val;
+ }
+ }
+ }
+ };
+
+ // Evaluate the reflect clause.
+ //
+ istringstream is (refl);
+ is.exceptions (istringstream::failbit | istringstream::badbit);
+
+ path_name in ("<depends-reflect-clause>");
+ uint64_t il (1);
+
+ // Note: keep it active until the end (see the override detection).
+ //
+ auto df = build2::make_diag_frame (
+ [this, &refl, &rs, depends_index] (const build2::diag_record& dr)
+ {
+ // Probably safe to assume a one-line fragment contains a variable
+ // assignment.
+ //
+ if (refl.find ('\n') == string::npos)
+ dr << info << "reflect variable: " << trim (string (refl));
+ else
+ dr << info << "reflect clause:\n"
+ << trim_right (string (refl));
+
+ // For external packages we have the manifest so print the
+ // location of the depends value in questions.
+ //
+ if (rs.out_eq_src ())
+ dr << info << "in depends manifest value of package "
+ << package.name;
+ else
+ depends_location (dr,
+ rs.src_path () / manifest_file,
+ depends_index);
+ });
+
+ lexer l (is, in, il /* start line */);
+ buildfile_parser p (rs.ctx,
+ dependency_var_prefixes_,
+ dependency_var_prefixes_pending);
+
+ process (true);
+ p.parse_buildfile (l, &rs, rs);
+ process (false);
+
+ // Add to the vars set the reflect variables collected previously.
+ //
+ auto& vp (rs.var_pool ());
+ for (const reflect_variable_value& v: reflect_)
+ {
+ const variable* var (vp.find (v.name));
+ assert (var != nullptr); // Must be there (set by load()).
+
+ auto p (vars.insert (rvar {var, nullptr, 0}));
+
+ if (p.second)
+ p.first->val = rs.vars[*var].value; // Must be there (set by load()).
+ }
+
+ // Re-populate everything from the var set but try to re-use buffers as
+ // much a possible (normally we would just be appending more variables
+ // at the end).
+ //
+ reflect_.resize (vars.size ());
+
+ // Collect the config.<name>.* variables that were changed by this
+ // and previous reflect clauses.
+ //
+ for (size_t i (0); i != vars.size (); ++i)
+ {
+ const variable& var (*vars[i].var);
+ const value& val (*vars[i].val);
+
+ pair<variable_origin, lookup> ol (
+ config::origin (rs,
+ var,
+ pair<lookup, size_t> {
+ lookup {val, var, rs.vars}, 1 /* depth */}));
+
+ reflect_variable_value& v (reflect_[i]);
+ v.name = var.name;
+ v.origin = ol.first;
+
+ if (ol.first == variable_origin::override_)
+ {
+ // Detect an overridden reflect value, but allowing it if the values
+ // match (think both user/dependent and reflect trying to enable the
+ // same feature).
+ //
+ // What would be the plausible scenarios for an override?
+ //
+ // 1. Append override that adds some backend or some such to the
+ // reflect value.
+ //
+ // 2. A reflect may enable a feature based on the dependency
+ // alternative selected (e.g., I see we are using Qt6 so we might
+ // as well enable feature X). The user may want do disable it
+ // with an override.
+ //
+ // Note also that a sufficiently smart reflect clause can detect if
+ // a variable is overridden (with $config.origin()) and avoid the
+ // clash. Perhaps that should be the recommendation for reflect
+ // variables that can also plausibly be set by the user (it feels
+ // like configuration variables have the intf/impl split similar
+ // to libraries)?
+ //
+ if (val != *ol.second)
+ {
+ // See if this is a dependent or user override.
+ //
+ const package_key* d (nullptr);
+ {
+ for (size_t i (0); i != dependent_vars_.size (); ++i)
+ {
+ const string& v (dependent_vars_[i]);
+ size_t n (var.name.size ());
+ if (v.compare (0, n, var.name) == 0 && v[n] == '=')
+ {
+ d = &dependent_orgs_[i];
+ break;
+ }
+ }
+ }
+
+ diag_record dr (fail);
+
+ dr << "reflect variable " << var << " overriden by ";
+
+ if (d != nullptr)
+ dr << "dependent " << *d;
+ else
+ dr << "user configuration";
+
+ names storage;
+ dr << info << "reflect value: "
+ << serialize_cmdline (var.name, val, storage);
+
+ dr << info << (d != nullptr ? "dependent" : "user") << " value: "
+ << serialize_cmdline (var.name, *ol.second, storage);
+ }
+
+ // Skipped in load(), collect_config(), but used in print_config().
+ }
+ else
+ {
+ assert (ol.first == variable_origin::buildfile);
+
+ // Note that we keep it always untyped letting the config directives
+ // in root.build to take care of typing.
+ //
+ v.value = reverse_value (val);
+ }
+ }
+
+ // Drop the build system state since it needs reloading (some computed
+ // values in root.build may depend on the new configuration values).
+ //
+ ctx_ = nullptr;
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
+ }
+
+#else
+
+ // @@ TMP: keep this in dep-config-neg but drop in master.
+
+ void package_skeleton::
+ evaluate_reflect (const string& refl, pair<size_t, size_t> indexes)
+ {
+ size_t depends_index (indexes.first);
+
+ // The reflect configuration variables are essentially overrides that will
+ // be passed on the command line when we configure the package. They could
+ // clash with configuration variables specified by the user (config_vars_)
+ // and it feels like user values should take precedence. Though one could
+ // also argue we should diagnose this case and fail not to cause more
+ // confusion.
//
- // config.hello.x ?= 1 # root.build
- // config.hello.x += 2 # reflect clause
+ // They could also clash with dependent configuration. Probably should be
+ // handled in the same way (it's just another type of "user"). Yes, since
+ // dependent_vars_ are entered as cmd line overrides, this is how they are
+ // treated.
+ //
+ // It seems like the most straightforward way to achieve the desired
+ // semantics with the mechanisms that we have (in other words, without
+ // inventing another "level" of overrides) is to evaluate the reflect
+ // fragment after loading root.build. This way it will (1) be able to use
+ // variables set by root.build in conditions, (2) override default values
+ // of configuration variables (and those loaded from config.build), and
+ // (3) be overriden by configuration variables specified by the user.
+ // Naturally, this approach is probably not without a few corner cases.
//
// We may also have configuration values from the previous reflect clause
- // which we want to "factor in" before evaluating the next enable or
- // reflect clauses (so that they can use the previously reflect values or
+ // which we want to "factor in" before evaluating the next clause (enable,
+ // reflect etc.; so that they can use the previously reflected values or
// values that are derived from them in root.build). It seems like we have
// two options here: either enter them as true overrides similar to
// config_vars_ or just evaluate them similar to loading config.build
@@ -259,18 +1224,39 @@ namespace bpkg
// responsibility of the package author (who is in control of both
// root.build and manifest) to arrange for suitable compartmentalization.
//
- // BTW, a plan B would be to restrict reflect to just config vars in which
- // case we could merge them with true overrides. Though how exactly would
- // we do this merging is unclear.
- //
try
{
// Note: similar in many respects to evaluate_enable().
//
using namespace build2;
using build2::fail;
+ using build2::info;
using build2::endf;
+ // Drop the state from the previous evaluation of prefer/accept if it's
+ // from the wrong position.
+ //
+ optional<size_t> dependency_var_prefixes_pending;
+ if (prefer_accept_)
+ {
+ if (*prefer_accept_ != indexes)
+ {
+ ctx_ = nullptr;
+ prefer_accept_ = nullopt;
+ }
+ else
+ {
+ // This could theoretically happen if we make a copy of the skeleton
+ // after evaluate_prefer_accept() and then attempt to continue with
+ // the call on the copy to evaluate_reflect() passing the same
+ // position. But it doesn't appear our usage should trigger this.
+ //
+ assert (ctx_ != nullptr);
+
+ dependency_var_prefixes_pending = dependency_var_prefixes_pending_;
+ }
+ }
+
scope& rs (load ());
istringstream is (refl);
@@ -280,21 +1266,24 @@ namespace bpkg
uint64_t il (1);
auto df = build2::make_diag_frame (
- [&refl, &rs, depends_index] (const diag_record& dr)
+ [this, &refl, &rs, depends_index] (const build2::diag_record& dr)
{
// Probably safe to assume a one-line fragment contains a variable
// assignment.
//
if (refl.find ('\n') == string::npos)
- dr << info << "reflect variable: " << refl;
+ dr << info << "reflect variable: " << trim (string (refl));
else
- dr << info << "reflect fragment:\n"
- << refl;
+ dr << info << "reflect clause:\n"
+ << trim_right (string (refl));
// For external packages we have the manifest so print the location
// of the depends value in questions.
//
- if (!rs.out_eq_src ())
+ if (rs.out_eq_src ())
+ dr << info << "in depends manifest value of package "
+ << package.name;
+ else
depends_location (dr,
rs.src_path () / manifest_file,
depends_index);
@@ -303,11 +1292,11 @@ namespace bpkg
// Note: a lot of this code is inspired by the config module.
//
- // Collect all the config.<name>.* variables on the first pass and
+ // Collect all the set config.<name>.* variables on the first pass and
// filter out unchanged on the second.
//
auto& vp (rs.var_pool ());
- const variable& ns (vp.insert ("config." + name ().variable ()));
+ const string& ns (var_prefix_);
struct value_data
{
@@ -315,6 +1304,8 @@ namespace bpkg
size_t ver;
};
+ // @@ Maybe redo as small_vector?
+ //
map<const variable*, value_data> vars;
auto process = [&rs, &ns, &vars] (bool collect)
@@ -323,12 +1314,12 @@ namespace bpkg
p.first != p.second;
++p.first)
{
- const variable* var (&p.first->first.get ());
+ const variable& var (p.first->first);
// This can be one of the overrides (__override, __prefix, etc),
// which we skip.
//
- if (var->override ())
+ if (var.override ())
continue;
// What happens to version if overriden? A: appears to be still
@@ -338,11 +1329,11 @@ namespace bpkg
if (collect)
{
- vars.emplace (var, value_data {nullptr, val.version});
+ vars.emplace (&var, value_data {nullptr, val.version});
}
else
{
- auto i (vars.find (var));
+ auto i (vars.find (&var));
if (i != vars.end ())
{
@@ -352,7 +1343,7 @@ namespace bpkg
i->second.val = &val;
}
else
- vars.emplace (var, value_data {&val, 0});
+ vars.emplace (&var, value_data {&val, 0});
}
}
};
@@ -360,15 +1351,26 @@ namespace bpkg
process (true);
lexer l (is, in, il /* start line */);
- parser p (rs.ctx);
+ buildfile_parser p (rs.ctx,
+ dependency_var_prefixes_,
+ dependency_var_prefixes_pending);
p.parse_buildfile (l, &rs, rs);
process (false);
- // Add to the map the reflect variables collected previously.
+ // Add to the map the reflect variables collected previously. Note that
+ // we can re-purpose the override since we re-populate it.
//
- for (string& n: reflect_names_)
+ for (string& n: reflect_vars_)
{
+ // Transform `name=value` to just `name`.
+ //
+ {
+ size_t p (n.find ('='));
+ assert (p != string::npos); // We've serialized it so must be there.
+ n.resize (p);
+ }
+
auto p (vars.emplace (&vp.insert (move (n)), value_data {nullptr, 0}));
if (p.second)
@@ -382,16 +1384,8 @@ namespace bpkg
// Re-populate everything from the map.
//
- reflect_names_.clear ();
- reflect_frag_.clear ();
-
-#if 0
- // NOTE: see also collect_config() if enabling this.
- //
reflect_vars_.clear ();
-#else
- reflect_vars_ = config_vars_;
-#endif
+ reflect_frag_.clear ();
// Collect the config.<name>.* variables that were changed by this
// and previous reflect clauses.
@@ -410,31 +1404,13 @@ namespace bpkg
const variable& var (*p.first);
const value& val (*p.second.val);
- reflect_names_.push_back (var.name);
-
// For the accumulated fragment we always save the original and let
// the standard overriding take its course.
//
- reflect_frag_ += var.name;
- reflect_frag_ += " = ";
-
- if (val.null)
- reflect_frag_ += "[null]";
- else
- {
- storage.clear ();
- names_view nv (reverse (val, storage));
-
- if (!nv.empty ())
- {
- ostringstream os;
- to_stream (os, nv, quote_mode::normal, '@');
- reflect_frag_ += os.str ();
- }
- }
-
- reflect_frag_ += '\n';
+ serialize_buildfile (reflect_frag_, var.name, val, storage);
+ // Note: this is currently disabled and is likely very outdated.
+ //
// For the accumulated overrides we have to merge user config_vars_
// with reflect values. Essentially, we have three possibilities:
//
@@ -452,6 +1428,9 @@ namespace bpkg
// config.hello.backend = foo # reflect
// config.hello.backend += bar # user
//
+
+ // @@ Can't we redo it via origin() call like in other places?
+ //
pair<lookup, size_t> org {lookup {val, var, rs.vars}, 1 /* depth */};
pair<lookup, size_t> ovr;
@@ -459,7 +1438,7 @@ namespace bpkg
ovr = org; // Case #2.
else
{
- // NOTE: see also above and below if enabling this.
+ // NOTE: see also below if enabling this.
//
#if 0
// Case #3.
@@ -519,41 +1498,656 @@ namespace bpkg
//
ovr = rs.lookup_override (var, org);
#else
+ // @@ TODO: probably also depends, not just user.
+ // @@ TODO: maybe we should allow if the same value (say a bool
+ // feature set to true but both)?!
+
fail << "command line override of reflect clause variable " << var
<< endf;
#endif
}
- string s (var.name + '=');
+ reflect_vars_.push_back (
+ serialize_cmdline (var.name, *ovr.first, storage));
+ }
- if (val.null)
- s += "[null]";
- else
+#if 0
+ // TODO: copy over config_vars_ that are not in the map (case #1).
+#endif
+
+ // Drop the build system state since it needs reloading (some computed
+ // values in root.build may depend on the new configuration values).
+ //
+ ctx_ = nullptr;
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
+ }
+
+#endif
+
+ bool package_skeleton::
+ evaluate_prefer_accept (const dependency_configurations& cfgs,
+ const string& prefer,
+ const string& accept,
+ pair<size_t, size_t> indexes)
+ {
+ size_t depends_index (indexes.first);
+
+ assert (dependency_reflect_index_ <= depends_index);
+
+ try
+ {
+ using namespace build2;
+ using config::variable_origin;
+ using build2::fail;
+ using build2::info;
+ using build2::endf;
+
+ // Drop the state from the previous evaluation of prefer/accept.
+ //
+ if (prefer_accept_)
+ {
+ ctx_ = nullptr;
+ prefer_accept_ = nullopt;
+ }
+
+ // Drop any dependency reflect values from the previous evaluation of
+ // this clause, if any.
+ //
+ if (dependency_reflect_index_ == depends_index)
+ dependency_reflect_.resize (dependency_reflect_pending_);
+
+ // This is what needs to happen to the variables of different origins in
+ // the passed dependency configurations:
+ //
+ // default -- set as default (value::extra=1)
+ // buildfile/dependent -- set as buildfile (value::extra=2)
+ // override/user -- set as override (so cannot be overriden)
+ // undefined -- ignored
+ //
+ // Note that we set value::extra to 2 for buildfile/dependent values.
+ // This is done so that we can detect when they were set by this
+ // dependent (even if to the same value). Note that the build2 config
+ // module only treats 1 as the default value marker.
+ //
+ // Additionally, for all origins we need to typify the variables.
+ //
+ // All of this is done by load(), including removing and returning the
+ // dependency variable prefixes (config.<project>) which we later add
+ // to dependency_var_prefixes_.
+ //
+ strings dvps;
+ scope& rs (load (cfgs, &dvps, true /* defaults */));
+
+ // Evaluate the prefer clause.
+ //
+ {
+ istringstream is (prefer);
+ is.exceptions (istringstream::failbit | istringstream::badbit);
+
+ path_name in ("<depends-prefer-clause>");
+ uint64_t il (1);
+
+ auto df = build2::make_diag_frame (
+ [this, &prefer, &rs, depends_index] (const build2::diag_record& dr)
+ {
+ dr << info << "prefer clause:\n"
+ << trim_right (string (prefer));
+
+ // For external packages we have the manifest so print the
+ // location of the depends value in questions.
+ //
+ if (rs.out_eq_src ())
+ dr << info << "in depends manifest value of package "
+ << package.name;
+ else
+ depends_location (dr,
+ rs.src_path () / manifest_file,
+ depends_index);
+ });
+
+ lexer l (is, in, il /* start line */);
+ buildfile_parser p (rs.ctx, dependency_var_prefixes_);
+ p.parse_buildfile (l, &rs, rs);
+
+ // Check if the dependent set any stray configuration variables.
+ //
+ for (size_t i (0); i != cfgs.size (); ++i)
{
- storage.clear ();
- names_view nv (reverse (*ovr.first, storage));
+ package_configuration& cfg (cfgs[i]);
- if (!nv.empty ())
+ const string& ns (dvps[i]); // Parallel.
+ for (auto p (rs.vars.lookup_namespace (ns));
+ p.first != p.second;
+ ++p.first)
{
- // Note: we need to use command-line (effective) quoting.
+ const variable& var (p.first->first);
+
+ // This can be one of the overrides (__override, __prefix, etc),
+ // which we skip.
//
- ostringstream os;
- to_stream (os, nv, quote_mode::effective, '@');
- s += os.str ();
+ if (var.override ())
+ continue;
+
+ if (cfg.find (var.name) == nullptr)
+ {
+ fail << "package " << cfg.package.name << " has no "
+ << "configuration variable " << var.name <<
+ info << var.name << " set in prefer clause of dependent "
+ << package.string ();
+ }
}
}
+ }
+
+ // Evaluate the accept condition.
+ //
+ bool r;
+ {
+ istringstream is ('(' + accept + ')');
+ is.exceptions (istringstream::failbit | istringstream::badbit);
+
+ path_name in ("<depends-accept-clause>");
+ uint64_t il (1);
+
+ auto df = build2::make_diag_frame (
+ [this, &accept, &rs, depends_index] (const build2::diag_record& dr)
+ {
+ dr << info << "accept condition: (" << accept << ")";
- reflect_vars_.push_back (move (s));
+ // For external packages we have the manifest so print the
+ // location of the depends value in questions.
+ //
+ if (rs.out_eq_src ())
+ dr << info << "in depends manifest value of package "
+ << package.name;
+ else
+ depends_location (dr,
+ rs.src_path () / manifest_file,
+ depends_index);
+ });
+
+ lexer l (is, in, il /* start line */);
+ buildfile_parser p (rs.ctx, dependency_var_prefixes_);
+ value v (p.parse_eval (l, rs, rs, parser::pattern_mode::expand));
+
+ try
+ {
+ // Should evaluate to 'true' or 'false'.
+ //
+ r = build2::convert<bool> (move (v));
+ }
+ catch (const invalid_argument& e)
+ {
+ fail (build2::location (in, il)) << e << endf;
+ }
}
-#if 0
- // TODO: copy over config_vars_ that are not in the map (case #1).
-#endif
+ // If acceptable, update the configuration with the new values, if any.
+ //
+ // We also save the subset of values that were set by this dependent to
+ // be reflected to further clauses.
+ //
+ if (r)
+ {
+ dependency_reflect_index_ = depends_index;
+ dependency_reflect_pending_ = dependency_reflect_.size ();
- // Drop the build system state since it needs reloading (some computed
- // values in root.build may depend on the new configuration values).
+ for (size_t i (0); i != cfgs.size (); ++i)
+ {
+ package_configuration& cfg (cfgs[i]);
+
+ const string& ns (dvps[i]);
+ for (auto p (rs.vars.lookup_namespace (ns));
+ p.first != p.second;
+ ++p.first)
+ {
+ const variable& var (p.first->first);
+
+ if (var.override ())
+ continue;
+
+ const value& val (p.first->second);
+
+ pair<variable_origin, lookup> ol (
+ config::origin (rs,
+ var,
+ pair<lookup, size_t> {
+ lookup {val, var, rs.vars}, 1 /* depth */}));
+
+ config_variable_value& v (*cfg.find (var.name));
+
+ // An override cannot become a non-override. And a non-override
+ // cannot become an override. Except that the dependency override
+ // could be specified (only) for the dependent.
+ //
+ if (v.origin == variable_origin::override_)
+ {
+ assert (ol.first == variable_origin::override_);
+ }
+ else if (ol.first == variable_origin::override_ &&
+ v.origin != variable_origin::override_)
+ {
+ fail << "dependency override " << var.name << " specified for "
+ << "dependent " << package.string () << " but not dependency" <<
+ info << "did you mean to specify ?" << cfg.package.name
+ << " +{ " << var.name << "=... }";
+ }
+
+ switch (ol.first)
+ {
+ case variable_origin::buildfile:
+ {
+ optional<names> ns (reverse_value (val));
+
+ // If this value was set, save it as a dependency reflect.
+ //
+ if (val.extra == 0)
+ {
+ dependency_reflect_.push_back (
+ reflect_variable_value {v.name, ol.first, v.type, ns});
+ }
+
+ // Possible transitions:
+ //
+ // default/undefine -> buildfile -- override dependency default
+ // buildfile -> buildfile -- override other dependent
+ //
+ if (v.origin == variable_origin::buildfile)
+ {
+ // If unchanged, then we keep the old originating dependent
+ // (even if the value was technically "overwritten" by this
+ // dependent).
+ //
+ if (val.extra == 2 || v.value == ns)
+ break;
+ }
+ else
+ v.origin = variable_origin::buildfile;
+
+ v.value = move (ns);
+ v.dependent = package; // We are the originating dependent.
+ v.confirmed = true;
+ break;
+ }
+ case variable_origin::default_:
+ {
+ // A default can only come from a default.
+ //
+ assert (ol.first == v.origin);
+ break;
+ }
+ case variable_origin::override_:
+ {
+ // If the value was set by this dependent then we need to
+ // reflect it even if it was overridden (but as the overridden
+ // value). Note that the mere presence of the value in rs.vars
+ // is not enough to say that it was set -- it could also be
+ // the default value. But we can detect that by examining
+ // value::extra.
+ //
+ if (val.extra == 0)
+ {
+ dependency_reflect_.push_back (
+ reflect_variable_value {
+ v.name, ol.first, v.type, reverse_value (*ol.second)});
+ }
+ break;
+ }
+ case variable_origin::undefined:
+ {
+ // Not possible since we have the defined original.
+ //
+ assert (false);
+ break;
+ }
+ }
+ }
+ }
+
+ // Note that because we add it here, the following reflect clause will
+ // not be able to expand undefined values. We handle this by keeping a
+ // pending position.
+ //
+ dependency_var_prefixes_pending_ = dependency_var_prefixes_.size ();
+ dependency_var_prefixes_.insert (dependency_var_prefixes_.end (),
+ make_move_iterator (dvps.begin ()),
+ make_move_iterator (dvps.end ()));
+
+ // Note: do not drop the build system state yet since it should be
+ // reused by the following reflect clause, if any.
+ //
+ prefer_accept_ = indexes;
+ }
+ else
+ ctx_ = nullptr;
+
+ return r;
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
+ }
+
+ bool package_skeleton::
+ evaluate_require (const dependency_configurations& cfgs,
+ const string& require, pair<size_t, size_t> indexes)
+ {
+ size_t depends_index (indexes.first);
+
+ assert (dependency_reflect_index_ <= depends_index);
+
+ try
+ {
+ using namespace build2;
+ using config::variable_origin;
+ using build2::fail;
+ using build2::info;
+ using build2::endf;
+
+ // Drop the state from the previous evaluation of prefer/accept.
+ //
+ if (prefer_accept_)
+ {
+ ctx_ = nullptr;
+ prefer_accept_ = nullopt;
+ }
+
+ // Drop any dependency reflect values from the previous evaluation of
+ // this clause, if any.
+ //
+ if (dependency_reflect_index_ == depends_index)
+ dependency_reflect_.resize (dependency_reflect_pending_);
+
+ // A require clause can only set bool configuration variables and only
+ // to true and may not have any conditions on other configuration
+ // variables (including their origin). As a result, we don't need to set
+ // the default (or other dependent) values, but will need the type
+ // information as well as overrides. Except that the type information
+ // may not be available for system packages, so we must deal with
+ // that. See negotiate_configuration() for details.
+ //
+ strings dvps;
+ scope& rs (load (cfgs, &dvps, false /* defaults */));
+
+ // Evaluate the require clause.
+ //
+ {
+ istringstream is (require);
+ is.exceptions (istringstream::failbit | istringstream::badbit);
+
+ path_name in ("<depends-require-clause>");
+ uint64_t il (1);
+
+ auto df = build2::make_diag_frame (
+ [this, &require, &rs, depends_index] (const build2::diag_record& dr)
+ {
+ dr << info << "require clause:\n"
+ << trim_right (string (require));
+
+ // For external packages we have the manifest so print the
+ // location of the depends value in questions.
+ //
+ if (rs.out_eq_src ())
+ dr << info << "in depends manifest value of package "
+ << package.name;
+ else
+ depends_location (dr,
+ rs.src_path () / manifest_file,
+ depends_index);
+ });
+
+ lexer l (is, in, il /* start line */);
+ buildfile_parser p (rs.ctx, dependency_var_prefixes_);
+ p.parse_buildfile (l, &rs, rs);
+
+ // Check for stray variables and enforce all the require restrictions
+ // (bool, set to true, etc).
+ //
+ for (size_t i (0); i != cfgs.size (); ++i)
+ {
+ package_configuration& cfg (cfgs[i]);
+
+ const string& ns (dvps[i]); // Parallel.
+ for (auto p (rs.vars.lookup_namespace (ns));
+ p.first != p.second;
+ ++p.first)
+ {
+ // Note that because we didn't set any default (or other
+ // dependent) values, all the values we see are set by this
+ // dependent.
+ //
+ const variable& var (p.first->first);
+
+ // This can be one of the overrides (__override, __prefix, etc),
+ // which we skip.
+ //
+ if (var.override ())
+ continue;
+
+ const value& val (p.first->second);
+
+ // Deal with a system package that has no type information.
+ //
+ if (!cfg.system)
+ {
+ const config_variable_value* v (cfg.find (var.name));
+
+ if (v == nullptr)
+ {
+ fail << "package " << cfg.package.name << " has no "
+ << "configuration variable " << var.name <<
+ info << var.name << " set in require clause of dependent "
+ << package.string ();
+ }
+
+ if (!v->type || *v->type != "bool")
+ {
+ fail << "configuration variable " << var.name << " is not of "
+ << "bool type" <<
+ info << var.name << " set in require clause of dependent "
+ << package.string ();
+ }
+ }
+
+ bool r;
+ if (cfg.system)
+ {
+ try
+ {
+ r = build2::convert<bool> (val);
+ }
+ catch (const invalid_argument&)
+ {
+ r = false;
+ }
+ }
+ else
+ r = cast_false<bool> (val);
+
+ if (!r)
+ {
+ fail << "configuration variable " << var.name << " is not set "
+ << "to true" <<
+ info << var.name << " set in require clause of dependent "
+ << package.string ();
+ }
+ }
+ }
+ }
+
+ // First determine if acceptable.
+ //
+ bool r (true);
+ for (size_t i (0); i != cfgs.size (); ++i)
+ {
+ package_configuration& cfg (cfgs[i]);
+
+ const string& ns (dvps[i]);
+ for (auto p (rs.vars.lookup_namespace (ns));
+ p.first != p.second;
+ ++p.first)
+ {
+ const variable& var (p.first->first);
+
+ if (var.override ())
+ continue;
+
+ const value& val (p.first->second);
+
+ // Note: could be NULL if cfg.system.
+ //
+ const config_variable_value* v (cfg.find (var.name));
+
+ // The only situation where the result would not be acceptable is if
+ // one of the values were overridden to false.
+ //
+ pair<variable_origin, lookup> ol (
+ config::origin (rs,
+ var,
+ pair<lookup, size_t> {
+ lookup {val, var, rs.vars}, 1 /* depth */}));
+
+ // An override cannot become a non-override. And a non-override
+ // cannot become an override. Except that the dependency override
+ // could be specified (only) for the dependent.
+ //
+ if (v != nullptr && v->origin == variable_origin::override_)
+ {
+ assert (ol.first == variable_origin::override_);
+ }
+ else if (ol.first == variable_origin::override_ &&
+ (v == nullptr || v->origin != variable_origin::override_))
+ {
+ fail << "dependency override " << var.name << " specified for "
+ << "dependent " << package.string () << " but not dependency" <<
+ info << "did you mean to specify ?" << cfg.package.name
+ << " +{ " << var.name << "=... }";
+ }
+
+ if (ol.first == variable_origin::override_)
+ {
+ if (cfg.system)
+ {
+ try
+ {
+ if (!build2::convert<bool> (*ol.second))
+ r = false;
+ }
+ catch (const invalid_argument&)
+ {
+ r = false;
+ }
+ }
+ else
+ {
+ if (!cast_false<bool> (*ol.second))
+ r = false;
+ }
+ }
+ }
+ }
+
+ // If acceptable, update the configuration with the new values, if any.
+ //
+ // Note that we cannot easily combine this loop with the above because
+ // we should not modify configurations if the result is not acceptable.
+ //
+ // We also save the subset of values that were set by this dependent to
+ // be reflected to further clauses.
+ //
+ if (r)
+ {
+ dependency_reflect_index_ = depends_index;
+ dependency_reflect_pending_ = dependency_reflect_.size ();
+
+ for (size_t i (0); i != cfgs.size (); ++i)
+ {
+ package_configuration& cfg (cfgs[i]);
+
+ const string& ns (dvps[i]);
+ for (auto p (rs.vars.lookup_namespace (ns));
+ p.first != p.second;
+ ++p.first)
+ {
+ const variable& var (p.first->first);
+
+ if (var.override ())
+ continue;
+
+ config_variable_value* v (cfg.find (var.name));
+
+ if (v == nullptr) // cfg.system
+ {
+ cfg.push_back (
+ config_variable_value {
+ var.name, variable_origin::undefined, {}, {}, {}, false});
+ v = &cfg.back ();
+ }
+
+ // This value was set so save it as a dependency reflect.
+ //
+ // Note that unlike the equivalent evaluate_prefer_accept() logic,
+ // here the value cannot be the default/buildfile (since we don't
+ // set those; see the load() call above).
+ //
+ optional<names> ns (names {name ("true")});
+
+ // Note: force bool type if system.
+ //
+ dependency_reflect_.push_back (
+ reflect_variable_value {
+ v->name,
+ (v->origin == variable_origin::override_
+ ? v->origin
+ : variable_origin::buildfile),
+ cfg.system ? optional<string> ("bool") : v->type,
+ ns});
+
+ if (v->origin != variable_origin::override_)
+ {
+ // Possible transitions:
+ //
+ // default/undefine -> buildfile -- override dependency default
+ // buildfile -> buildfile -- override other dependent
+ //
+
+ if (v->origin == variable_origin::buildfile)
+ {
+ // If unchanged, then we keep the old originating dependent
+ // (even if the value was technically "overwritten" by this
+ // dependent).
+ //
+ if (v->value == ns)
+ continue;
+ }
+ else
+ v->origin = variable_origin::buildfile;
+
+ v->value = move (ns);
+ v->dependent = package; // We are the originating dependent.
+ v->confirmed = true;
+ }
+ }
+ }
+
+ dependency_var_prefixes_.insert (dependency_var_prefixes_.end (),
+ make_move_iterator (dvps.begin ()),
+ make_move_iterator (dvps.end ()));
+ }
+
+ // Drop the build system state since it needs reloading (while it may
+ // seem safe for us to keep the state since we didn't set any defaults,
+ // we may have overrides that the clause did not set, so let's drop it
+ // for good measure and also to keep things simple).
//
ctx_ = nullptr;
+
+ return r;
}
catch (const build2::failed&)
{
@@ -561,75 +2155,649 @@ namespace bpkg
}
}
- pair<strings, vector<optional<config_source>>> package_skeleton::
- collect_config () &&
+ bool package_skeleton::
+ empty_print ()
{
- // Note that if the reflect variables list is not empty, then it also
- // contains the user-specified configuration variables, which all come
- // first (see above).
+ if (!loaded_old_config_)
+ load_old_config ();
+
+ return (dependent_vars_.empty () &&
+ reflect_.empty () &&
+ find_if (config_vars_.begin (), config_vars_.end (),
+ [this] (const string& v)
+ {
+ // See print_config() for details.
+ //
+ size_t vn;
+ if (project_override (v, var_prefix_, &vn))
+ {
+ if (!develop_)
+ {
+ size_t pn (var_prefix_.size ());
+ if (v.compare (pn, vn - pn, ".develop") == 0)
+ return false;
+ }
+
+ return true;
+ }
+ return false;
+ }) == config_vars_.end ());
+ }
+
+ void package_skeleton::
+ print_config (ostream& os, const char* indent)
+ {
+ using build2::config::variable_origin;
+
+ if (!loaded_old_config_)
+ load_old_config ();
+
+ auto print = [&os,
+ indent,
+ first = true] (const string& v) mutable -> ostream&
+ {
+ if (first)
+ first = false;
+ else
+ os << '\n';
+
+ os << indent << v;
+ return os;
+ };
+
+ // NOTE: see also empty_print() if changing anything here.
+
+ // @@ TODO: we could have added the package itself to "set by ..."
+ // for overriden (to the same value) reflect. But then why not
+ // do the same for dependent that is overriden by user (we could
+ // have kept them as reflect_variable_values rather than strings)?
+ // Maybe one day.
+
+ // First comes the user configuration.
//
- size_t nc (config_vars_.size ());
+ for (const string& v: config_vars_)
+ {
+ size_t vn;
+ if (project_override (v, var_prefix_, &vn))
+ {
+ // To reduce the noise (e.g., during bdep-init), skip
+ // config.<project>.develop if the package doesn't use it.
+ //
+ if (!develop_)
+ {
+ size_t pn (var_prefix_.size ());
+ if (v.compare (pn, vn - pn, ".develop") == 0)
+ continue;
+ }
- strings vars (reflect_vars_.empty ()
- ? move (config_vars_)
- : move (reflect_vars_));
+ print (v) << " (" << (system ? "expected " : "")
+ << "user configuration)";
+ }
+ }
- vector<optional<config_source>> sources;
+ // Next dependent configuration.
+ //
+ for (size_t i (0); i != dependent_vars_.size (); ++i)
+ {
+ const string& v (dependent_vars_[i]);
+ const package_key& d (dependent_orgs_[i]); // Parallel.
+
+ print (v) << " (" << (system ? "expected" : "set") << " by "
+ << d << ')';
+ }
+
+ // Finally reflect (but skip overriden).
+ //
+ for (const reflect_variable_value& v: reflect_)
+ {
+ if (v.origin == variable_origin::override_)
+ continue;
+
+ string s (serialize_cmdline (v.name, v.value));
+ print (s) << " (" << (system ? "expected" : "set") << " by "
+ << package.name << ')';
+ }
+ }
+
+ pair<strings, vector<config_variable>> package_skeleton::
+ collect_config () &&
+ {
+ assert (db_ != nullptr); // Must be called only once.
+
+ using build2::config::variable_origin;
+
+ if (!loaded_old_config_)
+ load_old_config ();
+
+ // Merge all the variables into a single list in the correct order
+ // and assign their sources while at it.
+ //
+ strings vars;
+ vector<config_variable> srcs;
- if (!vars.empty ())
+ if (size_t n = (config_vars_.size () +
+ dependent_vars_.size () +
+ reflect_.size ()))
{
- sources.reserve (vars.size ());
+ // For vars we will steal the first non-empty *_vars_. But for sources
+ // reserve the space.
+ //
+ srcs.reserve (n); // At most that many.
- // Assign the user source to only those user-specified configuration
- // variables which are project variables (i.e., names start with
- // config.<project>). Assign the reflect source to all variables that
- // follow the user-specified configuration variables (which can only be
- // project variables).
+ // Return the variable name given the variable override.
//
- // Note that some user-specified variables may have qualifications
- // (global, scope, etc) but there is no reason to expect any project
- // configuration variables to use such qualifications (since they can
- // only apply to one project). So we skip all qualified variables.
+ auto var_name = [] (const string& v)
+ {
+ size_t p (v.find_first_of ("=+ \t"));
+ assert (p != string::npos);
+ return string (v, 0, p);
+ };
+
+ // Note that we assume the three sets of variables do not clash.
//
- string p ("config." + name ().variable ());
- size_t n (p.size ());
- for (const string& v: vars)
+ // First comes the user configuration.
+ //
+ if (!config_vars_.empty ())
{
- if (sources.size () < nc)
+ // Assign the user source only to user-specified configuration
+ // variables which are project variables (i.e., names start with
+ // config.<project>).
+ //
+ for (const string& v: config_vars_)
{
- if (v.compare (0, n, p) == 0 && strchr (".=+ \t", v[n]) != nullptr)
- sources.push_back (config_source::user);
- else
- sources.push_back (nullopt);
+ if (project_override (v, var_prefix_))
+ {
+ string n (var_name (v));
+
+ // Check for a duplicate.
+ //
+ auto i (find_if (srcs.begin (), srcs.end (),
+ [&n] (const config_variable& cv)
+ {
+ return cv.name == n;
+ }));
+
+ if (i == srcs.end ())
+ srcs.push_back (config_variable {move (n), config_source::user});
+ }
}
+
+ vars = move (config_vars_);
+ }
+
+ // Next dependent configuration.
+ //
+ if (!dependent_vars_.empty ())
+ {
+ // These are all project variables. There should also be no duplicates
+ // by construction.
+ //
+ for (const string& v: dependent_vars_)
+ srcs.push_back (
+ config_variable {var_name (v), config_source::dependent});
+
+ if (vars.empty ())
+ vars = move (dependent_vars_);
else
- sources.push_back (config_source::reflect);
+ {
+ vars.reserve (n);
+ vars.insert (vars.end (),
+ make_move_iterator (dependent_vars_.begin ()),
+ make_move_iterator (dependent_vars_.end ()));
+ }
}
- }
- assert (db_ != nullptr);
+ // Finally reflect.
+ //
+ if (!reflect_.empty ())
+ {
+ vars.reserve (n);
- ctx_ = nullptr; // In case we only had conditions.
+ // These are all project variables. There should also be no duplicates
+ // by construction (see evaluate_reflect()).
+ //
+ for (const reflect_variable_value& v: reflect_)
+ {
+ if (v.origin == variable_origin::override_)
+ continue;
+
+ vars.push_back (serialize_cmdline (v.name, v.value));
+ srcs.push_back (config_variable {v.name, config_source::reflect});
+ }
+ }
+ }
+ ctx_ = nullptr; // Free.
db_ = nullptr;
- available_ = nullptr;
- return make_pair (move (vars), move (sources));
+ return make_pair (move (vars), move (srcs));
+ }
+
+ const strings& package_skeleton::
+ merge_cmd_vars (const strings& dependent_vars,
+ const strings& dependency_vars,
+ bool cache)
+ {
+ // Merge variable overrides (note that the order is important). See also a
+ // custom/optimized version in load_old_config().
+ //
+ if (!cache || !cmd_vars_cache_)
+ {
+ const strings& vs1 (build2_cmd_vars);
+ const strings& vs2 (config_vars_);
+ const strings& vs3 (dependent_vars); // Should not override.
+ const strings& vs4 (dependency_vars); // Should not override.
+
+ // Try to reuse both vector and string buffers.
+ //
+ cmd_vars_.resize (
+ 1 + vs1.size () + vs2.size () + vs3.size () + vs4.size ());
+
+ size_t i (0);
+ {
+ string& v (cmd_vars_[i++]);
+
+ // If the package is being disfigured, then don't load config.build at
+ // all. Otherwise, disfigure all package variables (config.<name>**).
+ //
+ // Note that this semantics must be consistent with how we actually
+ // configure the package in pkg_configure().
+ //
+ if (disfigure_)
+ v = "config.config.unload=true";
+ else
+ {
+ // Note: must be quoted to preserve the pattern.
+ //
+ v = "config.config.disfigure='config.";
+ v += package.name.variable ();
+ v += "**'";
+ }
+ }
+
+ for (const string& v: vs1) cmd_vars_[i++] = v;
+ for (const string& v: vs2) cmd_vars_[i++] = v;
+ for (const string& v: vs3) cmd_vars_[i++] = v;
+ for (const string& v: vs4) cmd_vars_[i++] = v;
+
+ cmd_vars_cache_ = cache;
+ }
+
+ return cmd_vars_;
+ }
+
+ void package_skeleton::
+ load_old_config ()
+ {
+ assert (!loaded_old_config_ && ctx_ == nullptr);
+
+ try
+ {
+ using namespace build2;
+
+ // This load that must be done without config.config.disfigure. Also, it
+ // would be nice to optimize for the common case where the only load is
+ // to get the old configuration (e.g., config.*.develop) as part of
+ // collect_config(). So instead of calling merge_cmd_vars() we will do
+ // our own (but consistent) thing.
+ //
+ const strings* cmd_vars (nullptr);
+ {
+ assert (!cmd_vars_cache_); // Sanity check (we are always first).
+
+ const strings& vs1 (build2_cmd_vars);
+ const strings& vs2 (config_vars_);
+
+ if (!disfigure_)
+ cmd_vars = (vs2.empty () ? &vs1 : vs1.empty () ? &vs2 : nullptr);
+
+ if (cmd_vars == nullptr)
+ {
+ // Note: the order is important (see merge_cmd_vars()).
+ //
+ cmd_vars_.reserve ((disfigure_ ? 1 : 0) + vs1.size () + vs2.size ());
+
+ // If the package is being disfigured, then don't load config.build
+ // at all.
+ //
+ if (disfigure_)
+ cmd_vars_.push_back ("config.config.unload=true");
+
+ cmd_vars_.insert (cmd_vars_.end (), vs1.begin (), vs1.end ());
+ cmd_vars_.insert (cmd_vars_.end (), vs2.begin (), vs2.end ());
+
+ cmd_vars = &cmd_vars_;
+ }
+ }
+
+ scope& rs (*bootstrap (*this, *cmd_vars)->second.front ());
+
+ // Load project's root.build.
+ //
+ load_root (rs);
+
+ if (const variable* var = rs.var_pool ().find (var_prefix_ + ".develop"))
+ {
+ // Use the fact that the variable is typed as a proxy for it being
+ // defined with config directive (the more accurate way would be via
+ // the config module's saved variables map).
+ //
+ develop_ = (var->type != nullptr);
+ }
+
+ // @@ TODO: should we also verify user-specified project configuration
+ // variables are not bogus? But they could be untyped...
+ //
+ // Also, build2 warns about unused variables being dropped.
+ //
+ // Note that currently load_old_config() is disabled unless there is
+ // a config.*.develop variable; see package_skeleton ctor.
+
+ // Extract and merge old user configuration variables from config.build
+ // (or equivalent) into config_vars.
+ //
+ if (config_srcs_ != nullptr)
+ {
+ assert (!disfigure_);
+
+ auto i (config_vars_.begin ()); // Insert position, see below.
+
+ names storage;
+ for (const config_variable& v: *config_srcs_)
+ {
+ if (v.source != config_source::user)
+ continue;
+
+ using config::variable_origin;
+
+ pair<variable_origin, lookup> ol (config::origin (rs, v.name));
+
+ switch (ol.first)
+ {
+ case variable_origin::override_:
+ {
+ // Already in config_vars.
+ //
+ // @@ TODO: theoretically, this could be an append/prepend
+ // override(s) and to make this work correctly we would need
+ // to replace them with an assign override with the final
+ // value. Maybe one day.
+ //
+ break;
+ }
+ case variable_origin::buildfile:
+ {
+ // Doesn't really matter where we add them though conceptually
+ // feels like old should go before new (and in the original
+ // order).
+ //
+ i = config_vars_.insert (
+ i,
+ serialize_cmdline (v.name, *ol.second, storage)) + 1;
+
+ break;
+ }
+ case variable_origin::undefined:
+ case variable_origin::default_:
+ {
+ // Old user configuration no longer in config.build. We could
+ // complain but that feels overly drastic. Seeing that we will
+ // recalculate the new set of config variable sources, let's
+ // just ignore this (we could issue a warning, but who knows how
+ // many times it will be issued with all this backtracking).
+ //
+ break;
+ }
+ }
+ }
+ }
+
+ loaded_old_config_ = true;
+ verified_ = true; // Managed to load without errors.
+ ctx_ = nullptr;
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
}
build2::scope& package_skeleton::
- load ()
+ load (const dependency_configurations& cfgs, strings* dvps, bool defaults)
{
if (ctx_ != nullptr)
- return *rs_;
+ {
+ // We have to reload if there is any dependency configuration.
+ //
+ if (cfgs.empty ())
+ return *rs_;
+
+ ctx_ = nullptr;
+ }
+
+ if (!loaded_old_config_)
+ load_old_config ();
+
+ try
+ {
+ using namespace build2;
+ using build2::config::variable_origin;
+
+ // If we have any dependency configurations, then here we need to add
+ // dependency configuration variables with the override origin to the
+ // command line overrides (see evaluate_prefer_accept() for details).
+ // While at it, handle dependency variable prefixes.
+ //
+ strings dependency_vars;
+ for (const package_configuration& cfg: cfgs)
+ {
+ for (const config_variable_value& v: cfg)
+ {
+ if (v.origin == variable_origin::override_)
+ dependency_vars.push_back (v.serialize_cmdline ());
+ }
+
+ string p ("config." + cfg.package.name.variable ());
+
+ auto i (find (dependency_var_prefixes_.begin (),
+ dependency_var_prefixes_.end (),
+ p));
+ if (i != dependency_var_prefixes_.end ())
+ dependency_var_prefixes_.erase (i);
+
+ dvps->push_back (move (p));
+ }
+
+ // If there aren't any, then we can reuse already merged cmd_vars (they
+ // don't change during evaluate_*() calls except for the dependency
+ // overrides case).
+ //
+ const strings& cmd_vars (
+ merge_cmd_vars (dependent_vars_,
+ dependency_vars,
+ dependency_vars.empty () /* cache */));
+
+ auto rsi (bootstrap (*this, cmd_vars));
+ scope& rs (*rsi->second.front ());
+
+ // Load project's root.build as well as potentially accumulated reflect
+ // variables.
+ //
+ // If we have the accumulated reflect variables, wedge them just before
+ // loading root.build (but after initializing config which may load
+ // config.build and which we wish to override).
+ //
+ // Note that the plan for non-external packages is to extract the
+ // configuration and then load it with config.config.load and this
+ // approach should work for that case too.
+ //
+ // This is also where we set dependency configuration variables with the
+ // default and buildfile origins and typify all dependency variables
+ // (see evaluate_prefer_accept() for details).
+ //
+ function<void (parser&)> pre;
+
+ struct data
+ {
+ scope& rs;
+ const dependency_configurations& cfgs;
+ bool defaults;
+ } d {rs, cfgs, defaults};
+
+ if (!cfgs.empty () ||
+ !reflect_.empty () ||
+ !dependency_reflect_.empty ())
+ {
+ pre = [this, &d] (parser&)
+ {
+ scope& rs (d.rs);
+
+ auto insert_var = [&rs] (const string& name,
+ const optional<string>& type)
+ -> const variable&
+ {
+ const value_type* vt (nullptr);
+ if (type)
+ {
+ vt = parser::find_value_type (&rs, *type);
+ assert (vt != nullptr);
+ }
+
+ return rs.var_pool ().insert (name, vt);
+ };
+
+ for (const reflect_variable_value& v: reflect_)
+ {
+ if (v.origin == variable_origin::override_)
+ continue;
+
+ const variable& var (insert_var (v.name, v.type)); // Note: untyped.
+ value& val (rs.assign (var));
+
+ if (v.value)
+ val.assign (names (*v.value), &var);
+ else
+ val = nullptr;
+ }
+
+ // Note that for now we don't bother setting overridden reflect
+ // values as overrides. It seems the only reason to go through the
+ // trouble would be to get the accurate $origin() result. But basing
+ // any decisions on whether the reflect value was overridden or not
+ // seems far fetched.
+ //
+ for (const reflect_variable_value& v: dependency_reflect_)
+ {
+ const variable& var (insert_var (v.name, v.type));
+ value& val (rs.assign (var));
+
+ if (v.value)
+ val.assign (names (*v.value), &var);
+ else
+ val = nullptr;
+ }
+
+ for (const package_configuration& cfg: d.cfgs)
+ {
+ for (const config_variable_value& v: cfg)
+ {
+ const variable& var (insert_var (v.name, v.type));
+
+ switch (v.origin)
+ {
+ case variable_origin::default_:
+ case variable_origin::buildfile:
+ {
+ if (d.defaults)
+ {
+ auto& val (
+ static_cast<variable_map::value_data&> (
+ rs.assign (var)));
+
+ if (v.value)
+ val.assign (names (*v.value), &var);
+ else
+ val = nullptr;
+
+ val.extra = v.origin == variable_origin::default_ ? 1 : 2;
+ }
+ break;
+ }
+ case variable_origin::undefined:
+ case variable_origin::override_: break;
+ }
+ }
+ }
+ };
+ }
+
+ load_root (rs, pre);
+
+ setup_base (rsi,
+ out_root_.empty () ? src_root_ : out_root_,
+ src_root_);
+
+ rs_ = &rs;
+ return rs;
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
+ }
+
+ // Create the build context.
+ //
+ static void
+ create_context (package_skeleton& skl, const strings& cmd_vars)
+ {
+ assert (skl.db_ != nullptr && skl.ctx_ == nullptr);
+
+ // Initialize the build system.
+ //
+ if (!build2_sched.started ())
+ build2_init (*skl.co_);
+
+ try
+ {
+ using namespace build2;
+ using build2::fail;
+ using build2::endf;
+
+ // Create build context.
+ //
+ skl.ctx_.reset (
+ new context (build2_sched,
+ build2_mutexes,
+ build2_fcache,
+ false /* match_only */, // Shouldn't matter.
+ false /* no_external_modules */,
+ false /* dry_run */, // Shouldn't matter.
+ false /* keep_going */, // Shouldnt' matter.
+ cmd_vars));
+ }
+ catch (const build2::failed&)
+ {
+ throw failed (); // Assume the diagnostics has already been issued.
+ }
+ }
+
+ // Bootstrap the package skeleton.
+ //
+ static build2::scope_map::iterator
+ bootstrap (package_skeleton& skl, const strings& cmd_vars)
+ {
+ assert (skl.db_ != nullptr &&
+ skl.ctx_ == nullptr &&
+ skl.available != nullptr);
// The overall plan is as follows:
//
// 0. Create filesystem state if necessary (could have been created by
// another instance, e.g., during simulation).
//
- // 1. Load the state potentially with accumulated reflect fragment.
+ // 1. Bootstrap the package skeleton.
//
// Creating a new context is not exactly cheap (~1.2ms debug, 0.08ms
// release) so we could try to re-use it by cleaning all the scopes other
@@ -640,22 +2808,22 @@ namespace bpkg
// Create the skeleton filesystem state, if it doesn't exist yet.
//
- if (!created_)
+ if (!skl.created_)
{
- const available_package& ap (*available_);
+ const available_package& ap (*skl.available);
// Note that we create the skeleton directories in the skeletons/
// subdirectory of the configuration temporary directory to make sure
// they never clash with other temporary subdirectories (git
// repositories, etc).
//
- if (src_root_.empty () || out_root_.empty ())
+ if (skl.src_root_.empty () || skl.out_root_.empty ())
{
// Cannot be specified if src_root_ is unspecified.
//
- assert (out_root_.empty ());
+ assert (skl.out_root_.empty ());
- auto i (tmp_dirs.find (db_->config_orig));
+ auto i (tmp_dirs.find (skl.db_->config_orig));
assert (i != tmp_dirs.end ());
// Make sure the source and out root directories, if set, are absolute
@@ -667,15 +2835,15 @@ namespace bpkg
dir_path d (normalize (i->second, "temporary directory"));
d /= "skeletons";
- d /= name ().string () + '-' + ap.version.string ();
+ d /= skl.package.name.string () + '-' + ap.version.string ();
- if (src_root_.empty ())
- src_root_ = move (d); // out_root_ is the same.
+ if (skl.src_root_.empty ())
+ skl.src_root_ = move (d); // out_root_ is the same.
else
- out_root_ = move (d); // Don't even need to create it.
+ skl.out_root_ = move (d); // Don't even need to create it.
}
- if (!exists (src_root_))
+ if (!exists (skl.src_root_))
{
// Create the buildfiles.
//
@@ -684,7 +2852,7 @@ namespace bpkg
// additional files.
//
{
- path bf (src_root_ / std_bootstrap_file);
+ path bf (skl.src_root_ / std_bootstrap_file);
mk_p (bf.directory ());
@@ -707,7 +2875,7 @@ namespace bpkg
save (*ap.bootstrap_build, bf);
if (ap.root_build)
- save (*ap.root_build, src_root_ / std_root_file);
+ save (*ap.root_build, skl.src_root_ / std_root_file);
}
// Create the manifest file containing the bare minimum of values
@@ -716,7 +2884,7 @@ namespace bpkg
//
{
package_manifest m;
- m.name = name ();
+ m.name = skl.package.name;
m.version = ap.version;
// Note that there is no guarantee that the potential build2
@@ -738,7 +2906,7 @@ namespace bpkg
m.dependencies.push_back (das);
}
- path mf (src_root_ / manifest_file);
+ path mf (skl.src_root_ / manifest_file);
try
{
@@ -763,58 +2931,19 @@ namespace bpkg
}
}
- created_ = true;
+ skl.created_ = true;
}
- // Initialize the build system.
- //
- if (!build2_sched.started ())
- build2_init (*co_);
-
try
{
using namespace build2;
using build2::fail;
using build2::endf;
- // Create build context.
- //
- // We can reasonably assume reflect cannot have global or absolute scope
- // variable overrides so we don't need to pass them to context.
-
- // Merge variable overrides (note that the order is important).
+ // Create the build context.
//
- strings* cmd_vars;
- {
- strings& v1 (build2_cmd_vars);
- strings& v2 (config_vars_);
-
- cmd_vars = (v2.empty () ? &v1 : v1.empty () ? &v2 : nullptr);
-
- if (cmd_vars == nullptr)
- {
- if (cmd_vars_.empty ()) // Cached.
- {
- cmd_vars_.reserve (v1.size () + v2.size ());
- cmd_vars_.assign (v1.begin (), v1.end ());
- cmd_vars_.insert (cmd_vars_.end (), v2.begin (), v2.end ());
- }
-
- cmd_vars = &cmd_vars_;
- }
- }
-
- ctx_.reset (
- new context (build2_sched,
- build2_mutexes,
- build2_fcache,
- false /* match_only */, // Shouldn't matter.
- false /* no_external_modules */,
- false /* dry_run */, // Shouldn't matter.
- false /* keep_going */, // Shouldnt' matter.
- *cmd_vars));
-
- context& ctx (*ctx_);
+ create_context (skl, cmd_vars);
+ context& ctx (*skl.ctx_);
// This is essentially a subset of the steps we perform in b.cxx. See
// there for more detailed comments.
@@ -835,8 +2964,10 @@ namespace bpkg
// Note that it's ok for out_root to not exist (external package).
//
- const dir_path& src_root (src_root_);
- const dir_path& out_root (out_root_.empty () ? src_root_ : out_root_);
+ const dir_path& src_root (skl.src_root_);
+ const dir_path& out_root (skl.out_root_.empty ()
+ ? skl.src_root_
+ : skl.out_root_);
auto rsi (create_root (ctx, out_root, src_root));
scope& rs (*rsi->second.front ());
@@ -849,16 +2980,31 @@ namespace bpkg
if (!v)
v = src_root;
else
- assert (cast<dir_path> (v) == src_root);
+ {
+ // If the package directory was moved, then it's possible we will have
+ // src-root.build with an old src_root value. Presumably this will
+ // cause the package to be re-configured and so ignoring the old value
+ // here should be ok. Note that the outdated src-root.build can also
+ // mess up subproject discovery in create_bootstrap_outer() but we
+ // omit that part.
+ //
+ if (cast<dir_path> (v) != src_root)
+ v = src_root;
+ }
setup_root (rs, false /* forwarded */);
bootstrap_pre (rs, altn);
bootstrap_src (rs, altn,
- db_->config.relative (out_root) /* amalgamation */,
- false /* subprojects */);
+ skl.db_->config.relative (out_root) /* amalgamation */,
+ false /* subprojects */);
- create_bootstrap_outer (rs);
+
+ // Omit discovering amalgamation's subprojects (i.e., all the packages
+ // in the configuration). Besides being a performance optimization, this
+ // also sidesteps the issue of outdated src-root.build (see above).
+ //
+ create_bootstrap_outer (rs, false /* subprojects */);
bootstrap_post (rs);
assert (mif.meta_operation_pre == nullptr);
@@ -866,41 +3012,7 @@ namespace bpkg
ctx.enter_project_overrides (rs, out_root, ctx.var_overrides);
- // Load project's root.build.
- //
- // If we have the accumulated reflect fragment, wedge it just before
- // loading root.build (but after initializing config which may load
- // config.build and which we wish to override).
- //
- // Note that the plan for non-external packages is to extract the
- // configuration and then load it with config.config.load and this
- // approach should work for that case too.
- //
- function<void (parser&)> pre;
-
- if (!reflect_frag_.empty ())
- {
- pre = [this, &rs] (parser& p)
- {
- istringstream is (reflect_frag_);
- is.exceptions (istringstream::failbit | istringstream::badbit);
-
- // Note that the fragment is just a bunch of variable assignments
- // and thus unlikely to cause any errors.
- //
- path_name in ("<accumulated-reflect-fragment>");
- p.parse_buildfile (is, in, &rs, rs);
- };
- }
-
- load_root (rs, pre);
-
- // Setup root scope as base.
- //
- setup_base (rsi, out_root, src_root);
-
- rs_ = &rs;
- return rs;
+ return rsi;
}
catch (const build2::failed&)
{
diff --git a/bpkg/package-skeleton.hxx b/bpkg/package-skeleton.hxx
index aaa9b8c..7224d1d 100644
--- a/bpkg/package-skeleton.hxx
+++ b/bpkg/package-skeleton.hxx
@@ -4,12 +4,13 @@
#ifndef BPKG_PACKAGE_SKELETON_HXX
#define BPKG_PACKAGE_SKELETON_HXX
-#include <libbuild2/forward.hxx> // build2::context
+#include <libbuild2/forward.hxx>
#include <bpkg/types.hxx>
#include <bpkg/utility.hxx>
#include <bpkg/package.hxx>
+#include <bpkg/package-configuration.hxx>
#include <bpkg/common-options.hxx>
namespace bpkg
@@ -20,6 +21,12 @@ namespace bpkg
class package_skeleton
{
public:
+ // If the package is system, then its available package should be NULL if
+ // it doesn't match the system package version "close enough" to be usable
+ // as the source of its configuration information (types, defaults). If it
+ // is NULL, then the skeleton can only be used to print and collect the
+ // configuration information.
+ //
// If the package is external, then the existing package source root
// directory needs to be specified (as absolute and normalized). In this
// case, if output root is specified (as absolute and normalized; normally
@@ -29,50 +36,152 @@ namespace bpkg
// If the package is not external, then none of the root directories
// should be specified.
//
- // Note that the options, database, and available_package are expected to
+ // The disfigure argument should indicate whether the package is being
+ // reconfigured from scratch (--disfigure).
+ //
+ // The config_vars argument contains configuration variables specified by
+ // the user in this bpkg execution. Optional config_srcs is used to
+ // extract (from config.build or equivalent) configuration variables
+ // specified by the user in previous bpkg executions. It should be NULL if
+ // this is the first build of the package. The extracted variables are
+ // merged with config_vars and the combined result is returned by
+ // collect_config() below.
+ //
+ // @@ TODO: speaking of the "config.build or equivalent" part, the
+ // equivalent is likely to be extracted configuration (probably saved
+ // to file in tmp somewhere) that we will load with config.config.load.
+ // It doesn't seem like a good idea to pass it as part of config_vars
+ // (because sometimes we may need to omit it) so most likely it will be
+ // passed as a separate arguments (likely a file path).
+ //
+ // Note that the options, database, and config_srcs are expected to
// outlive this object.
//
// Note also that this creates an "unloaded" skeleton and is therefore
// relatively cheap.
//
package_skeleton (const common_options& co,
- database&,
- const available_package&,
+ package_key,
+ bool system,
+ shared_ptr<const available_package>,
strings config_vars,
+ bool disfigure,
+ const vector<config_variable>* config_srcs,
optional<dir_path> src_root,
optional<dir_path> out_root);
- // For the following evaluate_*() functions assume that the clause belongs
- // to the specified (by index) depends value (used to print its location
- // on failure for an external package).
+
+ package_key package;
+ bool system;
+ shared_ptr<const available_package> available;
+
+ // The following functions should be called in the following sequence
+ // (* -- zero or more, ? -- zero or one):
+ //
+ // * reload_defaults() | verify_sensible()
+ // ? dependent_config()
+ // * evaluate_*()
+ // * empty() | print_config()
+ // collect_config()
+ //
+ // Note that a copy of the skeleton is expected to continue with the
+ // sequence rather than starting from scratch, unless reset() is called.
+ //
+ public:
+ // Reload the default values and type information for configuration
+ // variables using the values with the buildfile origin as a "tentative"
+ // dependent configuration.
+ //
+ void
+ reload_defaults (package_configuration&);
+
+ // Load overrides for a system package without skeleton info. Note that
+ // this is done in an ad hoc manner and only to support evaluate_require()
+ // semantics (see the implementation for details).
+ //
+ void
+ load_overrides (package_configuration&);
+
+ // Verify the specified "tentative" dependent configuration is sensible,
+ // that is, acceptable to the dependency itself. If it is not, then the
+ // second half of the result contains the diagnostics.
+ //
+ pair<bool, string>
+ verify_sensible (const package_configuration&);
+
+ // Incorporate the "final" dependent configuration into subsequent
+ // evaluations. Dependent configuration variables are expected not to
+ // clash with user.
//
+ void
+ dependent_config (const package_configuration&);
+
+ // For the following evaluate_*() functions assume that the clause belongs
+ // to the dependency alternative specified as a pair of indexes (depends
+ // value index and alternative index).
+
// Evaluate the enable clause.
//
bool
- evaluate_enable (const string&, size_t depends_index);
+ evaluate_enable (const string&, pair<size_t, size_t>);
// Evaluate the reflect clause.
//
void
- evaluate_reflect (const string&, size_t depends_index);
+ evaluate_reflect (const string&, pair<size_t, size_t>);
+
+ // Evaluate the prefer/accept or require clauses on the specified
+ // dependency configurations (serves as both input and output).
+ //
+ // Return true is acceptable and false otherwise. If acceptable, the
+ // passed configuration is updated with new values, if any.
+ //
+ using dependency_configurations =
+ small_vector<reference_wrapper<package_configuration>, 1>;
+
+ bool
+ evaluate_prefer_accept (const dependency_configurations&,
+ const string&, const string&, pair<size_t, size_t>);
+
+ bool
+ evaluate_require (const dependency_configurations&,
+ const string&, pair<size_t, size_t>);
+
+ // Reset the skeleton to the start of the call sequence.
+ //
+ // Note that this function cannot be called after collect_config().
+ //
+ void
+ reset ();
- // Return the accumulated reflect values together with their sources (the
- // resulting vectors are parallel).
+ // Return true if there are no accumulated *project* configuration
+ // variables that will be printed by print_config().
//
- // Note that the result is merged with config_vars and should be used
- // instead rather than in addition to config_vars. The source of
- // configuration variables which are not the project variables is absent.
+ bool
+ empty_print ();
+
+ // Print the accumulated *project* configuration variables as command line
+ // overrides one per line with the specified indentation.
+ //
+ void
+ print_config (ostream&, const char* indent);
+
+ // Return the accumulated configuration variables (first) and project
+ // configuration variable sources (second). Note that the arrays are not
+ // necessarily parallel (config_vars may contain non-project variables).
+ //
+ // Note that the dependent and reflect variables are merged with
+ // config_vars/config_srcs and should be used instead rather than in
+ // addition to config_vars.
//
// Note also that this should be the final call on this object.
//
- pair<strings, vector<optional<config_source>>>
+ pair<strings, vector<config_variable>>
collect_config () &&;
- const package_name&
- name () const {return available_->id.name;}
-
// Implementation details.
//
+ public:
// We have to define these because context is forward-declared. Also, copy
// constructor has some special logic.
//
@@ -84,32 +193,146 @@ namespace bpkg
package_skeleton& operator= (const package_skeleton&) = delete;
private:
- // Create the skeleton if necessary and (re)load the build system state.
+ // Load old user configuration variables from config.build (or equivalent)
+ // and merge them into config_vars_. Also verify new user configuration
+ // already in config_vars_ makes sense.
+ //
+ // This should be done before any attempt to load the configuration with
+ // config.config.disfigure and, if this did not happen, inside
+ // collect_config() (since the package will be reconfigured with
+ // config.config.disfigure).
+ //
+ void
+ load_old_config ();
+
+ // (Re)load the build system state.
//
// Call this function before evaluating every clause.
//
+ // If dependency configurations are specified, then typify the variables
+ // and set their values. If defaults is false, then only typify the
+ // variables and set overrides without setting the default/buildfile
+ // values. Note that buildfile values have value::extra set to 2. While
+ // at it, also remove from dependency_var_prefixes_ and add to
+ // dependency_var_prefixes variable prefixes (config.<project>) for
+ // the passed dependencies.
+ //
build2::scope&
- load ();
+ load (const dependency_configurations& = {},
+ strings* dependency_var_prefixes = nullptr,
+ bool defaults = true);
- private:
+ // Merge command line variable overrides into one list (normally to be
+ // passed to bootstrap()).
+ //
+ // If cache is true, then assume the result can be reused on subsequent
+ // calls.
+ //
+ const strings&
+ merge_cmd_vars (const strings& dependent_vars,
+ const strings& dependency_vars = {},
+ bool cache = false);
+
+ // Implementation details (public for bootstrap()).
+ //
+ public:
// NOTE: remember to update move/copy constructors!
//
const common_options* co_;
database* db_;
- const available_package* available_;
+
+ string var_prefix_; // config.<project>
+
strings config_vars_;
+ bool disfigure_;
+ const vector<config_variable>* config_srcs_; // NULL if nothing to do or
+ // already done.
dir_path src_root_; // Must be absolute and normalized.
dir_path out_root_; // If empty, the same as src_root_.
bool created_ = false;
+ bool verified_ = false;
+ bool loaded_old_config_;
+ bool develop_ = true; // Package has config.*.develop.
+
unique_ptr<build2::context> ctx_;
build2::scope* rs_ = nullptr;
- strings cmd_vars_; // Storage for merged build2_cmd_vars and config_vars_.
- strings reflect_names_; // Reflect configuration variable names.
- strings reflect_vars_; // Reflect configuration variable overrides.
- string reflect_frag_; // Reflect configuration variable fragment.
+ // Storage for merged build2_cmd_vars and config_vars_ and extra overrides
+ // (like config.config.disfigure). If cache is true, then the existing
+ // content can be reused.
+ //
+ strings cmd_vars_;
+ bool cmd_vars_cache_ = false;
+
+ strings dependent_vars_; // Dependent variable overrides.
+ vector<package_key> dependent_orgs_; // Dependent originators (parallel).
+
+ // Reflect variable value storage. Used for both real reflect and
+ // dependency reflect.
+ //
+ struct reflect_variable_value
+ {
+ string name;
+ build2::config::variable_origin origin;
+ optional<string> type;
+ optional<build2::names> value;
+ };
+
+ class reflect_variable_values: public vector<reflect_variable_value>
+ {
+ public:
+ const reflect_variable_value*
+ find (const string& name)
+ {
+ auto i (find_if (begin (), end (),
+ [&name] (const reflect_variable_value& v)
+ {
+ return v.name == name;
+ }));
+ return i != end () ? &*i : nullptr;
+ }
+ };
+
+ reflect_variable_values reflect_; // Reflect variables.
+
+ // Dependency configuration variables set by the prefer/require clauses
+ // and that should be reflected in subsequent clauses.
+ //
+ // The same prefer/require clause could be re-evaluated multiple times in
+ // which case the previous dependency reflect values from this clause (but
+ // not from any previous clauses) should be dropped. This is achieved by
+ // keeping track of the depends_index for the most recently evaluated
+ // prefer/require clause along with the position of the first element that
+ // was added by this clause. Note also that this logic does the right
+ // thing if we move to a different dependency alternative withing the same
+ // depends value.
+ //
+ reflect_variable_values dependency_reflect_;
+ size_t dependency_reflect_index_ = 0;
+ size_t dependency_reflect_pending_ = 0;
+
+ // List of variable prefixes (config.<project>) of all known dependencies.
+ //
+ // This information is used to detect and diagnose references to undefined
+ // dependency configuration variables (for example, those that were not
+ // set and therefore not reflected). The pending index is used to ignore
+ // the entries added by the last evaluate_prefer_accept() in the following
+ // reflect clause (see prefer_accept_ below for details).
+ //
+ strings dependency_var_prefixes_;
+ size_t dependency_var_prefixes_pending_ = 0;
+
+ // Position of the last successfully evaluated prefer/accept clauses.
+ //
+ // This information is used to make all (as opposed to only those set by
+ // the prefer clause) dependency configuration variables available to the
+ // reflect clause but only at the same position. This allows for some more
+ // advanced configuration techniques, such as, using a feature if enabled
+ // by someone else but not having any preferences ourselves.
+ //
+ optional<pair<size_t, size_t>> prefer_accept_;
};
}
diff --git a/bpkg/package.cxx b/bpkg/package.cxx
index 3a356f8..c02bdf4 100644
--- a/bpkg/package.cxx
+++ b/bpkg/package.cxx
@@ -53,17 +53,17 @@ namespace bpkg
return path;
}
- // config_package
+ // package_key
//
- string config_package::
+ string package_key::
string () const
{
- const std::string& s (db.string);
+ const std::string& s (db.get ().string);
return !s.empty () ? name.string () + ' ' + s : name.string ();
}
- bool config_package::
- operator< (const config_package& v) const
+ bool package_key::
+ operator< (const package_key& v) const
{
int r (name.compare (v.name));
return r != 0 ? (r < 0) : (db < v.db);
@@ -827,7 +827,7 @@ namespace bpkg
bool
toolchain_buildtime_dependency (const common_options& o,
const dependency_alternatives_ex& das,
- const package_name& pkg)
+ const package_name* pkg)
{
if (das.buildtime)
{
@@ -839,10 +839,10 @@ namespace bpkg
if (dn == "build2")
{
- if (d.constraint && !satisfy_build2 (o, d))
+ if (pkg != nullptr && d.constraint && !satisfy_build2 (o, d))
{
fail << "unable to satisfy constraint (" << d << ") for "
- << "package " << pkg <<
+ << "package " << *pkg <<
info << "available build2 version is " << build2_version;
}
@@ -850,10 +850,10 @@ namespace bpkg
}
else if (dn == "bpkg")
{
- if (d.constraint && !satisfy_bpkg (o, d))
+ if (pkg != nullptr && d.constraint && !satisfy_bpkg (o, d))
{
fail << "unable to satisfy constraint (" << d << ") for "
- << "package " << pkg <<
+ << "package " << *pkg <<
info << "available bpkg version is " << bpkg_version;
}
@@ -865,4 +865,18 @@ namespace bpkg
return false;
}
+
+ bool
+ has_dependencies (const common_options& o,
+ const dependencies& deps,
+ const package_name* pkg)
+ {
+ for (const auto& das: deps)
+ {
+ if (!toolchain_buildtime_dependency (o, das, pkg))
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index 7dc8e11..dc5031c 100644
--- a/bpkg/package.hxx
+++ b/bpkg/package.hxx
@@ -27,7 +27,7 @@
//
#define DB_SCHEMA_VERSION_BASE 7
-#pragma db model version(DB_SCHEMA_VERSION_BASE, 18, closed)
+#pragma db model version(DB_SCHEMA_VERSION_BASE, 19, closed)
namespace bpkg
{
@@ -580,17 +580,27 @@ namespace bpkg
make_move_iterator (das.end ()));
}
- // If this is a toolchain build-time dependency, then verify its constraint
- // returning true if it is satisfied and failing otherwise. Return false for
- // a regular dependency. Note that the package argument is used for
- // diagnostics only.
+ // Return true if this is a toolchain build-time dependency. If the package
+ // argument is specified and this is a toolchain build-time dependency then
+ // also verify its constraint and fail if it is unsatisfied. Note that the
+ // package argument is used for diagnostics only.
//
class common_options;
bool
toolchain_buildtime_dependency (const common_options&,
const dependency_alternatives_ex&,
- const package_name&);
+ const package_name*);
+
+ // Return true if any dependency other than toolchain build-time
+ // dependencies is specified. Optionally, verify toolchain build-time
+ // dependencies specifying the package argument which will be used for
+ // diagnostics only.
+ //
+ bool
+ has_dependencies (const common_options&,
+ const dependencies&,
+ const package_name* = nullptr);
// Return true if some clause that is a buildfile fragment is specified for
// any of the dependencies.
@@ -1022,21 +1032,63 @@ namespace bpkg
}
// A map of "effective" prerequisites (i.e., pointers to other selected
- // packages) to optional version constraint. Note that because it is a
- // single constraint, we don't support multiple dependencies on the same
- // package (e.g., two ranges of versions). See pkg_configure().
+ // packages) to optional version constraint (plus some other info). Note
+ // that because it is a single constraint, we don't support multiple
+ // dependencies on the same package (e.g., two ranges of versions). See
+ // pkg_configure().
//
// Note also that the pointer can refer to a selected package in another
// database.
//
class selected_package;
+ #pragma db value
+ struct prerequisite_info
+ {
+ // The "tightest" version constraint among all dependencies resolved to
+ // this prerequisite.
+ //
+ optional<version_constraint> constraint;
+
+ // Position of the first dependency alternative with a configuration
+ // clause, if any.
+ //
+ // Specifically, if there is such an alternative then this is a pair of
+ // 1-based indexes of the respective depends value (first) and the
+ // dependency alternative (second) in the dependent's manifest. Otherwise,
+ // this is a pair of zeros.
+ //
+ // For example, for the following dependent the position for libfoo/1.2.0
+ // prerequisite will be {2,2}:
+ //
+ // libbar: depends: libfoo >= 1.1.0
+ // depends: libfox | libfoo >= 1.2.0 {require {...}}
+ //
+ pair<size_t, size_t> config_position;
+
+ // Database mapping.
+ //
+ #pragma db member(constraint) column("")
+
+ #pragma db member(config_position) transient
+
+ #pragma db member(config_dependency_index) \
+ virtual(size_t) \
+ access(config_position.first) \
+ default(0)
+
+ #pragma db member(config_alternative_index) \
+ virtual(size_t) \
+ access(config_position.second) \
+ default(0)
+ };
+
// Note that the keys for this map need to be created with the database
// passed to their constructor, which is required for persisting them (see
// _selected_package_ref() implementation for details).
//
using package_prerequisites = std::map<lazy_shared_ptr<selected_package>,
- optional<version_constraint>,
+ prerequisite_info,
compare_lazy_ptr>;
// Database mapping for lazy_shared_ptr<selected_package> to configuration
@@ -1476,6 +1528,21 @@ namespace bpkg
#pragma db column("pp.package")
package_name name;
+ #pragma db transient
+ pair<size_t, size_t> config_position;
+
+ #pragma db member(config_dependency_index) \
+ column("pp.config_dependency_index") \
+ virtual(size_t) \
+ access(config_position.first) \
+ default(0)
+
+ #pragma db member(config_alternative_index) \
+ column("pp.config_alternative_index") \
+ virtual(size_t) \
+ access(config_position.second) \
+ default(0)
+
#pragma db column("pp.")
optional<version_constraint> constraint;
};
@@ -1501,34 +1568,50 @@ namespace bpkg
// not detached during such map lifetimes. Considers both package name and
// database for objects comparison.
//
- struct config_package
+ struct package_key
{
- database& db;
- package_name name;
+ reference_wrapper<database> db;
+ package_name name;
- config_package (database& d, package_name n): db (d), name (move (n)) {}
+ package_key (database& d, package_name n): db (d), name (move (n)) {}
// Create a pseudo-package (command line as a dependent, etc).
//
- config_package (database& d, string n)
+ package_key (database& d, string n)
: db (d),
name (n.empty () ? package_name () : package_name (move (n))) {}
bool
- operator== (const config_package& v) const
+ operator== (const package_key& v) const
{
// See operator==(database, database).
//
- return name == v.name && &db == &v.db;
+ return name == v.name && &db.get () == &v.db.get ();
}
bool
- operator< (const config_package&) const;
+ operator!= (const package_key& v) const
+ {
+ return !(*this == v);
+ }
+ bool
+ operator< (const package_key&) const;
+
+ // Return the package string representation in the form:
+ //
+ // <name>[ <config-dir>]
+ //
std::string
string () const;
};
+ inline ostream&
+ operator<< (ostream& os, const package_key& p)
+ {
+ return os << p.string ();
+ }
+
// Return a count of repositories that contain this repository fragment.
//
#pragma db view table("main.repository_fragments")
diff --git a/bpkg/package.xml b/bpkg/package.xml
index 904d0f6..8959529 100644
--- a/bpkg/package.xml
+++ b/bpkg/package.xml
@@ -1,4 +1,11 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="sqlite" version="1">
+ <changeset version="19">
+ <alter-table name="main.selected_package_prerequisites">
+ <add-column name="config_dependency_index" type="INTEGER" null="true" default="0"/>
+ <add-column name="config_alternative_index" type="INTEGER" null="true" default="0"/>
+ </alter-table>
+ </changeset>
+
<changeset version="18">
<add-table name="main.selected_package_config_variables" kind="container">
<column name="package" type="TEXT" null="true" options="COLLATE NOCASE"/>
diff --git a/bpkg/pkg-build.cli b/bpkg/pkg-build.cli
index b1415fe..493ffbe 100644
--- a/bpkg/pkg-build.cli
+++ b/bpkg/pkg-build.cli
@@ -379,11 +379,12 @@ namespace bpkg
{
"<sum>",
- "Hash the names and versions of all the packages that would be built.
- If the resulting checksum matches the specified, then exit without
- building anything (potentially with a special error code specified
- with the \cb{--noop-exit} option). Otherwise, proceed to build as
- normal. In both cases, print the resulting checksum to \cb{stdout}."
+ "Hash the names, versions, and configurations of all the packages that
+ would be built. If the resulting checksum matches the specified, then
+ exit without building anything (potentially with a special error code
+ specified with the \cb{--noop-exit} option). Otherwise, proceed to
+ build as normal. In both cases, print the resulting checksum to
+ \cb{stdout}."
}
uint16_t --no-private-config
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index 6d90ff9..331ab9d 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -6,10 +6,13 @@
#include <map>
#include <set>
#include <list>
-#include <cstring> // strlen()
-#include <iostream> // cout
+#include <limits> // numeric_limits
+#include <cstring> // strlen()
+#include <sstream>
+#include <iostream> // cout
+#include <functional> // ref()
+#include <forward_list>
-#include <libbutl/sha256.hxx>
#include <libbutl/standard-version.hxx>
#include <bpkg/package.hxx>
@@ -34,6 +37,7 @@
#include <bpkg/pkg-disfigure.hxx>
#include <bpkg/package-skeleton.hxx>
#include <bpkg/system-repository.hxx>
+#include <bpkg/package-configuration.hxx>
using namespace std;
using namespace butl;
@@ -434,6 +438,55 @@ namespace bpkg
return make_pair (move (ap), move (rf));
}
+ // Try to find an available package corresponding to the specified selected
+ // package and, if not found, return a transient one.
+ //
+ static shared_ptr<available_package>
+ find_available (const common_options& options,
+ database& db,
+ const shared_ptr<selected_package>& sp)
+ {
+ available_package_id pid (sp->name, sp->version);
+ for (database& ddb: dependent_repo_configs (db))
+ {
+ shared_ptr<available_package> ap (ddb.find<available_package> (pid));
+
+ if (ap != nullptr && !ap->stub ())
+ return ap;
+ }
+
+ return make_available (options, db, sp);
+ }
+
+ // As above but also pair the available package with the repository fragment
+ // the available package comes from. Note that the package locations list is
+ // left empty and that the returned repository fragment could be NULL if the
+ // package is an orphan.
+ //
+ static pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>>
+ find_available_fragment (const common_options& options,
+ database& db,
+ const shared_ptr<selected_package>& sp)
+ {
+ available_package_id pid (sp->name, sp->version);
+ for (database& ddb: dependent_repo_configs (db))
+ {
+ shared_ptr<available_package> ap (ddb.find<available_package> (pid));
+
+ if (ap != nullptr && !ap->stub ())
+ {
+ if (shared_ptr<repository_fragment> f = ddb.find<repository_fragment> (
+ sp->repository_fragment.canonical_name ()))
+ return make_pair (ap,
+ lazy_shared_ptr<repository_fragment> (ddb,
+ move (f)));
+ }
+ }
+
+ return make_pair (find_available (options, db, sp), nullptr);
+ }
+
// Return true if the version constraint represents the wildcard version.
//
static inline bool
@@ -453,7 +506,7 @@ namespace bpkg
// prerequisites being replaced ("old"). The unamended prerequisites have no
// entries.
//
- using repointed_dependents = map<config_package, map<config_package, bool>>;
+ using repointed_dependents = map<package_key, map<package_key, bool>>;
// List of the private configuration paths, relative to the containing
// configuration directories (.bpkg/host/, etc), together with the
@@ -480,10 +533,12 @@ namespace bpkg
// any version constraints. Specifically, during this step, we may
// "upgrade" or "downgrade" a package that is already in a map as a
// result of another package depending on it and, for example, requiring
- // a different version. One notable side-effect of this process is that
- // we may end up with a lot more packages in the map (but not in the list)
- // than we will have on the list. This is because some of the prerequisites
- // of "upgraded" or "downgraded" packages may no longer need to be built.
+ // a different version. If that happens, we make sure that the replaced
+ // package version doesn't apply constraints and/or configuration to its
+ // own dependencies anymore and also that its non-shared dependencies are
+ // gone from the map, recursively (see replaced_versions for details).
+ // One notable side-effect of this process is that all the packages in the
+ // map end up in the list.
//
// Note that we don't try to do exhaustive constraint satisfaction (i.e.,
// there is no backtracking). Specifically, if we have two candidate
@@ -557,10 +612,15 @@ namespace bpkg
//
// Initially nullopt. Can be filled partially if the package prerequisite
// builds collection is postponed for any reason (see postponed_packages
- // for possible reasons).
+ // and postponed_configurations for possible reasons).
//
optional<bpkg::dependencies> dependencies;
+ // Indexes of the selected dependency alternatives stored in the above
+ // dependencies member.
+ //
+ optional<vector<size_t>> alternatives;
+
// If we end up collecting the prerequisite builds for this package, then
// this member stores the skeleton of the package being built.
//
@@ -573,15 +633,36 @@ namespace bpkg
// If the package prerequisite builds collection is postponed, then this
// member stores the references to the enabled alternatives (in available
- // package) of a dependency being the cause of the postponement. This, in
- // particular, allows not to re-evaluate conditions multiple times on the
- // re-collection attempts.
+ // package) of a dependency being the cause of the postponement together
+ // with their original indexes in the respective dependency alternatives
+ // list. This, in particular, allows us not to re-evaluate conditions
+ // multiple times on the re-collection attempts.
//
// Note: it shouldn't be very common for a dependency to contain more than
// two true alternatives.
//
- optional<small_vector<reference_wrapper<const dependency_alternative>, 2>>
- postponed_dependency_alternatives;
+ using dependency_alternatives_refs =
+ small_vector<pair<reference_wrapper<const dependency_alternative>,
+ size_t>,
+ 2>;
+
+ optional<dependency_alternatives_refs> postponed_dependency_alternatives;
+
+ // True if the recursive collection of the package has been started or
+ // performed.
+ //
+ // Used by the dependency configuration negotiation machinery which makes
+ // sure that its configuration is negotiated between dependents before its
+ // recursive collection is started (see postponed_configurations for
+ // details).
+ //
+ // Note that the dependencies member cannot be used for that purpose since
+ // it is not always created (think of a system dependency or an existing
+ // dependency that doesn't need its prerequisites re-collection). In a
+ // sense the recursive collection flag is a barrier for the dependency
+ // configuration negotiation.
+ //
+ bool recursive_collection;
// Hold flags. Note that we only "increase" the hold_package value that is
// already in the selected package.
@@ -645,7 +726,7 @@ namespace bpkg
// selection and can be present regardless of the required_by_dependents
// flag value.
//
- set<config_package> required_by;
+ set<package_key> required_by;
// If this flags is true, then required_by contains dependents.
//
@@ -659,8 +740,38 @@ namespace bpkg
bool
user_selection () const
{
- return required_by.find (config_package {db.get ().main_database (),
- ""}) != required_by.end ();
+ return required_by.find (package_key {db.get ().main_database (),
+ ""}) != required_by.end ();
+ }
+
+ // Return true if the configured package needs to be recollected
+ // recursively.
+ //
+ // This is required if it is being built as a source package and needs to
+ // be up/down-graded and/or reconfigured and has some buildfile clauses,
+ // it is a repointed dependent, or it is already in the process of being
+ // collected.
+ //
+ bool
+ recollect_recursively (const repointed_dependents& rpt_depts) const
+ {
+ assert (action &&
+ *action == build_package::build &&
+ available != nullptr &&
+ selected != nullptr &&
+ selected->state == package_state::configured &&
+ selected->substate != package_substate::system);
+
+ // Note that if the skeleton is present then the package is either being
+ // already collected or its configuration has been negotiated between
+ // the dependents.
+ //
+ return !system &&
+ (dependencies ||
+ selected->version != available_version () ||
+ ((!config_vars.empty () || skeleton) &&
+ has_buildfile_clause (available->dependencies)) ||
+ rpt_depts.find (package_key (db, name ())) != rpt_depts.end ());
}
// State flags.
@@ -882,7 +993,8 @@ namespace bpkg
// dependency alternative choice.
//
assert (!skeleton ||
- (p.config_vars == config_vars && p.disfigure == disfigure));
+ ((p.config_vars.empty () || p.config_vars == config_vars) &&
+ p.disfigure == disfigure));
if (p.keep_out)
keep_out = p.keep_out;
@@ -945,6 +1057,57 @@ namespace bpkg
// For other cases ("weak system") we don't want to copy system over in
// order not prevent, for example, system to non-system upgrade.
}
+
+ // Initialize the skeleton of a being built package.
+ //
+ package_skeleton&
+ init_skeleton (const common_options& options,
+ const shared_ptr<available_package>& override = nullptr)
+ {
+ shared_ptr<available_package> ap (override != nullptr
+ ? override
+ : available);
+
+ assert (!skeleton && ap != nullptr);
+
+ package_key pk (db, ap->id.name);
+
+ if (system)
+ {
+ // Keep the available package if its version is "close enough" to the
+ // system package version. For now we will require the exact match
+ // but in the future we could relax this (e.g., allow the user to
+ // specify something like libfoo/^1.2.0 or some such).
+ //
+ const version* v (!ap->stub () ? ap->system_version (db) : nullptr);
+
+ if (v == nullptr || *v != ap->version)
+ ap = nullptr;
+ }
+
+ optional<dir_path> src_root, out_root;
+
+ if (ap != nullptr)
+ {
+ src_root = external_dir ();
+ out_root = (src_root && !disfigure
+ ? dir_path (db.get ().config) /= name ().string ()
+ : optional<dir_path> ());
+ }
+
+ skeleton = package_skeleton (
+ options,
+ move (pk),
+ system,
+ move (ap),
+ config_vars, // @@ Maybe make optional<strings> and move?
+ disfigure,
+ (selected != nullptr ? &selected->config_variables : nullptr),
+ move (src_root),
+ move (out_root));
+
+ return *skeleton;
+ }
};
using build_package_list = list<reference_wrapper<build_package>>;
@@ -954,24 +1117,1205 @@ namespace bpkg
using add_priv_cfg_function = void (database&, dir_path&&);
- struct build_packages: build_package_list
+ // Base for exception types that indicate an inability to collect a package
+ // build because it was collected prematurely (version needs to be replaced,
+ // configuration requires further negotiation, etc).
+ //
+ struct scratch_collection
+ {
+ // Only used for tracing.
+ //
+ const char* description;
+ const package_key* package = nullptr; // Could be NULL.
+
+ explicit
+ scratch_collection (const char* d): description (d) {}
+ };
+
+ // Map of packages which need to be re-collected with the different version
+ // and/or system flag or dropped.
+ //
+ // Note that the initial package version may be adjusted to satisfy
+ // constraints of dependents discovered during the packages collection. It
+ // may also be dropped if this is a dependency which turns out to be unused.
+ // However, it may not always be possible to perform such an adjustment
+ // in-place since the intermediate package version could already apply some
+ // constraints and/or configuration to its own dependencies. Thus, we may
+ // need to note the desired package version information and re-collect from
+ // scratch.
+ //
+ // Also note that during re-collection such a desired version may turn out
+ // to not be a final version and the adjustment/re-collection can repeat.
+ //
+ // And yet, it doesn't seem plausible to ever create a replacement for the
+ // drop: replacing one drop with another is meaningless (all drops are the
+ // same) and replacing the package drop with a package version build can
+ // always been handled in-place.
+ //
+ // On the first glance, the map entries which have not been used for
+ // replacement during the package collection (bogus entries) are harmless
+ // and can be ignored. However, the dependency configuration negotiation
+ // machinery refers to this map and skips existing dependents with
+ // configuration clause which belong to it (see query_existing_dependents()
+ // for details). Thus, if after collection of packages some bogus entries
+ // are present in the map, then it means that we could have erroneously
+ // skipped some existing dependents because of them and so need to erase
+ // these entries and re-collect.
+ //
+ struct replaced_version
+ {
+ // Desired package version, repository fragment, and system flag.
+ //
+ // Both are NULL for the replacement with the drop.
+ //
+ shared_ptr<available_package> available;
+ lazy_shared_ptr<bpkg::repository_fragment> repository_fragment;
+ bool system; // Meaningless for the drop.
+
+ // True if the entry has been inserted or used for the replacement during
+ // the current (re-)collection iteration. Used to keep track of "bogus"
+ // (no longer relevant) entries.
+ //
+ bool replaced;
+
+ // Create replacement with the different version.
+ //
+ replaced_version (shared_ptr<available_package> a,
+ lazy_shared_ptr<bpkg::repository_fragment> f,
+ bool s)
+ : available (move (a)),
+ repository_fragment (move (f)),
+ system (s),
+ replaced (true) {}
+
+ // Create replacement with the drop.
+ //
+ replaced_version (): system (false), replaced (true) {}
+ };
+
+ class replaced_versions: public map<package_key, replaced_version>
+ {
+ public:
+ // Erase the bogus replacements and, if any, throw cancel_replacement, if
+ // requested.
+ //
+ struct cancel_replacement: scratch_collection
+ {
+ cancel_replacement ()
+ : scratch_collection ("bogus version replacement cancellation") {}
+ };
+
+ void
+ cancel_bogus (tracer& trace, bool scratch)
+ {
+ bool bogus (false);
+ for (auto i (begin ()); i != end (); )
+ {
+ const replaced_version& v (i->second);
+
+ if (!v.replaced)
+ {
+ bogus = true;
+
+ l5 ([&]{trace << "erase bogus version replacement "
+ << i->first;});
+
+ i = erase (i);
+ }
+ else
+ ++i;
+ }
+
+ if (bogus && scratch)
+ {
+ l5 ([&]{trace << "bogus version replacement erased, throwing";});
+ throw cancel_replacement ();
+ }
+ }
+ };
+
+ // List of dependency groups whose recursive processing should be postponed
+ // due to dependents with configuration clauses, together with these
+ // dependents (we will call them package clusters).
+ //
+ // The idea is that configuration for the dependencies in the cluster needs
+ // to be negotiated between the dependents in the cluster. Note that at any
+ // given time during collection a dependency can only belong to a single
+ // cluster. For example, the following dependent/dependencies with
+ // configuration clauses:
+ //
+ // foo: depends: libfoo
+ // bar: depends: libfoo
+ // depends: libbar
+ // baz: depends: libbaz
+ //
+ // End up in the following clusters (see string() below for the cluster
+ // representation):
+ //
+ // {foo bar | libfoo->{foo/1,1 bar/1,1}}
+ // {bar | libbar->{bar/2,1}}
+ // {baz | libbaz->{baz/1,1}}
+ //
+ // Or, another example:
+ //
+ // foo: depends: libfoo
+ // bar: depends: libfoo libbar
+ // baz: depends: libbaz
+ //
+ // {foo bar | libfoo->{foo/1,1 bar/1,1} libbar->{bar/1,1}}
+ // {baz | libbaz->{baz/1,1}}
+ //
+ // Note that a dependent can belong to any given non-negotiated cluster with
+ // only one `depends` position. However, if some dependency configuration is
+ // up-negotiated for a dependent, then multiple `depends` positions will
+ // correspond to this dependent in the same cluster. Naturally, such
+ // clusters are always (being) negotiated.
+ //
+ // Note that adding new dependent/dependencies to the postponed
+ // configurations can result in merging some of the existing clusters if the
+ // dependencies being added intersect with multiple clusters. For example,
+ // adding:
+ //
+ // fox: depends: libbar libbaz
+ //
+ // to the clusters in the second example will merge them into a single
+ // cluster:
+ //
+ // {foo bar baz fox | libfoo->{foo/1,1 bar/1,1} libbar->{bar/1,1 fox/1,1}
+ // libbaz->{baz/1,1 fox/1,1}}
+ //
+ // Also note that we keep track of packages which turn out to be
+ // dependencies of existing (configured) dependents with configuration
+ // clauses. The recursive processing of such packages should be postponed
+ // until negotiation between all the existing and new dependents which may
+ // or may not be present.
+ //
+ class postponed_configuration;
+
+ static ostream&
+ operator<< (ostream&, const postponed_configuration&);
+
+ class postponed_configuration
+ {
+ public:
+ // The id of the cluster plus the ids of all the clusters that have been
+ // merged into it.
+ //
+ size_t id;
+ small_vector<size_t, 1> merged_ids;
+
+ using packages = small_vector<package_key, 1>;
+
+ class dependency: public packages
+ {
+ public:
+ pair<size_t, size_t> position; // depends + alternative
+
+ dependency (const pair<size_t, size_t>& pos, packages deps)
+ : packages (move (deps)), position (pos) {}
+ };
+
+ class dependent_info
+ {
+ public:
+ bool existing;
+ small_vector<dependency, 1> dependencies;
+
+ dependency*
+ find_dependency (pair<size_t, size_t> pos)
+ {
+ auto i (find_if (dependencies.begin (),
+ dependencies.end (),
+ [&pos] (const dependency& d)
+ {
+ return d.position == pos;
+ }));
+ return i != dependencies.end () ? &*i : nullptr;
+ }
+
+ void
+ add (dependency&& dep)
+ {
+ if (dependency* d = find_dependency (dep.position))
+ {
+ // Feels like we can accumulate dependencies into an existing
+ // position only for an existing dependent.
+ //
+ assert (existing);
+
+ for (package_key& p: dep)
+ {
+ // Add the dependency unless it's already there.
+ //
+ if (find (d->begin (), d->end (), p) == d->end ())
+ d->push_back (move (p));
+ }
+ }
+ else
+ dependencies.push_back (move (dep));
+ }
+ };
+
+ using dependents_map = map<package_key, dependent_info>;
+
+ dependents_map dependents;
+ packages dependencies;
+
+ // Dependency configuration.
+ //
+ // Note that this container may not yet contain some entries that are
+ // already in the dependencies member above. And it may already contain
+ // entries that are not yet in dependencies due to the retry_configuration
+ // logic.
+ //
+ package_configurations dependency_configurations;
+
+ // Shadow clusters.
+ //
+ // See the collect lambda in collect_build_prerequisites() for details.
+ //
+ using positions = small_vector<pair<size_t, size_t>, 1>;
+ using shadow_dependents_map = map<package_key, positions>;
+
+ shadow_dependents_map shadow_cluster;
+
+ // Absent -- not negotiated yet, false -- being negotiated, true -- has
+ // been negotiated.
+ //
+ optional<bool> negotiated;
+
+ // The depth of the negotiating recursion (see collect_build_postponed()
+ // for details).
+ //
+ size_t depth = 0;
+
+ // Add dependencies of a new dependent.
+ //
+ postponed_configuration (size_t i,
+ package_key&& dependent,
+ bool existing,
+ pair<size_t, size_t> position,
+ packages&& deps)
+ : id (i)
+ {
+ add (move (dependent), existing, position, move (deps));
+ }
+
+ // Add dependency of an existing dependent.
+ //
+ postponed_configuration (size_t i,
+ package_key&& dependent,
+ pair<size_t, size_t> position,
+ package_key&& dep)
+ : id (i)
+ {
+ add (move (dependent),
+ true /* existing */,
+ position,
+ packages ({move (dep)}));
+ }
+
+ // Add dependencies of a dependent.
+ //
+ // Note: adds the specified dependencies to the end of the configuration
+ // dependencies list suppressing duplicates.
+ //
+ void
+ add (package_key&& dependent,
+ bool existing,
+ pair<size_t, size_t> position,
+ packages&& deps)
+ {
+ assert (position.first != 0 && position.second != 0);
+
+ add_dependencies (deps); // Don't move from since will be used later.
+
+ auto i (dependents.find (dependent));
+
+ if (i != dependents.end ())
+ {
+ dependent_info& ddi (i->second);
+
+ ddi.add (dependency (position, move (deps)));
+
+ // Conceptually, on the first glance, we can only move from existing
+ // to non-existing (e.g., due to a upgrade/downgrade later) and that
+ // case is handled via the version replacement rollback. However,
+ // after re-evaluation the existing dependent is handled similar to
+ // the new dependent and we can potentially up-negotiate the
+ // dependency configuration for it.
+ //
+ assert (ddi.existing || !existing);
+ }
+ else
+ {
+ small_vector<dependency, 1> ds ({dependency (position, move (deps))});
+
+ dependents.emplace (move (dependent),
+ dependent_info {existing, move (ds)});
+ }
+ }
+
+ // Return true if any of the configuration's dependents depend on the
+ // specified package.
+ //
+ bool
+ contains_dependency (const package_key& d) const
+ {
+ return find (dependencies.begin (), dependencies.end (), d) !=
+ dependencies.end ();
+ }
+
+ // Return true if this configuration contains any of the specified
+ // dependencies.
+ //
+ bool
+ contains_dependency (const packages& ds) const
+ {
+ for (const package_key& d: ds)
+ {
+ if (contains_dependency (d))
+ return true;
+ }
+
+ return false;
+ }
+
+ // Return true if this and specified configurations contain any common
+ // dependencies.
+ //
+ bool
+ contains_dependency (const postponed_configuration& c) const
+ {
+ for (const auto& d: c.dependencies)
+ {
+ if (contains_dependency (d))
+ return true;
+ }
+
+ return false;
+ }
+
+ // If the configuration contains the specified existing dependent, then
+ // return the earliest dependency position. Otherwise return NULL.
+ //
+ const pair<size_t, size_t>*
+ existing_dependent_position (const package_key& p) const
+ {
+ const pair<size_t, size_t>* r (nullptr);
+
+ auto i (dependents.find (p));
+ if (i != dependents.end () && i->second.existing)
+ {
+ for (const dependency& d: i->second.dependencies)
+ {
+ if (r == nullptr || d.position < *r)
+ r = &d.position;
+ }
+
+ assert (r != nullptr);
+ }
+
+ return r;
+ }
+
+ // Notes:
+ //
+ // - Adds dependencies of the being merged from configuration to the end
+ // of the current configuration dependencies list suppressing
+ // duplicates.
+ //
+ // - Doesn't change the negotiate member of this configuration.
+ //
+ void
+ merge (postponed_configuration&& c)
+ {
+ assert (c.id != id); // Can't merge to itself.
+
+ merged_ids.push_back (c.id);
+
+ // Merge dependents.
+ //
+ for (auto& d: c.dependents)
+ {
+ auto i (dependents.find (d.first));
+
+ if (i != dependents.end ())
+ {
+ dependent_info& ddi (i->second); // Destination dependent info.
+ dependent_info& sdi (d.second); // Source dependent info.
+
+ for (dependency& sd: sdi.dependencies)
+ ddi.add (move (sd));
+
+ // As in add() above.
+ //
+ assert (ddi.existing || !sdi.existing);
+ }
+ else
+ dependents.emplace (d.first, move (d.second));
+ }
+
+ // Merge dependencies.
+ //
+ add_dependencies (move (c.dependencies));
+
+ // Pick the depth of the outermost negotiated configuration (minimum
+ // non-zero depth) between the two.
+ //
+ if (depth != 0)
+ {
+ if (c.depth != 0 && depth > c.depth)
+ depth = c.depth;
+ }
+ else
+ depth = c.depth;
+ }
+
+ void
+ set_shadow_cluster (postponed_configuration&& c)
+ {
+ shadow_cluster.clear ();
+
+ for (auto& dt: c.dependents)
+ {
+ positions ps;
+ for (auto& d: dt.second.dependencies)
+ ps.push_back (d.position);
+
+ shadow_cluster.emplace (dt.first, move (ps));
+ }
+ }
+
+ bool
+ contains_in_shadow_cluster (package_key dependent,
+ pair<size_t, size_t> pos) const
+ {
+ auto i (shadow_cluster.find (dependent));
+
+ if (i != shadow_cluster.end ())
+ {
+ const positions& ps (i->second);
+ return find (ps.begin (), ps.end (), pos) != ps.end ();
+ }
+ else
+ return false;
+ }
+
+ // Return the postponed configuration string representation in the form:
+ //
+ // {<dependent>[ <dependent>]* | <dependency>[ <dependency>]*}['!'|'?']
+ //
+ // <dependent> = <package>['^']
+ // <dependency> = <package>->{<dependent>/<position>[ <dependent>/<position>]*}
+ //
+ // The potential trailing '!' or '?' of the configuration representation
+ // indicates that the configuration is negotiated or is being negotiated,
+ // respectively.
+ //
+ // '^' character that may follow a dependent indicates that this is an
+ // existing dependent.
+ //
+ // <position> = <depends-index>','<alternative-index>
+ //
+ // <depends-index> and <alternative-index> are the 1-based serial numbers
+ // of the respective depends value and the dependency alternative in the
+ // dependent's manifest.
+ //
+ // See package_key for details on <package>.
+ //
+ // For example:
+ //
+ // {foo^ bar | libfoo->{foo/2,3 bar/1,1} libbar->{bar/1,1}}!
+ //
+ std::string
+ string () const
+ {
+ std::string r;
+
+ for (const auto& d: dependents)
+ {
+ r += r.empty () ? '{' : ' ';
+ r += d.first.string ();
+
+ if (d.second.existing)
+ r += '^';
+ }
+
+ if (r.empty ())
+ r += '{';
+
+ r += " |";
+
+ for (const package_key& d: dependencies)
+ {
+ r += ' ';
+ r += d.string ();
+ r += "->{";
+
+ bool first (true);
+ for (const auto& dt: dependents)
+ {
+ for (const dependency& dp: dt.second.dependencies)
+ {
+ if (find (dp.begin (), dp.end (), d) != dp.end ())
+ {
+ if (!first)
+ r += ' ';
+ else
+ first = false;
+
+ r += dt.first.string ();
+ r += '/';
+ r += to_string (dp.position.first);
+ r += ',';
+ r += to_string (dp.position.second);
+ }
+ }
+ }
+
+ r += '}';
+ }
+
+ r += '}';
+
+ if (negotiated)
+ r += *negotiated ? '!' : '?';
+
+ return r;
+ }
+
+ private:
+ // Add the specified packages to the end of the dependencies list
+ // suppressing duplicates.
+ //
+ void
+ add_dependencies (packages&& deps)
+ {
+ for (auto& d: deps)
+ {
+ if (find (dependencies.begin (), dependencies.end (), d) ==
+ dependencies.end ())
+ dependencies.push_back (move (d));
+ }
+ }
+
+ void
+ add_dependencies (const packages& deps)
+ {
+ for (const auto& d: deps)
+ {
+ if (find (dependencies.begin (), dependencies.end (), d) ==
+ dependencies.end ())
+ dependencies.push_back (d);
+ }
+ }
+ };
+
+ static ostream&
+ operator<< (ostream& os, const postponed_configuration& c)
+ {
+ return os << c.string ();
+ }
+
+ // Note that we could be adding new/merging existing entries while
+ // processing an entry. Thus we use a list.
+ //
+ class postponed_configurations: public forward_list<postponed_configuration>
+ {
+ public:
+ // Return the configuration the dependent is added to (after all the
+ // potential configuration merges, etc).
+ //
+ // Also return in second absent if the merge happened due to the shadow
+ // cluster logic (in which case the cluster was/is being negotiated),
+ // false if any non-negotiated or being negotiated clusters has been
+ // merged in, and true otherwise.
+ //
+ // If some configurations needs to be merged and this involves the (being)
+ // negotiated configurations, then merge into the outermost-depth
+ // negotiated configuration (with minimum non-zero depth).
+ //
+ pair<postponed_configuration&, optional<bool>>
+ add (package_key dependent,
+ bool existing,
+ pair<size_t, size_t> position,
+ postponed_configuration::packages dependencies)
+ {
+ tracer trace ("postponed_configurations::add");
+
+ assert (!dependencies.empty ());
+
+ // The plan is to first go through the existing clusters and check if
+ // any of them contain this dependent/dependencies in their shadow
+ // clusters. If such a cluster is found, then force-add them to
+ // it. Otherwise, if any dependency-intersecting clusters are present,
+ // then add the specified dependent/dependencies to the one with the
+ // minimum non-zero depth, if any, and to the first one otherwise.
+ // Otherwise, add the new cluster. Afterwards, merge into the resulting
+ // cluster other dependency-intersecting clusters. Note that in case of
+ // shadow, this should normally not happen because such a cluster should
+ // have been either pre-merged or its dependents should be in the
+ // cluster. But it feels like it may still happen if things change, in
+ // which case we will throw again (admittedly a bit fuzzy).
+ //
+ iterator ri;
+ bool rb (true);
+
+ // Note that if a single dependency is added, then it can only belong to
+ // a single existing cluster and so no clusters merge can happen, unless
+ // we are force-adding. In the later case we can only merge once for a
+ // single dependency.
+ //
+ // Let's optimize for the common case based on these facts.
+ //
+ bool single (dependencies.size () == 1);
+
+ // Merge dependency-intersecting clusters in the specified range into
+ // the resulting cluster and reset change rb to false if any of the
+ // merged in clusters is non-negotiated or is being negotiated.
+ //
+ // The iterator arguments refer to entries before and after the range
+ // endpoints, respectively.
+ //
+ auto merge = [&trace, &ri, &rb, single, this] (iterator i,
+ iterator e,
+ bool shadow_based)
+ {
+ postponed_configuration& rc (*ri);
+
+ iterator j (i);
+
+ // Merge the intersecting configurations.
+ //
+ bool merged (false);
+ for (++i; i != e; ++i)
+ {
+ postponed_configuration& c (*i);
+
+ if (c.contains_dependency (rc))
+ {
+ if (!c.negotiated || !*c.negotiated)
+ rb = false;
+
+ l5 ([&]{trace << "merge " << c << " into " << rc;});
+
+ assert (!shadow_based || (c.negotiated && *c.negotiated));
+
+ rc.merge (move (c));
+ c.dependencies.clear (); // Mark as merged from (see above).
+
+ merged = true;
+
+ if (single)
+ break;
+ }
+ }
+
+ // Erase configurations which we have merged from.
+ //
+ if (merged)
+ {
+ i = j;
+
+ for (++i; i != e; )
+ {
+ if (!i->dependencies.empty ())
+ {
+ ++i;
+ ++j;
+ }
+ else
+ i = erase_after (j);
+ }
+ }
+ };
+
+ auto trace_add = [&trace, &dependent, existing, position, &dependencies]
+ (const postponed_configuration& c, bool shadow)
+ {
+ if (verb >= 5)
+ {
+ diag_record dr (trace);
+ dr << "add {" << dependent;
+
+ if (existing)
+ dr << '^';
+
+ dr << ' ' << position.first << ',' << position.second << ':';
+
+ for (const auto& d: dependencies)
+ dr << ' ' << d;
+
+ dr << "} to " << c;
+
+ if (shadow)
+ dr << " (shadow cluster-based)";
+ }
+ };
+
+ // Try to add based on the shadow cluster.
+ //
+ {
+ auto i (begin ());
+ for (; i != end (); ++i)
+ {
+ postponed_configuration& c (*i);
+
+ if (c.contains_in_shadow_cluster (dependent, position))
+ {
+ trace_add (c, true /* shadow */);
+
+ c.add (move (dependent), existing, position, move (dependencies));
+ break;
+ }
+ }
+
+ if (i != end ())
+ {
+ // Note that the cluster with a shadow cluster is by definition
+ // either being negotiated or has been negotiated. Actually, there
+ // is also a special case when we didn't negotiate the configuration
+ // yet and are in the process of re-evaluating existing dependents.
+ // Note though, that in this case we have already got the try/catch
+ // frame corresponding to the cluster negotiation (see
+ // collect_build_postponed() for details).
+ //
+ assert (i->depth != 0);
+
+ ri = i;
+
+ merge (before_begin (), ri, true /* shadow_based */);
+ merge (ri, end (), true /* shadow_based */);
+
+ return make_pair (ref (*ri), optional<bool> ());
+ }
+ }
+
+ // Find the cluster to add the dependent/dependencies to.
+ //
+ optional<size_t> depth;
+
+ auto j (before_begin ()); // Precedes iterator i.
+ for (auto i (begin ()); i != end (); ++i, ++j)
+ {
+ postponed_configuration& c (*i);
+
+ if (c.contains_dependency (dependencies) &&
+ (!depth || (c.depth != 0 && (*depth == 0 || *depth > c.depth))))
+ {
+ ri = i;
+ depth = c.depth;
+ }
+ }
+
+ if (!depth) // No intersecting cluster?
+ {
+ // New cluster. Insert after the last element.
+ //
+ ri = insert_after (j,
+ postponed_configuration (
+ next_id_++,
+ move (dependent),
+ existing,
+ position,
+ move (dependencies)));
+
+ l5 ([&]{trace << "create " << *ri;});
+ }
+ else
+ {
+ // Add the dependent/dependencies into an existing cluster.
+ //
+ postponed_configuration& c (*ri);
+
+ trace_add (c, false /* shadow */);
+
+ c.add (move (dependent), existing, position, move (dependencies));
+
+ // Try to merge other clusters into this cluster.
+ //
+ merge (before_begin (), ri, false /* shadow_based */);
+ merge (ri, end (), false /* shadow_based */);
+ }
+
+ return make_pair (ref (*ri), optional<bool> (rb));
+ }
+
+ // Add new postponed configuration cluster with a single dependency of an
+ // existing dependent.
+ //
+ // Note that it's the caller's responsibility to make sure that the
+ // dependency doesn't already belong to any existing cluster.
+ //
+ void
+ add (package_key dependent,
+ pair<size_t, size_t> position,
+ package_key dependency)
+ {
+ tracer trace ("postponed_configurations::add");
+
+ // Add the new cluster to the end of the list which we can only find by
+ // traversing the list. While at it, make sure that the dependency
+ // doesn't belong to any existing cluster.
+ //
+ auto i (before_begin ()); // Insert after this element.
+
+ for (auto j (begin ()); j != end (); ++i, ++j)
+ assert (!j->contains_dependency (dependency));
+
+ i = insert_after (i,
+ postponed_configuration (next_id_++,
+ move (dependent),
+ position,
+ move (dependency)));
+
+ l5 ([&]{trace << "create " << *i;});
+ }
+
+ postponed_configuration*
+ find (size_t id)
+ {
+ for (postponed_configuration& cfg: *this)
+ {
+ if (cfg.id == id)
+ return &cfg;
+ }
+
+ return nullptr;
+ }
+
+ // Return address of the cluster the dependency belongs to and NULL if it
+ // doesn't belong to any cluster.
+ //
+ const postponed_configuration*
+ find_dependency (const package_key& d) const
+ {
+ for (const postponed_configuration& cfg: *this)
+ {
+ if (cfg.contains_dependency (d))
+ return &cfg;
+ }
+
+ return nullptr;
+ }
+
+ // Return true if all the configurations have been negotiated.
+ //
+ bool
+ negotiated () const
+ {
+ for (const postponed_configuration& cfg: *this)
+ {
+ if (!cfg.negotiated || !*cfg.negotiated)
+ return false;
+ }
+
+ return true;
+ }
+
+ // Translate index to iterator and return the referenced configuration.
+ //
+ postponed_configuration&
+ operator[] (size_t index)
+ {
+ auto i (begin ());
+ for (size_t j (0); j != index; ++j, ++i) assert (i != end ());
+
+ assert (i != end ());
+ return *i;
+ }
+
+ size_t
+ size () const
+ {
+ size_t r (0);
+ for (auto i (begin ()); i != end (); ++i, ++r) ;
+ return r;
+ }
+
+ private:
+ size_t next_id_ = 1;
+ };
+
+ // The following exceptions are used by the dependency configuration
+ // up-negotiation/refinement machinery. See the collect lambda in
+ // collect_build_prerequisites() for details.
+ //
+ struct retry_configuration
+ {
+ size_t depth;
+ package_key dependent;
+ };
+
+ struct merge_configuration
+ {
+ size_t depth;
+ };
+
+ // Packages with postponed prerequisites collection, for one of the
+ // following reasons:
+ //
+ // - Postponed due to the inability to find a version satisfying the pre-
+ // entered constraint from repositories available to this package. The
+ // idea is that this constraint could still be satisfied from a repository
+ // fragment of some other package (that we haven't processed yet) that
+ // also depends on this prerequisite.
+ //
+ // - Postponed due to the inability to choose between two dependency
+ // alternatives, both having dependency packages which are not yet
+ // selected in the configuration nor being built. The idea is that this
+ // ambiguity could still be resolved after some of those dependency
+ // packages get built via some other dependents.
+ //
+ using postponed_packages = set<build_package*>;
+
+ // Map of dependency packages whose recursive processing should be postponed
+ // because they have dependents with configuration clauses.
+ //
+ // Note that dependents of such a package that don't have any configuration
+ // clauses are processed right away (since the negotiated configuration may
+ // not affect them) while those that do are postponed in the same way as
+ // those with dependency alternatives (see above).
+ //
+ // Note that the latter kind of dependent is what eventually causes
+ // recursive processing of the dependency packages. Which means we must
+ // watch out for bogus entries in this map which we may still end up with
+ // (e.g., because postponement caused cross-talk between dependency
+ // alternatives). Thus we keep flags that indicate whether we have seen each
+ // type of dependent and then just process dependencies that have the first
+ // (without config) but not the second (with config). We also need to track
+ // at which phase of collection an entry has been added to process the bogus
+ // entries accordingly.
+ //
+ struct postponed_dependency
+ {
+ bool wout_config; // Has dependent without config.
+ bool with_config; // Has dependent with config.
+ bool initial_collection;
+
+ postponed_dependency (bool woc, bool wic, bool ic)
+ : wout_config (woc),
+ with_config (wic),
+ initial_collection (ic) {}
+
+ bool
+ bogus () const {return wout_config && !with_config;}
+ };
+
+ class postponed_dependencies: public map<package_key, postponed_dependency>
+ {
+ public:
+ bool
+ has_bogus () const
+ {
+ for (const auto& pd: *this)
+ {
+ if (pd.second.bogus ())
+ return true;
+ }
+ return false;
+ }
+
+ // Erase the bogus postponements and throw cancel_postponement, if any.
+ //
+ struct cancel_postponement: scratch_collection
+ {
+ cancel_postponement ()
+ : scratch_collection (
+ "bogus dependency collection postponement cancellation") {}
+ };
+
+ void
+ cancel_bogus (tracer& trace, bool initial_collection)
+ {
+ bool bogus (false);
+ for (auto i (begin ()); i != end (); )
+ {
+ const postponed_dependency& d (i->second);
+
+ if (d.bogus () && (!initial_collection || d.initial_collection))
+ {
+ bogus = true;
+
+ l5 ([&]{trace << "erase bogus postponement " << i->first;});
+
+ i = erase (i);
+ }
+ else
+ ++i;
+ }
+
+ if (bogus)
+ {
+ l5 ([&]{trace << "bogus postponements erased, throwing";});
+ throw cancel_postponement ();
+ }
+ }
+ };
+
+ // Map of existing dependents which may not be re-evaluated to a position
+ // with the dependency index greater than the specified one.
+ //
+ // This mechanism applies when we re-evaluate an existing dependent to a
+ // certain position but later realize we've gone too far. In this case we
+ // note the earlier position information and re-collect from scratch. On the
+ // re-collection any re-evaluation of the dependent to a greater position
+ // will be either skipped or performed but to this earlier position (see the
+ // replace member for details).
+ //
+ // We consider the postponement bogus if some dependent re-evaluation was
+ // skipped due to its presence but no re-evaluation to this (or earlier)
+ // dependency index was performed. Thus, if after the collection of packages
+ // some bogus entries are present in the map, then it means that we have
+ // skipped the respective re-evaluations erroneously and so need to erase
+ // these entries and re-collect.
+ //
+ // Note that if no re-evaluation is skipped due to a postponement then it
+ // is harmless and we don't consider it bogus.
+ //
+ struct postponed_position: pair<size_t, size_t>
{
- // Packages with postponed prerequisites collection, for one of the
- // following reasons:
+ // True if the "later" position should be replaced rather than merely
+ // skipped. The replacement deals with the case where the "earlier"
+ // position is encountered while processing the same cluster as what
+ // contains the later position. In this case, if we merely skip, then we
+ // will never naturally encounter the earlier position. So we have to
+ // force the issue (even if things change enough for us to never see the
+ // later position again).
//
- // - Postponed due to the inability to find a version satisfying the pre-
- // entered constraint from repositories available to this package. The
- // idea is that this constraint could still be satisfied from a
- // repository fragment of some other package (that we haven't processed
- // yet) that also depends on this prerequisite.
+ bool replace;
+
+ // Re-evaluation was skipped due to this postponement.
//
- // - Postponed due to the inability to choose between two dependency
- // alternatives, both having dependency packages which are not yet
- // selected in the configuration nor being built. The idea is that this
- // ambiguity could still be resolved after some of those dependency
- // packages get built via some other dependents.
+ bool skipped = false;
+
+ // The dependent was re-evaluated. Note that it can be only re-evaluated
+ // to this or earlier dependency index.
+ //
+ bool reevaluated = false;
+
+ postponed_position (pair<size_t, size_t> p, bool r)
+ : pair<size_t, size_t> (p), replace (r) {}
+ };
+
+ class postponed_positions: public map<package_key, postponed_position>
+ {
+ public:
+ // If true, override the first encountered non-replace position to replace
+ // and clear this flag. See collect_build_postponed() for details.
+ //
+ bool replace = false;
+
+ // Erase the bogus postponements and throw cancel_postponement, if any.
+ //
+ struct cancel_postponement: scratch_collection
+ {
+ cancel_postponement ()
+ : scratch_collection ("bogus existing dependent re-evaluation "
+ "postponement cancellation") {}
+ };
+
+ void
+ cancel_bogus (tracer& trace)
+ {
+ bool bogus (false);
+ for (auto i (begin ()); i != end (); )
+ {
+ const postponed_position& p (i->second);
+
+ if (p.skipped && !p.reevaluated)
+ {
+ bogus = true;
+
+ l5 ([&]{trace << "erase bogus existing dependent " << i->first
+ << " re-evaluation postponement with dependency index "
+ << i->second.first;});
+
+ // It seems that the replacement may never be bogus.
+ //
+ assert (!p.replace);
+
+ i = erase (i);
+ }
+ else
+ ++i;
+ }
+
+ if (bogus)
+ {
+ l5 ([&]{trace << "bogus re-evaluation postponement erased, throwing";});
+ throw cancel_postponement ();
+ }
+ }
+ };
+
+ struct build_packages: build_package_list
+ {
+ build_packages () = default;
+
+ // Copy-constructible and move-assignable (used for snapshoting).
//
- using postponed_packages = set<build_package*>;
+ build_packages (const build_packages& v)
+ : build_package_list ()
+ {
+ // Copy the map.
+ //
+ for (const auto& p: v.map_)
+ map_.emplace (p.first, data_type {end (), p.second.package});
+
+ // Copy the list.
+ //
+ for (const auto& p: v)
+ {
+ auto i (map_.find (p.get ().db, p.get ().name ()));
+ assert (i != map_.end ());
+ i->second.position = insert (end (), i->second.package);
+ }
+ }
+
+ build_packages (build_packages&&) = delete;
+
+ build_packages& operator= (const build_packages&) = delete;
+
+ build_packages&
+ operator= (build_packages&& v)
+ {
+ clear ();
+
+ // Move the map.
+ //
+ // Similar to what we do in the copy-constructor, but here we also need
+ // to restore the database reference and the package shared pointers in
+ // the source entry after the move. This way we can obtain the source
+ // packages databases and names later while copying the list.
+ //
+ for (auto& p: v.map_)
+ {
+ build_package& bp (p.second.package);
+
+ database& db (bp.db);
+ shared_ptr<selected_package> sp (bp.selected);
+ shared_ptr<available_package> ap (bp.available);
+
+ map_.emplace (p.first, data_type {end (), move (bp)});
+
+ bp.db = db;
+ bp.selected = move (sp);
+ bp.available = move (ap);
+ }
+
+ // Copy the list.
+ //
+ for (const auto& p: v)
+ {
+ auto i (map_.find (p.get ().db, p.get ().name ()));
+ assert (i != map_.end ());
+ i->second.position = insert (end (), i->second.package);
+ }
+
+ return *this;
+ }
// Pre-enter a build_package without an action. No entry for this package
// may already exists.
@@ -982,23 +2326,46 @@ namespace bpkg
assert (!pkg.action);
database& db (pkg.db); // Save before the move() call.
- auto p (map_.emplace (config_package {db, move (name)},
+ auto p (map_.emplace (package_key {db, move (name)},
data_type {end (), move (pkg)}));
assert (p.second);
}
- // Return true if a package is already in the map.
+ // Return the package pointer if it is already in the map and NULL
+ // otherwise (so can be used as bool).
//
- bool
- entered (database& db, const package_name& name)
+ build_package*
+ entered_build (database& db, const package_name& name)
{
- return map_.find (db, name) != map_.end ();
+ auto i (map_.find (db, name));
+ return i != map_.end () ? &i->second.package : nullptr;
+ }
+
+ build_package*
+ entered_build (const package_key& p)
+ {
+ return entered_build (p.db, p.name);
}
// Collect the package being built. Return its pointer if this package
// version was, in fact, added to the map and NULL if it was already there
- // or the existing version was preferred. So can be used as bool.
+ // and the existing version was preferred or if the package build has been
+ // replaced with the drop. So can be used as bool.
+ //
+ // Consult replaced_vers for an existing version replacement entry and
+ // follow it, if present, potentially collecting the package drop
+ // instead. Add entry to replaced_vers and throw replace_version if the
+ // existing version needs to be replaced but the new version cannot be
+ // re-collected recursively in-place (see replaced_versions for details).
+ // Also add an entry and throw if the existing dependent needs to be
+ // replaced.
+ //
+ // Optionally, pass the function which verifies the chosen package
+ // version. It is called before replace_version is potentially thrown or
+ // the recursive collection is performed. The scratch argument is true if
+ // the package version needs to be replaced but in-place replacement is
+ // not possible (see replaced_versions for details).
//
// Also, in the recursive mode (dep_chain is not NULL):
//
@@ -1015,54 +2382,132 @@ namespace bpkg
// Note that postponed_* and dep_chain arguments must all be either
// specified or not.
//
+ struct replace_version: scratch_collection
+ {
+ replace_version ()
+ : scratch_collection ("package version replacement") {}
+ };
+
+ using verify_package_build_function = void (const build_package&,
+ bool scratch);
+
build_package*
collect_build (const pkg_build_options& options,
build_package pkg,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
const function<add_priv_cfg_function>& apc,
+ bool initial_collection,
+ replaced_versions& replaced_vers,
+ postponed_configurations& postponed_cfgs,
+ build_package_refs* dep_chain = nullptr,
postponed_packages* postponed_repo = nullptr,
postponed_packages* postponed_alts = nullptr,
- build_package_refs* dep_chain = nullptr)
+ postponed_dependencies* postponed_deps = nullptr,
+ postponed_positions* postponed_poss = nullptr,
+ const function<verify_package_build_function>& vpb = nullptr)
{
using std::swap; // ...and not list::swap().
tracer trace ("collect_build");
- // Must all be either specified or not.
+ // See the above notes.
//
- assert ((dep_chain == nullptr) == (postponed_repo == nullptr));
- assert ((postponed_repo == nullptr) == (postponed_alts == nullptr));
+ bool recursive (dep_chain != nullptr);
+ assert ((postponed_repo != nullptr) == recursive &&
+ (postponed_alts != nullptr) == recursive &&
+ (postponed_deps != nullptr) == recursive &&
+ (postponed_poss != nullptr) == recursive);
// Only builds are allowed here.
//
assert (pkg.action && *pkg.action == build_package::build &&
pkg.available != nullptr);
- auto i (map_.find (pkg.db, pkg.available->id.name));
+ package_key pk (pkg.db, pkg.available->id.name);
+
+ // Apply the version replacement, if requested, and indicate that it was
+ // applied.
+ //
+ auto vi (replaced_vers.find (pk));
+
+ if (vi != replaced_vers.end () && !vi->second.replaced)
+ {
+ l5 ([&]{trace << "apply version replacement for "
+ << pkg.available_name_version_db ();});
+
+ replaced_version& v (vi->second);
+
+ v.replaced = true;
+
+ if (v.available != nullptr)
+ {
+ pkg.available = v.available;
+ pkg.repository_fragment = v.repository_fragment;
+ pkg.system = v.system;
+
+ l5 ([&]{trace << "replacement: "
+ << pkg.available_name_version_db ();});
+ }
+ else
+ {
+ l5 ([&]{trace << "replacement: drop";});
+
+ assert (pkg.selected != nullptr);
- // If we already have an entry for this package name, then we
- // have to pick one over the other.
+ collect_drop (options, pkg.db, pkg.selected, replaced_vers);
+ return nullptr;
+ }
+ }
+
+ // Add the version replacement entry, call the verification function if
+ // specified, and throw replace_version.
//
- // If the existing entry is a pre-entered or is non-build one, then we
- // merge it into the new build entry. Otherwise (both are builds), we
- // pick one and merge the other into it.
+ auto replace_ver = [&pk, &vpb, &vi, &replaced_vers]
+ (const build_package& p)
+ {
+ replaced_version rv (p.available, p.repository_fragment, p.system);
+
+ if (vi != replaced_vers.end ())
+ vi->second = move (rv);
+ else
+ replaced_vers.emplace (move (pk), move (rv));
+
+ if (vpb)
+ vpb (p, true /* scratch */);
+
+ throw replace_version ();
+ };
+
+ auto i (map_.find (pk));
+
+ // If we already have an entry for this package name, then we have to
+ // pick one over the other.
+ //
+ // If the existing entry is a drop, then we override it. If the existing
+ // entry is a pre-entered or is non-build one, then we merge it into the
+ // new build entry. Otherwise (both are builds), we pick one and merge
+ // the other into it.
//
if (i != map_.end ())
{
build_package& bp (i->second.package);
- // Can't think of the scenario when this happens. We would start
- // collecting from scratch (see below).
+ // Note that we used to think that the scenario when the build could
+ // replace drop could never happen since we would start collecting
+ // from scratch. This has changed when we introduced replaced_versions
+ // for collecting drops.
//
- assert (!bp.action || *bp.action != build_package::drop);
-
- if (!bp.action || *bp.action != build_package::build) // Non-build.
+ if (bp.action && *bp.action == build_package::drop) // Drop.
+ {
+ bp = move (pkg);
+ }
+ else if (!bp.action || *bp.action != build_package::build) // Non-build.
{
pkg.merge (move (bp));
bp = move (pkg);
}
- else // Build.
+ else // Build.
{
// At the end we want p1 to point to the object that we keep
// and p2 to the object that we merge from.
@@ -1140,10 +2585,9 @@ namespace bpkg
<< " over " << p2->available_name_version_db ();});
}
- // See if we are replacing the object. If not, then we don't
- // need to collect its prerequisites since that should have
- // already been done. Remember, p1 points to the object we
- // want to keep.
+ // See if we are replacing the object. If not, then we don't need to
+ // collect its prerequisites since that should have already been
+ // done. Remember, p1 points to the object we want to keep.
//
bool replace (p1 != &i->second.package);
@@ -1155,26 +2599,99 @@ namespace bpkg
p1->merge (move (*p2));
- if (!replace)
+ if (replace)
+ {
+ if (p1->available_version () != p2->available_version () ||
+ p1->system != p2->system)
+ {
+ // See if in-place replacement is possible (no dependencies,
+ // etc) and set scratch to false if that's the case.
+ //
+ // Firstly, such a package should not participate in any
+ // configuration negotiation.
+ //
+ // Other than that, it looks like the only optimization we can
+ // do easily is if the package has no dependencies (and thus
+ // cannot impose any constraints). Anything more advanced would
+ // require analyzing our dependencies (which we currently cannot
+ // easily get) and (1) either dropping the dependency
+ // build_package altogether if we are the only dependent (so
+ // that it doesn't influence any subsequent dependent) or (2)
+ // making sure our constraint is a sub-constraint of any other
+ // constraint and removing it from the dependency build_package.
+ // Maybe/later.
+ //
+ // NOTE: remember to update collect_drop() if changing anything
+ // here.
+ //
+ bool scratch (true);
+
+ // While checking if the package has any dependencies skip the
+ // toolchain build-time dependencies since they should be quite
+ // common.
+ //
+ if (!has_dependencies (options, p2->available->dependencies))
+ scratch = false;
+
+ l5 ([&]{trace << p2->available_name_version_db ()
+ << " package version needs to be replaced "
+ << (!scratch ? "in-place " : "") << "with "
+ << p1->available_name_version_db ();});
+
+ if (scratch)
+ replace_ver (*p1);
+ }
+ else
+ {
+ // It doesn't seem possible that replacing the build object
+ // without changing the package version may result in changing
+ // the package configuration since the configuration always gets
+ // into the initial package build entry (potentially
+ // pre-entered, etc). If it wouldn't be true then we would also
+ // need to add the replacement version entry and re-collect from
+ // scratch.
+ }
+ }
+ else
return nullptr;
}
}
else
{
+ // Treat the replacement of the existing dependent that is
+ // participating in the configuration negotiation also as a version
+ // replacement. This way we will not be treating the dependent as an
+ // existing on the re-collection (see query_existing_dependents() for
+ // details).
+ //
+ // Note: an existing dependent may not be configured as system.
+ //
+ if (pkg.selected != nullptr &&
+ (pkg.selected->version != pkg.available_version () ||
+ pkg.system))
+ {
+
+ for (const postponed_configuration& cfg: postponed_cfgs)
+ {
+ auto i (cfg.dependents.find (pk));
+
+ if (i != cfg.dependents.end () && i->second.existing)
+ replace_ver (pkg);
+ }
+ }
+
// This is the first time we are adding this package name to the map.
//
l4 ([&]{trace << "add " << pkg.available_name_version_db ();});
- // Note: copy; see emplace() below.
- //
- database& db (pkg.db); // Save before the move() call.
- package_name n (pkg.available->id.name);
- i = map_.emplace (config_package {db, move (n)},
- data_type {end (), move (pkg)}).first;
+ i = map_.emplace (move (pk), data_type {end (), move (pkg)}).first;
}
build_package& p (i->second.package);
+ if (vpb)
+ vpb (p, false /* scratch */);
+
// Recursively collect build prerequisites, if requested.
//
// Note that detecting dependency cycles during the satisfaction phase
@@ -1195,16 +2712,21 @@ namespace bpkg
// replaced once. So let's wait until some real use case proves this
// reasoning wrong.
//
- if (dep_chain != nullptr)
+ if (recursive)
collect_build_prerequisites (options,
p,
fdb,
rpt_depts,
apc,
+ initial_collection,
+ replaced_vers,
+ *dep_chain,
postponed_repo,
postponed_alts,
0 /* max_alt_index */,
- *dep_chain);
+ *postponed_deps,
+ postponed_cfgs,
+ *postponed_poss);
return &p;
}
@@ -1232,6 +2754,9 @@ namespace bpkg
// and, potentially, for its reconfigured existing prerequisites,
// recursively.
//
+ // - For an existing dependent being re-evaluated to the specific
+ // dependency position.
+ //
// Note that for these cases, as it was said above, we can potentially
// fail if the dependent is an orphan, but this is exactly what we need to
// do in that case, since we won't be able to re-collect its dependencies.
@@ -1249,64 +2774,333 @@ namespace bpkg
// with the lower indexes first (see collect_build_postponed() for
// details).
//
+ // Always postpone recursive collection of dependencies for a dependent
+ // with configuration clauses, recording them in postponed_deps (see
+ // postponed_dependencies for details) and also recording the dependent in
+ // postponed_cfgs (see postponed_configurations for details). If it turns
+ // out that some dependency of such a dependent has already been collected
+ // via some other dependent without configuration clauses, then throw the
+ // postpone_dependency exception. This exception is handled via
+ // re-collecting packages from scratch, but now with the knowledge about
+ // premature dependency collection. If it turns out that some dependency
+ // configuration has already been negotiated between some other
+ // dependents, then up-negotiate the configuration and throw
+ // retry_configuration exception so that the configuration refinement can
+ // be performed (see the collect lambda implementation for details on the
+ // configuration refinement machinery).
+ //
+ // If the package is a dependency of a configured dependent with
+ // configuration clause and needs to be reconfigured (being upgraded, has
+ // configuration specified, etc), then postpone its recursive collection
+ // by recording it in postponed_cfgs as a single-dependency cluster with
+ // an existing dependent (see postponed_configurations for details). If
+ // this dependent already belongs to some (being) negotiated configuration
+ // cluster with a greater dependency position then record this dependency
+ // position in postponed_poss and throw postpone_position. This exception
+ // is handled by re-collecting packages from scratch, but now with the
+ // knowledge about position this dependent needs to be re-evaluated to.
+ //
+ struct postpone_dependency: scratch_collection
+ {
+ package_key package;
+
+ explicit
+ postpone_dependency (package_key p)
+ : scratch_collection ("prematurely collected dependency"),
+ package (move (p))
+ {
+ scratch_collection::package = &package;
+ }
+ };
+
+ struct postpone_position: scratch_collection
+ {
+ postpone_position ()
+ : scratch_collection ("earlier dependency position") {}
+ };
+
void
collect_build_prerequisites (const pkg_build_options& options,
build_package& pkg,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
const function<add_priv_cfg_function>& apc,
+ bool initial_collection,
+ replaced_versions& replaced_vers,
+ build_package_refs& dep_chain,
postponed_packages* postponed_repo,
postponed_packages* postponed_alts,
size_t max_alt_index,
- build_package_refs& dep_chain)
+ postponed_dependencies& postponed_deps,
+ postponed_configurations& postponed_cfgs,
+ postponed_positions& postponed_poss,
+ pair<size_t, size_t> reeval_pos =
+ make_pair(0, 0))
{
+ // NOTE: don't forget to update collect_build_postponed() if changing
+ // anything in this function.
+ //
tracer trace ("collect_build_prerequisites");
assert (pkg.action && *pkg.action == build_package::build);
+ const package_name& nm (pkg.name ());
+ database& pdb (pkg.db);
+ package_key pk (pdb, nm);
+
+ bool reeval (reeval_pos.first != 0);
+
+ // The being re-evaluated dependent cannot be recursively collected yet.
+ // Also, we don't expect it being configured as system.
+ //
+ // Note that the configured package can still be re-evaluated after
+ // collect_build_prerequisites() has been called but didn't end up with
+ // the recursive collection.
+ //
+ assert (!reeval ||
+ ((!pkg.recursive_collection ||
+ !pkg.recollect_recursively (rpt_depts)) &&
+ !pkg.skeleton && !pkg.system));
+
+ // If this package is not being re-evaluated, is not yet collected
+ // recursively, needs to be reconfigured, and is not yet postponed, then
+ // check if it is a dependency of any dependent with configuration
+ // clause and postpone the collection if that's the case.
+ //
+ // The reason why we don't need to do this for the re-evaluated case is
+ // as follows: this logic is used for an existing dependent that is not
+ // otherwise built (e.g., reconfigured) which means its externally-
+ // imposed configuration (user, dependents) is not being changed.
+ //
+ if (!reeval &&
+ !pkg.recursive_collection &&
+ pkg.reconfigure () &&
+ postponed_cfgs.find_dependency (pk) == nullptr)
+ {
+ // If the dependent is being built, then check if it was re-evaluated
+ // to the position greater than the dependency position. Return true
+ // if that's the case, so this package is added to the resulting list
+ // and we can handle this situation below.
+ //
+ // Note that we rely on "small function object" optimization here.
+ //
+ const function<verify_dependent_build_function> verify (
+ [&postponed_cfgs]
+ (const package_key& pk, pair<size_t, size_t> pos)
+ {
+ for (const postponed_configuration& cfg: postponed_cfgs)
+ {
+ if (cfg.negotiated)
+ {
+ if (const pair<size_t, size_t>* p =
+ cfg.existing_dependent_position (pk))
+ {
+ if (p->first > pos.first)
+ return true;
+ }
+ }
+ }
+
+ return false;
+ });
+
+ // Note that there can be multiple existing dependents for a
+ // dependency. Strictly speaking, we only need to add the first one
+ // with the assumption that the remaining dependents will also be
+ // considered comes the time for the negotiation. Let's, however,
+ // process all of them to detect the potential "re-evaluation on the
+ // greater dependency index" situation earlier. And, generally, have
+ // as much information as possible up front.
+ //
+ vector<existing_dependent> eds (
+ query_existing_dependents (trace,
+ pk.db,
+ pk.name,
+ replaced_vers,
+ rpt_depts,
+ verify));
+
+ if (!eds.empty ())
+ {
+ for (existing_dependent& ed: eds)
+ {
+ package_key dpk (ed.db, ed.selected->name);
+ size_t& di (ed.dependency_position.first);
+
+ const build_package* bp (&pkg);
+
+ // Check if this dependent needs to be re-evaluated to an earlier
+ // dependency position and, if that's the case, create the
+ // configuration cluster with this dependency instead.
+ //
+ // Note that if the replace flag is false, we proceed normally
+ // with the assumption that the dependency referred by the entry
+ // will be collected later and its configuration cluster will be
+ // created normally and will be negotiated earlier than the
+ // cluster being created for the current dependency (see
+ // collect_build_postponed() for details).
+ //
+ {
+ auto pi (postponed_poss.find (dpk));
+
+ if (pi != postponed_poss.end () && pi->second.first < di)
+ {
+ // If requested, override the first encountered non-replace
+ // position to replace. See collect_build_postponed () for
+ // details.
+ //
+ if (!pi->second.replace && postponed_poss.replace)
+ {
+ pi->second.replace = true;
+ postponed_poss.replace = false;
+ }
+
+ if (pi->second.replace)
+ {
+ // Overwrite the existing dependent dependency information
+ // and fall through to proceed as for the normal case.
+ //
+ bp = replace_existing_dependent_dependency (
+ trace,
+ options,
+ ed, // Note: modified.
+ pi->second,
+ fdb,
+ rpt_depts,
+ apc,
+ initial_collection,
+ replaced_vers,
+ postponed_cfgs);
+
+ pk = package_key (bp->db, bp->name ());
+
+ // Note that here we side-step the bogus logic (by not
+ // setting the skipped flag) because in this case
+ // (replace=true) our choices are either (potentially) bogus
+ // or pathological (where we have evaluated too far). In
+ // other words, the postponed entry may cause the depends
+ // entry that triggered it to disappear (and thus, strictly
+ // speaking, to become bogus) but if we cancel it, we will
+ // be back to square one.
+ }
+ }
+ }
+
+ // Make sure that this existing dependent doesn't belong to any
+ // (being) negotiated configuration cluster with a greater
+ // dependency index. That would mean that this dependent has
+ // already been re-evaluated to this index and so cannot
+ // participate in the configuration negotiation of this earlier
+ // dependency.
+ //
+ for (const postponed_configuration& cfg: postponed_cfgs)
+ {
+ if (const pair<size_t, size_t>* p =
+ cfg.existing_dependent_position (pk))
+ {
+ size_t ei (p->first);
+
+ if (di < ei && cfg.negotiated)
+ {
+ // Feels like there cannot be an earlier position.
+ //
+ postponed_position pp (ed.dependency_position,
+ false /* replace */);
+
+ auto p (postponed_poss.emplace (move (pk), pp));
+ if (!p.second)
+ {
+ assert (p.first->second > pp);
+ p.first->second = pp;
+ }
+
+ l5 ([&]{trace << "cannot cfg-postpone dependency "
+ << bp->available_name_version_db ()
+ << " of existing dependent " << *ed.selected
+ << ed.db << " (index " << di
+ << ") due to earlier dependency index " << ei
+ << " in " << cfg << ", throwing "
+ << "postpone_position";});
+
+ // Don't print the "while satisfying..." chain.
+ //
+ dep_chain.clear ();
+
+ throw postpone_position ();
+ }
+
+ if (di == ei)
+ {
+ // For the negotiated cluster all the dependency packages
+ // should have been added. For non-negotiated cluster we
+ // cannot add the missing dependencies at the moment and
+ // will do it as a part of the dependent re-evaluation.
+ //
+ assert (!cfg.negotiated);
+ }
+ }
+ }
+
+ l5 ([&]{trace << "cfg-postpone dependency "
+ << bp->available_name_version_db ()
+ << " of existing dependent " << *ed.selected
+ << ed.db;});
+
+ postponed_cfgs.add (move (dpk), ed.dependency_position, move (pk));
+ }
+
+ return;
+ }
+ }
+
+ pkg.recursive_collection = true;
+
if (pkg.system)
+ {
+ l5 ([&]{trace << "skip system " << pkg.available_name_version_db ();});
return;
+ }
const shared_ptr<available_package>& ap (pkg.available);
+ assert (ap != nullptr);
+
const shared_ptr<selected_package>& sp (pkg.selected);
- database& pdb (pkg.db);
// True if this is an up/down-grade.
//
- bool ud (false);
+ bool ud (sp != nullptr && sp->version != pkg.available_version ());
// If this is a repointed dependent, then it points to its prerequisite
// replacements flag map (see repointed_dependents for details).
//
- const map<config_package, bool>* rpt_prereq_flags (nullptr);
+ const map<package_key, bool>* rpt_prereq_flags (nullptr);
- assert (ap != nullptr);
-
- // Bail out if this is a configured non-system package and no
- // up/down-grade nor collecting prerequisite replacements are required.
- //
- // NOTE: remember to update the check condition in
- // collect_order_dependents() if changing anything here.
+ // Bail out if this is a configured non-system package and no recursive
+ // collection is required.
//
bool src_conf (sp != nullptr &&
sp->state == package_state::configured &&
sp->substate != package_substate::system);
+ // The being re-evaluated dependent must be configured as a source
+ // package and should not be collected recursively (due to upgrade,
+ // etc).
+ //
+ assert (!reeval || (src_conf && !pkg.recollect_recursively (rpt_depts)));
+
if (src_conf)
{
- ud = sp->version != pkg.available_version ();
-
- repointed_dependents::const_iterator i (
- rpt_depts.find (config_package {pdb, sp->name}));
+ repointed_dependents::const_iterator i (rpt_depts.find (pk));
if (i != rpt_depts.end ())
rpt_prereq_flags = &i->second;
- if (!ud &&
- rpt_prereq_flags == nullptr &&
- (pkg.config_vars.empty () ||
- !has_buildfile_clause (ap->dependencies)))
+ if (!reeval && !pkg.recollect_recursively (rpt_depts))
+ {
+ l5 ([&]{trace << "skip configured "
+ << pkg.available_name_version_db ();});
return;
+ }
}
// Iterate over dependencies, trying to unambiguously select a
@@ -1315,9 +3109,13 @@ namespace bpkg
//
const dependencies& deps (ap->dependencies);
- // Must both be either present or not.
+ // The skeleton can be pre-initialized before the recursive collection
+ // starts (as a part of dependency configuration negotiation, etc). The
+ // dependencies and alternatives members must both be either present or
+ // not.
//
- assert (pkg.dependencies.has_value () == pkg.skeleton.has_value ());
+ assert ((!pkg.dependencies || pkg.skeleton) &&
+ pkg.dependencies.has_value () == pkg.alternatives.has_value ());
// Note that the selected alternatives list can be filled partially (see
// build_package::dependencies for details). In this case we continue
@@ -1325,32 +3123,36 @@ namespace bpkg
//
if (!pkg.dependencies)
{
+ l5 ([&]{trace << (reeval ? "reeval " : "begin ")
+ << pkg.available_name_version_db ();});
+
pkg.dependencies = dependencies ();
+ pkg.alternatives = vector<size_t> ();
if (size_t n = deps.size ())
+ {
pkg.dependencies->reserve (n);
+ pkg.alternatives->reserve (n);
+ }
- optional<dir_path> src_root (pkg.external_dir ());
-
- optional<dir_path> out_root (
- src_root && !pkg.disfigure
- ? dir_path (pdb.config) /= pkg.name ().string ()
- : optional<dir_path> ());
-
- pkg.skeleton = package_skeleton (options,
- pdb,
- *ap,
- pkg.config_vars,
- move (src_root),
- move (out_root));
+ if (!pkg.skeleton)
+ pkg.init_skeleton (options);
}
+ else
+ l5 ([&]{trace << "resume " << pkg.available_name_version_db ();});
- dependencies& sdeps (*pkg.dependencies);
+ dependencies& sdeps (*pkg.dependencies);
+ vector<size_t>& salts (*pkg.alternatives);
+
+ assert (sdeps.size () == salts.size ()); // Must be parallel.
// Check if there is nothing to collect anymore.
//
if (sdeps.size () == deps.size ())
+ {
+ l5 ([&]{trace << "end " << pkg.available_name_version_db ();});
return;
+ }
// Show how we got here if things go wrong.
//
@@ -1379,8 +3181,24 @@ namespace bpkg
package_skeleton& skel (*pkg.skeleton);
+ auto fail_reeval = [&pkg] ()
+ {
+ fail << "unable to re-create dependency information of already "
+ << "configured package " << pkg.available_name_version_db () <<
+ info << "likely cause is change in external environment" <<
+ info << "consider resetting the build configuration";
+ };
+
+ bool postponed (false);
+ bool reevaluated (false);
+
for (size_t di (sdeps.size ()); di != deps.size (); ++di)
{
+ // Fail if we missed the re-evaluation target position for any reason.
+ //
+ if (reeval && di == reeval_pos.first) // Note: reeval_pos is 1-based.
+ fail_reeval ();
+
const dependency_alternatives_ex& das (deps[di]);
// Add an empty alternatives list into the selected dependency list if
@@ -1388,9 +3206,10 @@ namespace bpkg
//
dependency_alternatives_ex sdas (das.buildtime, das.comment);
- if (toolchain_buildtime_dependency (options, das, pkg.name ()))
+ if (toolchain_buildtime_dependency (options, das, &nm))
{
sdeps.push_back (move (sdas));
+ salts.push_back (0); // Keep parallel to sdeps.
continue;
}
@@ -1398,7 +3217,7 @@ namespace bpkg
// Add an empty alternatives list into the selected dependency list if
// there are none.
//
- small_vector<reference_wrapper<const dependency_alternative>, 2> edas;
+ build_package::dependency_alternatives_refs edas;
if (pkg.postponed_dependency_alternatives)
{
@@ -1407,16 +3226,20 @@ namespace bpkg
}
else
{
- for (const dependency_alternative& da: das)
+ for (size_t i (0); i != das.size (); ++i)
{
- if (!da.enable || skel.evaluate_enable (*da.enable, di))
- edas.push_back (da);
+ const dependency_alternative& da (das[i]);
+
+ if (!da.enable ||
+ skel.evaluate_enable (*da.enable, make_pair (di, i)))
+ edas.push_back (make_pair (ref (da), i));
}
}
if (edas.empty ())
{
sdeps.push_back (move (sdas));
+ salts.push_back (0); // Keep parallel to sdeps.
continue;
}
@@ -1483,6 +3306,7 @@ namespace bpkg
};
auto precollect = [&options,
&pkg,
+ &nm,
&pdb,
ud,
&fdb,
@@ -1490,6 +3314,7 @@ namespace bpkg
&apc,
postponed_repo,
&dep_chain,
+ &trace,
this]
(const dependency_alternative& da,
bool buildtime,
@@ -1523,9 +3348,10 @@ namespace bpkg
bool system (false);
bool specified (false);
- // If the user specified the desired dependency version constraint,
- // then we will use it to overwrite the constraint imposed by the
- // dependent package, checking that it is still satisfied.
+ // If the user specified the desired dependency version
+ // constraint, then we will use it to overwrite the constraint
+ // imposed by the dependent package, checking that it is still
+ // satisfied.
//
// Note that we can't just rely on the execution plan refinement
// that will pick up the proper dependency version at the end of
@@ -1575,12 +3401,12 @@ namespace bpkg
if (dr != nullptr)
*dr << error << "unable to satisfy constraints on package "
<< dn <<
- info << pkg.name () << pdb << " depends on (" << dn
+ info << nm << pdb << " depends on (" << dn
<< " " << *dp.constraint << ")" <<
info << c.dependent << c.db << " depends on (" << dn
<< " " << c.value << ")" <<
info << "specify " << dn << " version to satisfy "
- << pkg.name () << " constraint";
+ << nm << " constraint";
return precollect_result (false /* postpone */);
}
@@ -1644,7 +3470,7 @@ namespace bpkg
//
if (rpt_prereq_flags != nullptr)
{
- auto i (rpt_prereq_flags->find (config_package {*ddb, dn}));
+ auto i (rpt_prereq_flags->find (package_key {*ddb, dn}));
bool unamended (i == rpt_prereq_flags->end ());
bool replacement (!unamended && i->second);
@@ -1675,17 +3501,18 @@ namespace bpkg
{
system = dsp->system ();
- optional<version_constraint> vc (
- !system
- ? version_constraint (dsp->version)
- : optional<version_constraint> ());
+ version_constraint vc (dsp->version);
// First try to find an available package for this exact
// version, falling back to ignoring version revision and
// iteration. In particular, this handles the case where a
// package moves from one repository to another (e.g., from
- // testing to stable). For a system package we pick the latest
- // one (its exact version doesn't really matter).
+ // testing to stable). For a system package we will try to
+ // find the available package that matches the selected
+ // package version (preferable for the configuration
+ // negotiation machinery) and, if fail, fallback to picking
+ // the latest one (its exact version doesn't really matter in
+ // this case).
//
// It seems reasonable to search for the package in the
// repositories explicitly added by the user if the selected
@@ -1703,11 +3530,11 @@ namespace bpkg
true /* prereq */,
true /* revision */);
- // Note: constraint is not present for the system package,
- // so there is no sense to repeat the attempt.
- //
- if (dap == nullptr && !system)
+ if (dap == nullptr)
rp = find_available_one (dbs, dn, vc);
+
+ if (dap == nullptr && system)
+ rp = find_available_one (dbs, dn, nullopt);
}
else if (af != nullptr)
{
@@ -1717,8 +3544,11 @@ namespace bpkg
true /* prereq */,
true /* revision */);
- if (dap == nullptr && !system)
+ if (dap == nullptr)
rp = find_available_one (dn, vc, af);
+
+ if (dap == nullptr && system)
+ rp = find_available_one (dn, nullopt, af);
}
// A stub satisfies any version constraint so we weed them out
@@ -1884,9 +3714,9 @@ namespace bpkg
// the same configuration with the build2 module it depends upon
// is an error.
//
- if (buildtime &&
- !build2_module (pkg.name ()) &&
- build2_module (dn) &&
+ if (buildtime &&
+ !build2_module (nm) &&
+ build2_module (dn) &&
pdb == *ddb)
{
assert (dr == nullptr); // Should fail on the "silent" run.
@@ -1926,7 +3756,7 @@ namespace bpkg
// for this package version. Consider this scenario as an
// example: hello/1.0.0 and libhello/1.0.0 in stable and
// libhello/2.0.0 in testing. As a prerequisite of hello, which
- // version should libhello resolve to? While one can probably
+ // version should libhello resolve to? While one can probably
// argue either way, resolving it to 1.0.0 is the conservative
// choice and the user can always override it by explicitly
// building libhello.
@@ -1959,13 +3789,17 @@ namespace bpkg
// problematic dependent, expecting that some other one will
// find the appropriate version in its repositories.
//
- // For a system package we pick the latest version just to make
- // sure the package is recognized. An unrecognized package means
- // the broken/stale repository (see below).
+ // For a system package we will try to find the available
+ // package that matches the constraint (preferable for the
+ // configuration negotiation machinery) and, if fail, fallback
+ // to picking the latest one just to make sure the package is
+ // recognized. An unrecognized package means the broken/stale
+ // repository (see below).
//
- rp = find_available_one (dn,
- !system ? d.constraint : nullopt,
- af);
+ rp = find_available_one (dn, d.constraint, af);
+
+ if (dap == nullptr && system && d.constraint)
+ rp = find_available_one (dn, nullopt, af);
if (dap == nullptr)
{
@@ -1976,6 +3810,12 @@ namespace bpkg
//
assert (dr == nullptr);
+ l5 ([&]{trace << "rep-postpone dependent "
+ << pkg.available_name_version_db ()
+ << " due to dependency " << dp
+ << " and user-specified constraint "
+ << *dep_constr;});
+
postponed_repo->insert (&pkg);
return precollect_result (true /* postpone */);
}
@@ -2004,7 +3844,7 @@ namespace bpkg
(!dep_constr || !wildcard (*dep_constr)))
*dr << ' ' << *d.constraint;
- *dr << ") of package " << pkg.name () << pdb <<
+ *dr << ") of package " << nm << pdb <<
info << "available " << dn << " versions:";
for (const shared_ptr<available_package>& ap: aps)
@@ -2013,7 +3853,7 @@ namespace bpkg
else
{
*dr << "no package available for dependency " << dn
- << " of package " << pkg.name () << pdb;
+ << " of package " << nm << pdb;
}
// Avoid printing this if the dependent package is external
@@ -2054,7 +3894,7 @@ namespace bpkg
{
if (dr != nullptr)
*dr << error << "dependency " << d << " of package "
- << pkg.name () << " is not available in source" <<
+ << nm << " is not available in source" <<
info << "specify ?sys:" << dn << " if it is available "
<< "from the system";
@@ -2065,7 +3905,7 @@ namespace bpkg
{
if (dr != nullptr)
*dr << error << "dependency " << d << " of package "
- << pkg.name () << " is not available in source" <<
+ << nm << " is not available in source" <<
info << package_string (dn,
*dap->system_version (*ddb),
true /* system */)
@@ -2114,8 +3954,7 @@ namespace bpkg
{
using constraint_type = build_package::constraint_type;
- constraint_type c1 {
- pkg.db, pkg.name ().string (), *d.constraint};
+ constraint_type c1 {pdb, nm.string (), *d.constraint};
if (!satisfies (v2, c1.value))
{
@@ -2170,20 +4009,49 @@ namespace bpkg
return precollect_result (move (r), reused);
};
- // Collect the previously collected pre-builds.
+ // Try to collect the previously collected pre-builds.
+ //
+ // Return false if the dependent has configuration clauses and is
+ // postponed until dependencies configuration negotiation.
//
auto collect = [&options,
&pkg,
&pdb,
+ &nm,
+ &pk,
&fdb,
&rpt_depts,
&apc,
+ initial_collection,
+ &replaced_vers,
+ &dep_chain,
postponed_repo,
postponed_alts,
- &dep_chain,
+ &postponed_deps,
+ &postponed_cfgs,
+ &postponed_poss,
+ &di,
+ reeval,
+ &reeval_pos,
+ &reevaluated,
+ &fail_reeval,
+ &trace,
this]
- (prebuilds&& bs)
+ (const dependency_alternative& da,
+ size_t dai,
+ prebuilds&& bs)
{
+ // Dependency alternative position.
+ //
+ pair<size_t, size_t> dp (di + 1, dai + 1);
+
+ if (reeval &&
+ dp.first == reeval_pos.first &&
+ dp.second != reeval_pos.second)
+ fail_reeval ();
+
+ postponed_configuration::packages cfg_deps;
+
for (prebuild& b: bs)
{
build_package bp {
@@ -2192,22 +4060,24 @@ namespace bpkg
b.selected,
b.available,
move (b.repository_fragment),
- nullopt, // Dependencies.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
b.system,
- false, // Keep output directory.
- false, // Disfigure (from-scratch reconf).
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {config_package {pdb, pkg.name ()}}, // Required by (dependent).
- true, // Required by dependents.
- 0}; // State flags.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ {pk}, // Required by (dependent).
+ true, // Required by dependents.
+ 0}; // State flags.
const optional<version_constraint>& constraint (
b.dependency.constraint);
@@ -2220,9 +4090,7 @@ namespace bpkg
// constraints for completeness.
//
if (constraint)
- bp.constraints.emplace_back (pdb,
- pkg.name ().string (),
- *constraint);
+ bp.constraints.emplace_back (pdb, nm.string (), *constraint);
// Now collect this prerequisite. If it was actually collected
// (i.e., it wasn't already there) and we are forcing a downgrade
@@ -2242,71 +4110,591 @@ namespace bpkg
// build sys:bar/1
// build foo ?sys:bar/2
//
- // Note: recursive.
+ // Pass the function which verifies we don't try to force
+ // up/downgrade of the held version and makes sure we don't print
+ // the dependency chain if replace_version will be thrown.
+ //
+ // Also note that we rely on "small function object" optimization
+ // here.
+ //
+ struct
+ {
+ const build_package& dependent;
+ const prebuild& prerequisite;
+ } dpn {pkg, b};
+
+ const function<verify_package_build_function> verify (
+ [&dpn, &dep_chain] (const build_package& p, bool scratch)
+ {
+ const prebuild& prq (dpn.prerequisite);
+ const build_package& dep (dpn.dependent);
+
+ if (prq.force && !prq.specified_dependency)
+ {
+ // Fail if the version is held. Otherwise, warn if the
+ // package is held.
+ //
+ bool f (prq.selected->hold_version);
+ bool w (!f && prq.selected->hold_package);
+
+ // Note that there is no sense to warn or inform the user if
+ // we are about to start re-collection from scratch.
+ //
+ // @@ It seems that we may still warn/inform multiple times
+ // about the same package if we start from scratch. The
+ // intermediate diagnostics can probably be irrelevant to
+ // the final result.
+ //
+ // Perhaps what we should do is queue the diagnostics and
+ // then, if the run is not scratched, issues it. And if
+ // it is scratched, then drop it.
+ //
+ if (f || ((w || verb >= 2) && !scratch))
+ {
+ const version& av (p.available_version ());
+
+ bool u (av > prq.selected->version);
+ bool c (prq.dependency.constraint);
+
+ diag_record dr;
+
+ (f ? dr << fail :
+ w ? dr << warn :
+ dr << info)
+ << "package " << dep.name () << dep.db
+ << " dependency on " << (c ? "(" : "") << prq.dependency
+ << (c ? ")" : "") << " is forcing "
+ << (u ? "up" : "down") << "grade of " << *prq.selected
+ << prq.db << " to ";
+
+ // Print both (old and new) package names in full if the
+ // system attribution changes.
+ //
+ if (prq.selected->system ())
+ dr << p.available_name_version ();
+ else
+ dr << av; // Can't be a system version so is never wildcard.
+
+ if (prq.selected->hold_version)
+ dr << info << "package version " << *prq.selected
+ << prq.db<< " is held";
+
+ if (f)
+ dr << info << "explicitly request version "
+ << (u ? "up" : "down") << "grade to continue";
+ }
+ }
+
+ // Don't print the "while satisfying..." chain if we are about
+ // to re-collect the packages.
+ //
+ if (scratch)
+ dep_chain.clear ();
+ });
+
+ // Note: non-recursive.
//
- const build_package* p (
+ build_package* p (
collect_build (options,
move (bp),
fdb,
rpt_depts,
apc,
- postponed_repo,
- postponed_alts,
- &dep_chain));
+ initial_collection,
+ replaced_vers,
+ postponed_cfgs,
+ nullptr /* dep_chain */,
+ nullptr /* postponed_repo */,
+ nullptr /* postponed_alts */,
+ nullptr /* postponed_deps */,
+ nullptr /* postponed_poss */,
+ verify));
+
+ package_key dpk (b.db, b.available->id.name);
+
+ // Do not collect prerequisites recursively for dependent
+ // re-evaluation. Instead, if the re-evaluation position is
+ // reached, collect the dependency packages to add them to the
+ // existing dependent's cluster.
+ //
+ if (reeval)
+ {
+ if (dp == reeval_pos)
+ cfg_deps.push_back (move (dpk));
+
+ continue;
+ }
+
+ // Do not recursively collect a dependency of a dependent with
+ // configuration clauses, which could be this or some other
+ // (indicated by the presence in postponed_deps) dependent. In the
+ // former case if the prerequisites were prematurely collected,
+ // throw postpone_dependency.
+ //
+ // Note that such a dependency will be recursively collected
+ // directly right after the configuration negotiation (rather than
+ // via the dependent).
+ //
+ bool collect_prereqs (p != nullptr);
- if (p != nullptr && b.force && !b.specified_dependency)
{
- // Fail if the version is held. Otherwise, warn if the package is
- // held.
- //
- bool f (b.selected->hold_version);
- bool w (!f && b.selected->hold_package);
+ build_package* bp (entered_build (dpk));
+ assert (bp != nullptr);
- if (f || w || verb >= 2)
+ if (da.prefer || da.require)
{
- const version& av (p->available_version ());
+ // Indicate that the dependent with configuration clauses is
+ // present.
+ //
+ {
+ auto i (postponed_deps.find (dpk));
- bool u (av > b.selected->version);
- bool c (constraint);
+ // Do not override postponements recorded during postponed
+ // collection phase with those recorded during initial
+ // phase.
+ //
+ if (i == postponed_deps.end ())
+ {
+ postponed_deps.emplace (dpk,
+ postponed_dependency {
+ false /* without_config */,
+ true /* with_config */,
+ initial_collection});
+ }
+ else
+ i->second.with_config = true;
+ }
- diag_record dr;
+ // Prematurely collected before we saw any config clauses.
+ //
+ if (bp->recursive_collection &&
+ postponed_cfgs.find_dependency (dpk) == nullptr)
+ {
+ l5 ([&]{trace << "cannot cfg-postpone dependency "
+ << bp->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ()
+ << " (collected prematurely), "
+ << "throwing postpone_dependency";});
+
+ // Don't print the "while satisfying..." chain.
+ //
+ dep_chain.clear ();
- (f ? dr << fail :
- w ? dr << warn :
- dr << info)
- << "package " << pkg.name () << pdb << " dependency on "
- << (c ? "(" : "") << b.dependency << (c ? ")" : "")
- << " is forcing " << (u ? "up" : "down") << "grade of "
- << *b.selected << b.db << " to ";
+ throw postpone_dependency (move (dpk));
+ }
- // Print both (old and new) package names in full if the system
- // attribution changes.
+ // Postpone until (re-)negotiation.
//
- if (b.selected->system ())
- dr << p->available_name_version ();
+ l5 ([&]{trace << "cfg-postpone dependency "
+ << bp->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ();});
+
+ cfg_deps.push_back (move (dpk));
+
+ collect_prereqs = false;
+ }
+ else
+ {
+ // Indicate that the dependent without configuration clauses
+ // is also present.
+ //
+ auto i (postponed_deps.find (dpk));
+ if (i != postponed_deps.end ())
+ {
+ l5 ([&]{trace << "dep-postpone dependency "
+ << bp->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ();});
+
+ i->second.wout_config = true;
+
+ collect_prereqs = false;
+ }
else
- dr << av; // Can't be a system version so is never wildcard.
+ {
+ l5 ([&]{trace << "no cfg-clause for dependency "
+ << bp->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ();});
+ }
+ }
+ }
+
+ if (collect_prereqs)
+ collect_build_prerequisites (options,
+ *p,
+ fdb,
+ rpt_depts,
+ apc,
+ initial_collection,
+ replaced_vers,
+ dep_chain,
+ postponed_repo,
+ postponed_alts,
+ 0 /* max_alt_index */,
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
+ }
+
+ // If this dependent has any dependencies with configurations
+ // clauses, then we need to deal with that.
+ //
+ // This is what we refer to as the "up-negotiation" where we
+ // negotiate the configuration of dependents that could not be
+ // postponed and handled all at once during "initial negotiation" in
+ // collect_build_postponed().
+ //
+ if (!cfg_deps.empty ())
+ {
+ // Re-evaluation is a special case (it happens during cluster
+ // negotiation; see collect_build_postponed()).
+ //
+ if (reeval)
+ {
+ reevaluated = true;
+
+ // Note: the dependent may already exist in the cluster with a
+ // subset of dependencies.
+ //
+ postponed_configuration& cfg (
+ postponed_cfgs.add (pk,
+ true /* existing */,
+ dp,
+ cfg_deps).first);
+
+ // Can we merge clusters as a result? Seems so.
+ //
+ // - Simple case is if the cluster(s) being merged are not
+ // negotiated. Then perhaps we could handle this via the same
+ // logic that handles the addition of extra dependencies.
+ //
+ // - For the complex case, perhaps just making the resulting
+ // cluster shadow and rolling back, just like in the other
+ // case (non-existing dependent).
+ //
+ // Note: this is a special case of the below more general logic.
+ //
+ // Also note that we can distinguish the simple case by the fact
+ // that the resulting cluster is not negotiated. Note however,
+ // that in this case it is guaranteed that all the involved
+ // clusters will be merged into the cluster which the being
+ // re-evaluated dependent belongs to since this cluster (while
+ // not being negotiated) already has non-zero depth (see
+ // collect_build_postponed() for details).
+ //
+ assert (cfg.depth != 0);
+
+ if (cfg.negotiated)
+ {
+ l5 ([&]{trace << "re-evaluating dependent "
+ << pkg.available_name_version_db ()
+ << " involves negotiated configurations and "
+ << "results in " << cfg << ", throwing "
+ << "merge_configuration";});
+
+ // Don't print the "while satisfying..." chain.
+ //
+ dep_chain.clear ();
- if (b.selected->hold_version)
- dr << info << "package version " << *b.selected << b.db
- << " is held";
+ throw merge_configuration {cfg.depth};
+ }
+
+ l5 ([&]{trace << "re-evaluating dependent "
+ << pkg.available_name_version_db ()
+ << " results in " << cfg;});
+
+ return false;
+ }
+
+ // As a first step add this dependent/dependencies to one of the
+ // new/existing postponed_configuration clusters, which could
+ // potentially cause some of them to be merged. Here are the
+ // possibilities and what we should do in each case.
+ //
+ // 1. Got added to a new cluster -- this dependent got postponed
+ // and we return false.
+ //
+ // 2. Got added to an existing non-yet-negotiated cluster (which
+ // could potentially involve merging a bunch of them) -- ditto.
+ //
+ // 3. Got added to an existing already-[being]-negotiated cluster
+ // (which could potentially involve merging a bunch of them,
+ // some negotiated, some being negotiated, and some not yet
+ // negotiated) -- see below logic.
+ //
+ // Note that if a dependent is postponed, it will be recursively
+ // recollected right after the configuration negotiation.
+
+ // Note: don't move the argument from since may be needed for
+ // constructing exception.
+ //
+ pair<postponed_configuration&, optional<bool>> r (
+ postponed_cfgs.add (pk, false /* existing */, dp, cfg_deps));
+
+ postponed_configuration& cfg (r.first);
+
+ if (cfg.depth == 0)
+ return false; // Cases (1) or (2).
+ else
+ {
+ // Case (3).
+ //
+ // There is just one complication:
+ //
+ // If all the merged clusters are already negotiated, then all
+ // is good: all the dependencies in cfg_deps have been collected
+ // recursively as part of the configuration negotiation (because
+ // everything in this cluster is already negotiated) and we can
+ // return true (no need to postpone any further steps).
+ //
+ // But if we merged clusters not yet negotiated, or, worse,
+ // being in the middle of negotiation, then we need to get this
+ // merged cluster into the fully negotiated state. The way we do
+ // it is by throwing merge_configuration (see below).
+ //
+ // When we are back here after throwing merge_configuration,
+ // then all the clusters have been pre-merged and our call to
+ // add() shouldn't have added any new cluster. In this case the
+ // cluster can either be already negotiated or being negotiated
+ // and we can proceed as in the "everything is negotiated case"
+ // above (we just need to get the the dependencies that we care
+ // about into the recursively collected state).
+ //
+
+ // To recap, r.second values mean:
+ //
+ // absent -- shadow cluster-based merge is/being negotiated
+ // false -- some non or being negotiated
+ // true -- all have been negotiated
+ //
+ if (r.second && !*r.second)
+ {
+ // The partially negotiated case.
+ //
+ // Handling this in a straightforward way is not easy due to
+ // the being negotiated cases -- we have code up the stack
+ // that is in the middle of the negotiation logic.
+ //
+ // Another idea is to again throw to the outer try/catch frame
+ // (thus unwinding all the being negotiated code) and complete
+ // the work there. The problem with this approach is that
+ // without restoring the state we may end up with unrelated
+ // clusters that will have no corresponding try-catch frames
+ // (because we may unwind them in the process).
+ //
+ // So the approach we will use is the "shadow" idea for
+ // merging clusters. Specifically, we throw
+ // merge_configuration to the outer try/catch. At the catch
+ // site we make the newly merged cluster a shadow of the
+ // restored cluster and retry the same steps similar to
+ // retry_configuration. As we redo these steps, we consult the
+ // shadow cluster and if the dependent/dependency entry is
+ // there, then instead of adding it to another (new/existing)
+ // cluster that would later be merged into this non-shadow
+ // cluster, we add it directly to the non-shadow cluster
+ // (potentially merging other cluster which it feels like by
+ // definition should all be already fully negotiated). The end
+ // result is that once we reach this point again, there will
+ // be nothing to merge.
+ //
+ // The shadow check is part of postponed_configs::add().
+ //
+ l5 ([&]{trace << "cfg-postponing dependent "
+ << pkg.available_name_version_db ()
+ << " merges non-negotiated and/or being "
+ << "negotiated configurations in and results in "
+ << cfg << ", throwing merge_configuration";});
+
+ // Don't print the "while satisfying..." chain.
+ //
+ dep_chain.clear ();
+
+ throw merge_configuration {cfg.depth};
+ }
+
+ // Up-negotiate the configuration and if it has changed, throw
+ // retry_configuration to the try/catch frame corresponding to
+ // the negotiation of the outermost merged cluster in order to
+ // retry the same steps (potentially refining the configuration
+ // as we go along) and likely (but not necessarily) ending up
+ // here again, at which point we up-negotiate again with the
+ // expectation that the configuration won't change (but if it
+ // does, then we throw again and do another refinement pass).
+ //
+ // In a sense, semantically, we should act like a one more
+ // iteration of the initial negotiation loop with the exception
+ // acting like a request to restart the refinement process from
+ // the beginning.
+ //
+ bool changed;
+ {
+ // Similar to initial negotiation, resolve package skeletons
+ // for this dependent and its dependencies.
+ //
+ package_skeleton* dept;
+ {
+ build_package* b (entered_build (pk));
+ assert (b != nullptr && b->skeleton);
+ dept = &*b->skeleton;
+ }
+
+ // If a dependency has already been recursively collected,
+ // then we can no longer call reload_defaults() or
+ // verify_sensible() on its skeleton. We could reset it, but
+ // then we wouldn't be able to continue using it if
+ // negotiate_configuration() below returns false. So it seems
+ // the most sensible approach is to make a temporary copy and
+ // reset that.
+ //
+ small_vector<reference_wrapper<package_skeleton>, 1> depcs;
+ forward_list<package_skeleton> depcs_storage; // Ref stability.
+ {
+ depcs.reserve (cfg_deps.size ());
+ for (const package_key& pk: cfg_deps)
+ {
+ build_package* b (entered_build (pk));
+ assert (b != nullptr);
+
+ package_skeleton* depc;
+ if (b->recursive_collection)
+ {
+ assert (b->skeleton);
+
+ depcs_storage.push_front (*b->skeleton);
+ depc = &depcs_storage.front ();
+ depc->reset ();
+ }
+ else
+ depc = &(b->skeleton
+ ? *b->skeleton
+ : b->init_skeleton (options));
+
+ depcs.push_back (*depc);
+ }
+ }
+
+ changed = negotiate_configuration (
+ cfg.dependency_configurations, *dept, dp, depcs);
+ }
+
+ // If the configuration hasn't changed, then we carry on.
+ // Otherwise, retry the negotiation from the beginning to
+ // refine the resulting configuration (see the catch block
+ // for retry_configuration).
+ //
+ if (changed)
+ {
+ l5 ([&]{trace << "cfg-postponing dependent "
+ << pkg.available_name_version_db ()
+ << " involves (being) negotiated configurations "
+ << "and results in " << cfg
+ << ", throwing retry_configuration";});
+
+ // Don't print the "while satisfying..." chain.
+ //
+ dep_chain.clear ();
+
+ throw retry_configuration {cfg.depth, move (pk)};
+ }
+
+ l5 ([&]{trace << "configuration for cfg-postponed "
+ << "dependencies of dependent "
+ << pkg.available_name_version_db () << " is "
+ << (r.second ? "" : "shadow-") << "negotiated";});
+
+ // Note that even in the fully negotiated case we may still add
+ // extra dependencies to this cluster which we still need to
+ // configure and recursively collect before indicating to the
+ // caller (returning true) that we are done with this depends
+ // value and the dependent is not postponed.
+ //
+ for (const package_key& p: cfg_deps)
+ {
+ build_package* b (entered_build (p));
+ assert (b != nullptr);
+
+ // Reconfigure the configured dependencies (see
+ // collect_build_postponed() for details).
+ //
+ if (b->selected != nullptr &&
+ b->selected->state == package_state::configured)
+ b->flags |= build_package::adjust_reconfigure;
+
+ if (!b->recursive_collection)
+ {
+ l5 ([&]{trace << "collecting cfg-postponed dependency "
+ << b->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ();});
+
+ // Similar to the inital negotiation case, verify and set
+ // the dependent configuration for this dependency.
+ //
+ {
+ assert (b->skeleton); // Should have been init'ed above.
+
+ const package_configuration& pc (
+ cfg.dependency_configurations[p]);
+
+ pair<bool, string> pr (b->skeleton->available != nullptr
+ ? b->skeleton->verify_sensible (pc)
+ : make_pair (true, string ()));
+
+ if (!pr.first)
+ {
+ diag_record dr (fail);
+ dr << "unable to negotiate sensible configuration for "
+ << "dependency " << p << '\n'
+ << " " << pr.second;
+
+ dr << info << "negotiated configuration:\n";
+ pc.print (dr, " ");
+ }
+
+ b->skeleton->dependent_config (pc);
+ }
- if (f)
- dr << info << "explicitly request version "
- << (u ? "up" : "down") << "grade to continue";
+ collect_build_prerequisites (options,
+ *b,
+ fdb,
+ rpt_depts,
+ apc,
+ initial_collection,
+ replaced_vers,
+ dep_chain,
+ postponed_repo,
+ postponed_alts,
+ 0 /* max_alt_index */,
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
+ }
+ else
+ l5 ([&]{trace << "dependency "
+ << b->available_name_version_db ()
+ << " of dependent "
+ << pkg.available_name_version_db ()
+ << " is already (being) recursively "
+ << "collected, skipping";});
}
+
+ return true;
}
}
+
+ return true;
};
// Select a dependency alternative, copying it alone into the
- // resulting dependencies list, evaluating its reflect clause, if
- // present, and collecting its dependency builds.
+ // resulting dependencies list and evaluating its reflect clause, if
+ // present.
//
bool selected (false);
- auto select = [&sdeps, &sdas, &skel, di, &collect, &selected]
- (const dependency_alternative& da,
- prebuilds&& bs)
+ auto select = [&sdeps, &salts, &sdas, &skel, di, &selected]
+ (const dependency_alternative& da, size_t dai)
{
assert (sdas.empty ());
@@ -2320,20 +4708,18 @@ namespace bpkg
da /* dependencies */);
sdeps.push_back (move (sdas));
+ salts.push_back (dai);
if (da.reflect)
- skel.evaluate_reflect (*da.reflect, di);
-
- collect (move (bs));
+ skel.evaluate_reflect (*da.reflect, make_pair (di, dai));
selected = true;
};
// Postpone the prerequisite builds collection, optionally inserting
- // the package to the postpones set (can potentially already be there)
- // and saving the enabled alternatives.
+ // the package to the postponements set (can potentially already be
+ // there) and saving the enabled alternatives.
//
- bool postponed (false);
auto postpone = [&pkg, &edas, &postponed]
(postponed_packages* postpones)
{
@@ -2357,10 +4743,19 @@ namespace bpkg
// decisions" mode and select the alternative ignoring the current
// prerequisites.
//
+ // Note though, that if we are re-evaluating an existing dependent
+ // then we fail if we didn't succeed in the "recreate dependency
+ // decisions" mode.
+ //
const package_prerequisites* prereqs (src_conf && !ud
? &sp->prerequisites
: nullptr);
+ // During the dependent re-evaluation we always try to reproduce the
+ // existing setup.
+ //
+ assert (!reeval || prereqs != nullptr);
+
for (;;)
{
// The index and pre-collection result of the first satisfactory
@@ -2374,7 +4769,7 @@ namespace bpkg
for (size_t i (0); i != edas.size (); ++i)
{
- const dependency_alternative& da (edas[i]);
+ const dependency_alternative& da (edas[i].first);
precollect_result r (precollect (da, das.buildtime, prereqs));
@@ -2388,7 +4783,7 @@ namespace bpkg
// satisfies the constraint. On the other hand, it could be that
// it's other dependent's constraints that we cannot satisfy
// together with others. And in this case we may want some other
- // alternative. Consider, as an example, something like this:
+ // alternative. Consider, as an example, something like this:
//
// depends: libfoo >= 2.0.0 | libfoo >= 1.0.0 libbar
//
@@ -2396,6 +4791,9 @@ namespace bpkg
{
if (r.repo_postpone)
{
+ if (reeval)
+ fail_reeval ();
+
postpone (nullptr); // Already inserted into postponed_repo.
break;
}
@@ -2408,9 +4806,9 @@ namespace bpkg
// Note that when we see the first satisfactory alternative, we
// don't know yet if it is a single alternative or the first of
// the (multiple) true alternatives (those are handled
- // differently). Thus, we postpone its processing until the
- // second satisfactory alternative is encountered or the end of
- // the alternatives list is reached.
+ // differently). Thus, we postpone its processing until the second
+ // satisfactory alternative is encountered or the end of the
+ // alternatives list is reached.
//
if (!first_alt)
{
@@ -2424,15 +4822,31 @@ namespace bpkg
// of it dependencies are reused).
//
auto try_select = [postponed_alts, &max_alt_index,
- &edas,
- &postpone, &select]
+ &edas, &pkg,
+ reeval,
+ &trace,
+ &postpone, &collect, &select]
(size_t index, precollect_result&& r)
{
+ const auto& eda (edas[index]);
+ const dependency_alternative& da (eda.first);
+ size_t dai (eda.second);
+
// Postpone the collection if the alternatives maximum index is
// reached.
//
if (postponed_alts != nullptr && index >= max_alt_index)
{
+ // For a dependent re-evaluation max_alt_index is expected to
+ // be max size_t.
+ //
+ assert (!reeval);
+
+ l5 ([&]{trace << "alt-postpone dependent "
+ << pkg.available_name_version_db ()
+ << " since max index is reached: " << index <<
+ info << "dependency alternative: " << da;});
+
postpone (postponed_alts);
return true;
}
@@ -2447,12 +4861,20 @@ namespace bpkg
//
assert (postponed_alts != nullptr);
- select (edas[index], move (*r.builds));
+ if (!collect (da, dai, move (*r.builds)))
+ {
+ postpone (nullptr); // Already inserted into postponed_cfgs.
+ return true;
+ }
+
+ select (da, dai);
// Make sure no more true alternatives are selected during
- // this function call.
+ // this function call unless we are re-evaluating a dependent.
//
- max_alt_index = 0;
+ if (!reeval)
+ max_alt_index = 0;
+
return true;
}
else
@@ -2491,7 +4913,17 @@ namespace bpkg
{
assert (first_alt && first_alt->second.builds);
- select (edas[first_alt->first], move (*first_alt->second.builds));
+ const auto& eda (edas[first_alt->first]);
+ const dependency_alternative& da (eda.first);
+ size_t dai (eda.second);
+
+ if (!collect (da, dai, move (*first_alt->second.builds)))
+ {
+ postpone (nullptr); // Already inserted into postponed_cfgs.
+ break;
+ }
+
+ select (da, dai);
}
// If an alternative is selected, then we are done.
@@ -2500,12 +4932,16 @@ namespace bpkg
break;
// Fail or postpone the collection if no alternative is selected,
- // unless we are in the "recreate dependency decisions" mode. In the
- // latter case fall back to the "make dependency decisions" mode and
- // retry.
+ // unless we are re-evaluating a dependent or are in the "recreate
+ // dependency decisions" mode. In the latter case fail for
+ // re-evaluation and fall back to the "make dependency decisions"
+ // mode and retry otherwise.
//
if (prereqs != nullptr)
{
+ if (reeval)
+ fail_reeval ();
+
prereqs = nullptr;
continue;
}
@@ -2516,8 +4952,8 @@ namespace bpkg
if (alts_num == 0)
{
diag_record dr;
- for (const dependency_alternative& da: edas)
- precollect (da, das.buildtime, nullptr /* prereqs */, &dr);
+ for (const auto& da: edas)
+ precollect (da.first, das.buildtime, nullptr /* prereqs */, &dr);
assert (!dr.empty ());
@@ -2533,6 +4969,17 @@ namespace bpkg
if (postponed_alts != nullptr)
{
+ if (verb >= 5)
+ {
+ diag_record dr (trace);
+ dr << "alt-postpone dependent "
+ << pkg.available_name_version_db ()
+ << " due to ambiguous alternatives";
+
+ for (const auto& da: edas)
+ dr << info << "alternative: " << da.first;
+ }
+
postpone (postponed_alts);
break;
}
@@ -2543,10 +4990,10 @@ namespace bpkg
info << "explicitly specify dependency packages to manually "
<< "select the alternative";
- for (const dependency_alternative& da: edas)
+ for (const auto& da: edas)
{
precollect_result r (
- precollect (da, das.buildtime, nullptr /* prereqs */));
+ precollect (da.first, das.buildtime, nullptr /* prereqs */));
if (r.builds)
{
@@ -2570,7 +5017,57 @@ namespace bpkg
break;
}
+ if (reeval)
+ {
+ if (!reevaluated)
+ fail_reeval ();
+
+ assert (postponed);
+ }
+
dep_chain.pop_back ();
+
+ l5 ([&]{trace << (!postponed ? "end " :
+ reeval ? "re-evaluated " :
+ "postpone ")
+ << pkg.available_name_version_db ();});
+ }
+
+ void
+ collect_build_prerequisites (const pkg_build_options& o,
+ database& db,
+ const package_name& name,
+ const function<find_database_function>& fdb,
+ const repointed_dependents& rpt_depts,
+ const function<add_priv_cfg_function>& apc,
+ bool initial_collection,
+ replaced_versions& replaced_vers,
+ postponed_packages& postponed_repo,
+ postponed_packages& postponed_alts,
+ size_t max_alt_index,
+ postponed_dependencies& postponed_deps,
+ postponed_configurations& postponed_cfgs,
+ postponed_positions& postponed_poss)
+ {
+ auto mi (map_.find (db, name));
+ assert (mi != map_.end ());
+
+ build_package_refs dep_chain;
+
+ collect_build_prerequisites (o,
+ mi->second.package,
+ fdb,
+ rpt_depts,
+ apc,
+ initial_collection,
+ replaced_vers,
+ dep_chain,
+ &postponed_repo,
+ &postponed_alts,
+ max_alt_index,
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
}
// Collect the repointed dependents and their replaced prerequisites,
@@ -2585,8 +5082,12 @@ namespace bpkg
collect_repointed_dependents (
const pkg_build_options& o,
const repointed_dependents& rpt_depts,
- build_packages::postponed_packages& postponed_repo,
- build_packages::postponed_packages& postponed_alts,
+ replaced_versions& replaced_vers,
+ postponed_packages& postponed_repo,
+ postponed_packages& postponed_alts,
+ postponed_dependencies& postponed_deps,
+ postponed_configurations& postponed_cfgs,
+ postponed_positions& postponed_poss,
const function<find_database_function>& fdb,
const function<add_priv_cfg_function>& apc)
{
@@ -2619,13 +5120,13 @@ namespace bpkg
// Add the prerequisite replacements as the required-by packages.
//
- set<config_package> required_by;
+ set<package_key> required_by;
for (const auto& prq: rd.second)
{
if (prq.second) // Prerequisite replacement?
{
- const config_package& cp (prq.first);
- required_by.emplace (cp.db, cp.name);
+ const package_key& pk (prq.first);
+ required_by.emplace (pk.db, pk.name);
}
}
@@ -2636,8 +5137,10 @@ namespace bpkg
move (rp.first),
move (rp.second),
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
nullopt, // Hold package.
nullopt, // Hold version.
{}, // Constraints.
@@ -2661,18 +5164,62 @@ namespace bpkg
fdb,
rpt_depts,
apc,
+ true /* initial_collection */,
+ replaced_vers,
+ postponed_cfgs,
+ &dep_chain,
&postponed_repo,
&postponed_alts,
- &dep_chain);
+ &postponed_deps,
+ &postponed_poss);
}
}
// Collect the package being dropped.
//
+ // Add entry to replaced_vers and throw replace_version if the existing
+ // version needs to be dropped but this can't be done in-place (see
+ // replaced_versions for details).
+ //
void
- collect_drop (database& db, shared_ptr<selected_package> sp)
+ collect_drop (const pkg_build_options& options,
+ database& db,
+ shared_ptr<selected_package> sp,
+ replaced_versions& replaced_vers)
{
- const package_name& nm (sp->name);
+ tracer trace ("collect_drop");
+
+ package_key pk (db, sp->name);
+
+ // If there is an entry for building specific version of the package
+ // (the available member is not NULL), then it wasn't created to prevent
+ // out drop (see replaced_versions for details). This rather mean that
+ // the replacement version is not being built anymore due to the plan
+ // refinement. Thus, just erase the entry in this case and continue.
+ //
+ auto vi (replaced_vers.find (pk));
+ if (vi != replaced_vers.end () && !vi->second.replaced)
+ {
+ replaced_version& v (vi->second);
+ const shared_ptr<available_package>& ap (v.available);
+
+ if (ap != nullptr)
+ {
+ if (verb >= 5)
+ {
+ bool s (v.system);
+ const version& av (s ? *ap->system_version (db) : ap->version);
+
+ l5 ([&]{trace << "erase version replacement for "
+ << package_string (ap->id.name, av, s) << db;});
+ }
+
+ replaced_vers.erase (vi);
+ vi = replaced_vers.end (); // Keep it valid for the below check.
+ }
+ else
+ v.replaced = true;
+ }
build_package p {
build_package::drop,
@@ -2681,8 +5228,10 @@ namespace bpkg
nullptr,
nullptr,
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
nullopt, // Hold package.
nullopt, // Hold version.
{}, // Constraints.
@@ -2697,20 +5246,55 @@ namespace bpkg
false, // Required by dependents.
0}; // State flags.
- auto i (map_.find (db, nm));
+ auto i (map_.find (pk));
if (i != map_.end ())
{
build_package& bp (i->second.package);
+ if (bp.available != nullptr)
+ {
+ // Similar to the version replacement in collect_build(), see if
+ // in-place drop is possible (no dependencies, etc) and set scratch
+ // to false if that's the case.
+ //
+ bool scratch (true);
+
+ // While checking if the package has any dependencies skip the
+ // toolchain build-time dependencies since they should be quite
+ // common.
+ //
+ if (!has_dependencies (options, bp.available->dependencies))
+ scratch = false;
+
+ l5 ([&]{trace << bp.available_name_version_db ()
+ << " package version needs to be replaced "
+ << (!scratch ? "in-place " : "") << "with drop";});
+
+ if (scratch)
+ {
+ if (vi != replaced_vers.end ())
+ vi->second = replaced_version ();
+ else
+ replaced_vers.emplace (move (pk), replaced_version ());
+
+ throw replace_version ();
+ }
+ }
+
// Overwrite the existing (possibly pre-entered, adjustment, or
// repoint) entry.
//
+ l4 ([&]{trace << "overwrite " << pk;});
+
bp = move (p);
}
else
- map_.emplace (config_package {db, nm},
- data_type {end (), move (p)});
+ {
+ l4 ([&]{trace << "add " << pk;});
+
+ map_.emplace (move (pk), data_type {end (), move (p)});
+ }
}
// Collect the package being unheld.
@@ -2734,21 +5318,23 @@ namespace bpkg
sp,
nullptr,
nullptr,
- nullopt, // Dependencies.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
- false, // System package.
- false, // Keep output directory.
- false, // Disfigure (from-scratch reconf).
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {}, // Required by.
- false, // Required by dependents.
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ sp->system (),
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ {}, // Required by.
+ false, // Required by dependents.
build_package::adjust_unhold};
p.merge (move (bp));
@@ -2759,46 +5345,823 @@ namespace bpkg
}
void
- collect_build_prerequisites (const pkg_build_options& o,
- database& db,
- const package_name& name,
- postponed_packages& postponed_repo,
- postponed_packages& postponed_alts,
- size_t max_alt_index,
- const function<find_database_function>& fdb,
- const repointed_dependents& rpt_depts,
- const function<add_priv_cfg_function>& apc)
- {
- auto mi (map_.find (db, name));
- assert (mi != map_.end ());
-
- build_package_refs dep_chain;
-
- collect_build_prerequisites (o,
- mi->second.package,
- fdb,
- rpt_depts,
- apc,
- &postponed_repo,
- &postponed_alts,
- max_alt_index,
- dep_chain);
- }
-
- void
collect_build_postponed (const pkg_build_options& o,
+ replaced_versions& replaced_vers,
postponed_packages& postponed_repo,
postponed_packages& postponed_alts,
+ postponed_dependencies& postponed_deps,
+ postponed_configurations& postponed_cfgs,
+ strings& postponed_cfgs_history,
+ postponed_positions& postponed_poss,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
- const function<add_priv_cfg_function>& apc)
+ const function<add_priv_cfg_function>& apc,
+ postponed_configuration* pcfg = nullptr)
{
+ // Snapshot of the package builds collection state.
+ //
+ // Note: should not include postponed_cfgs_history.
+ //
+ class snapshot
+ {
+ public:
+ snapshot (const build_packages& pkgs,
+ const postponed_packages& postponed_repo,
+ const postponed_packages& postponed_alts,
+ const postponed_dependencies& postponed_deps,
+ const postponed_configurations& postponed_cfgs)
+ : pkgs_ (pkgs),
+ postponed_deps_ (postponed_deps),
+ postponed_cfgs_ (postponed_cfgs)
+ {
+ auto save = [] (vector<package_key>& d,
+ const postponed_packages& s)
+ {
+ d.reserve (s.size ());
+
+ for (const build_package* p: s)
+ d.emplace_back (p->db, p->name ());
+ };
+
+ save (postponed_repo_, postponed_repo);
+ save (postponed_alts_, postponed_alts);
+ }
+
+ void
+ restore (build_packages& pkgs,
+ postponed_packages& postponed_repo,
+ postponed_packages& postponed_alts,
+ postponed_dependencies& postponed_deps,
+ postponed_configurations& postponed_cfgs)
+ {
+ pkgs = move (pkgs_);
+ postponed_cfgs = move (postponed_cfgs_);
+ postponed_deps = move (postponed_deps_);
+
+ auto restore = [&pkgs] (postponed_packages& d,
+ const vector<package_key>& s)
+ {
+ d.clear ();
+
+ for (const package_key& p: s)
+ {
+ build_package* b (pkgs.entered_build (p));
+ assert (b != nullptr);
+ d.insert (b);
+ }
+ };
+
+ restore (postponed_repo, postponed_repo_);
+ restore (postponed_alts, postponed_alts_);
+ }
+
+ private:
+ // Note: try to use vectors instead of sets for storage to save
+ // memory. We could probably optimize this some more if
+ // necessary (there are still sets/maps inside).
+ //
+ build_packages pkgs_;
+ vector<package_key> postponed_repo_;
+ vector<package_key> postponed_alts_;
+ postponed_dependencies postponed_deps_;
+ postponed_configurations postponed_cfgs_;
+ };
+
+ // This exception is thrown if negotiation of the current cluster needs
+ // to be skipped until later. This is normally required if this cluster
+ // contains some existing dependent which needs to be re-evaluated to a
+ // dependency position greater than some other not yet negotiated
+ // cluster will re-evaluate this dependent to. Sometimes this another
+ // cluster yet needs to be created in which case the exception carries
+ // the information required for that (see the postponed_position's
+ // replace flag for details).
+ //
+ struct skip_configuration
+ {
+ optional<existing_dependent> dependent;
+ pair<size_t, size_t> new_position;
+
+ skip_configuration () = default;
+
+ skip_configuration (existing_dependent&& d, pair<size_t, size_t> n)
+ : dependent (move (d)), new_position (n) {}
+ };
+
+ size_t depth (pcfg != nullptr ? pcfg->depth : 0);
+
+ string t ("collect_build_postponed (" + to_string (depth) + ")");
+ tracer trace (t.c_str ());
+
+ string trace_suffix (verb >= 5 && pcfg != nullptr
+ ? " " + pcfg->string ()
+ : "");
+
+ l5 ([&]{trace << "begin" << trace_suffix;});
+
+ if (pcfg != nullptr)
+ {
+ // This is what we refer to as the "initial negotiation" where we
+ // negotiate the configuration of dependents that could be postponed.
+ // Those that could not we "up-negotiate" in the collect() lambda of
+ // collect_build_prerequisites().
+ //
+ using packages = postponed_configuration::packages;
+
+ assert (!pcfg->negotiated);
+
+ // Re-evaluate existing dependents with configuration clause for
+ // dependencies in this configuration cluster up to these
+ // dependencies. Omit dependents which are already being built or
+ // dropped. Note that these dependents, potentially with additional
+ // dependencies, will be added to this cluster with the `existing`
+ // flag as a part of the dependents' re-evaluation (see the collect
+ // lambda in collect_build_prerequisites() for details).
+ //
+ // After being re-evaluated the existing dependents are recursively
+ // collected in the same way as the new dependents.
+ //
+ {
+ // Map existing dependents to the dependencies they apply a
+ // configuration to. Also, collect the information which is required
+ // for a dependent re-evaluation and its subsequent recursive
+ // collection (selected package, etc).
+ //
+ // As mentioned earlier, we may end up adding additional
+ // dependencies to pcfg->dependencies which in turn may have
+ // additional existing dependents which we need to process. Feels
+ // like doing this iteratively is the best option.
+ //
+ // Note that we need to make sure we don't re-process the same
+ // existing dependents.
+ //
+ struct existing_dependent_ex: existing_dependent
+ {
+ packages dependencies;
+ bool reevaluated = false;
+
+ existing_dependent_ex (existing_dependent&& ed)
+ : existing_dependent (move (ed)) {}
+ };
+ map<package_key, existing_dependent_ex> dependents;
+
+ const packages& deps (pcfg->dependencies);
+
+ // Note that the below collect_build_prerequisites() call can only
+ // add new dependencies to the end of the cluster's dependencies
+ // list. Thus on each iteration we will only add existing dependents
+ // of unprocessed/new dependencies. We will also skip the already
+ // re-evaluated existing dependents.
+ //
+ for (size_t i (0); i != deps.size (); )
+ {
+ size_t n (dependents.size ());
+
+ for (; i != deps.size (); ++i)
+ {
+ // Note: this reference is only used while deps is unchanged.
+ //
+ const package_key& p (deps[i]);
+
+ // If the dependent is being built, then check if it was
+ // re-evaluated to the position greater than the dependency
+ // position. Return true if that's the case, so this package is
+ // added to the resulting list and we can handle this situation.
+ //
+ // Note that we rely on "small function object" optimization
+ // here.
+ //
+ const function<verify_dependent_build_function> verify (
+ [&postponed_cfgs, pcfg]
+ (const package_key& pk, pair<size_t, size_t> pos)
+ {
+ for (const postponed_configuration& cfg: postponed_cfgs)
+ {
+ if (&cfg == pcfg || cfg.negotiated)
+ {
+ if (const pair<size_t, size_t>* p =
+ cfg.existing_dependent_position (pk))
+ {
+ if (p->first > pos.first)
+ return true;
+ }
+ }
+ }
+
+ return false;
+ });
+
+ for (existing_dependent& ed:
+ query_existing_dependents (trace,
+ p.db,
+ p.name,
+ replaced_vers,
+ rpt_depts,
+ verify))
+ {
+ package_key pk (ed.db, ed.selected->name);
+
+ // If this dependent is present in postponed_deps, then it
+ // means someone depends on it with configuration and it's no
+ // longer considered an existing dependent (it will be
+ // reconfigured). However, this fact may not be reflected yet.
+ // And it can actually turn out bogus.
+ //
+ auto pi (postponed_deps.find (pk));
+ if (pi != postponed_deps.end ())
+ {
+ l5 ([&]{trace << "skip dep-postponed existing dependent "
+ << pk << " of dependency " << p;});
+
+ // Note that here we would re-evaluate the existing dependent
+ // without specifying any configuration for it.
+ //
+ pi->second.wout_config = true;
+
+ continue;
+ }
+
+ auto i (dependents.find (pk));
+ size_t di (ed.dependency_position.first);
+
+ // Skip re-evaluated dependent if the dependency index is
+ // greater than the one we have already re-evaluated to. If it
+ // is earlier, then add the entry to postponed_poss and throw
+ // postpone_position to recollect from scratch. Note that this
+ // entry in postponed_poss is with replacement.
+ //
+ if (i != dependents.end () && i->second.reevaluated)
+ {
+ size_t ci (i->second.dependency_position.first);
+
+ if (di > ci)
+ continue;
+
+ // The newly-introduced dependency must belong to the
+ // depends value other then the one we have re-evaluated to.
+ //
+ assert (di < ci);
+
+ postponed_position pp (ed.dependency_position,
+ true /* replace */);
+
+ auto p (postponed_poss.emplace (pk, pp));
+
+ if (!p.second)
+ {
+ assert (p.first->second > pp);
+ p.first->second = pp;
+ }
+
+ l5 ([&]{trace << "cannot re-evaluate dependent "
+ << pk << " to dependency index " << di
+ << " since it is already re-evaluated to "
+ << "greater index " << ci << " in " << *pcfg
+ << ", throwing postpone_position";});
+
+ throw postpone_position ();
+ }
+
+ // If the existing dependent is not in the map yet, then add
+ // it. Otherwise, if the dependency position is greater than
+ // that one in the existing map entry then skip it (this
+ // position will be up-negotiated, if it's still present).
+ // Otherwise, if the position is less then overwrite the
+ // existing entry. Otherwise (the position is equal), just
+ // add the dependency to the existing entry.
+ //
+ // Note that we want to re-evaluate the dependent up to the
+ // earliest dependency position and continue with the regular
+ // prerequisites collection (as we do for new dependents)
+ // afterwards.
+ //
+ if (i == dependents.end ())
+ {
+ i = dependents.emplace (
+ move (pk), existing_dependent_ex (move (ed))).first;
+ }
+ else
+ {
+ size_t ci (i->second.dependency_position.first);
+
+ if (ci < di)
+ continue;
+ else if (ci > di)
+ i->second = existing_dependent_ex (move (ed));
+ //else if (ci == di)
+ // ;
+ }
+
+ i->second.dependencies.push_back (p);
+ }
+ }
+
+ // Re-evaluate the newly added existing dependents, if any.
+ //
+ if (dependents.size () != n)
+ {
+ l5 ([&]{trace << "re-evaluate existing dependents for " << *pcfg;});
+
+ for (auto& d: dependents)
+ {
+ existing_dependent_ex& ed (d.second);
+
+ // Skip re-evaluated.
+ //
+ if (ed.reevaluated)
+ continue;
+
+ size_t di (ed.dependency_position.first);
+ const package_key& pk (d.first);
+
+ // Check if there is an earlier dependency position for this
+ // dependent that will be participating in a configuration
+ // negotiation and skip this cluster if that's the case. There
+ // are two places to check: postponed_poss and other clusters.
+ //
+ auto pi (postponed_poss.find (pk));
+ if (pi != postponed_poss.end () && pi->second.first < di)
+ {
+ l5 ([&]{trace << "pos-postpone existing dependent "
+ << pk << " re-evaluation to dependency "
+ << "index " << di << " due to recorded index "
+ << pi->second.first << ", skipping " << *pcfg;});
+
+ pi->second.skipped = true;
+
+ // If requested, override the first encountered non-replace
+ // position to replace (see below for details).
+ //
+ if (!pi->second.replace && postponed_poss.replace)
+ {
+ pi->second.replace = true;
+ postponed_poss.replace = false;
+ }
+
+ if (pi->second.replace)
+ throw skip_configuration (move (ed), pi->second);
+ else
+ throw skip_configuration ();
+ }
+
+ // The other clusters check is a bit more complicated: if the
+ // other cluster (with the earlier position) is not yet
+ // negotiated, then we skip. Otherwise, we have to add an
+ // entry to postponed_poss and backtrack.
+ //
+ bool skip (false);
+ for (const postponed_configuration& cfg: postponed_cfgs)
+ {
+ // Skip the current cluster.
+ //
+ if (&cfg == pcfg)
+ continue;
+
+ if (const pair<size_t, size_t>* p =
+ cfg.existing_dependent_position (pk))
+ {
+ size_t ei (p->first); // Other position.
+
+ if (!cfg.negotiated)
+ {
+ if (ei < di)
+ {
+ l5 ([&]{trace << "cannot re-evaluate dependent "
+ << pk << " to dependency index " << di
+ << " due to earlier dependency index "
+ << ei << " in " << cfg << ", skipping "
+ << *pcfg;});
+
+ skip = true;
+ }
+ }
+ else
+ {
+ // If this were not the case, then this dependent
+ // wouldn't have been considered as an existing by
+ // query_existing_dependents() since as it is (being)
+ // negotiated then it is already re-evaluated and so is
+ // being built (see the verify lambda above).
+ //
+ assert (ei > di);
+
+ // Feels like there cannot be an earlier position.
+ //
+ postponed_position pp (ed.dependency_position,
+ false /* replace */);
+
+ auto p (postponed_poss.emplace (pk, pp));
+ if (!p.second)
+ {
+ assert (p.first->second > pp);
+ p.first->second = pp;
+ }
+
+ l5 ([&]{trace << "cannot re-evaluate dependent "
+ << pk << " to dependency index " << di
+ << " due to greater dependency "
+ << "index " << ei << " in " << cfg
+ << ", throwing postpone_position";});
+
+ throw postpone_position ();
+ }
+ }
+ }
+
+ if (skip)
+ throw skip_configuration ();
+
+ // Finally, re-evaluate the dependent.
+ //
+ packages& ds (ed.dependencies);
+
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> rp (
+ find_available_fragment (o, pk.db, ed.selected));
+
+ build_package p {
+ build_package::build,
+ pk.db,
+ move (ed.selected),
+ move (rp.first),
+ move (rp.second),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ false, // System.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ set<package_key> ( // Required by (dependency).
+ ds.begin (), ds.end ()),
+ false, // Required by dependents.
+ build_package::adjust_reconfigure};
+
+ // Note: not recursive.
+ //
+ collect_build (o,
+ move (p),
+ fdb,
+ rpt_depts,
+ apc,
+ false /* initial_collection */,
+ replaced_vers,
+ postponed_cfgs);
+
+ build_package* b (entered_build (pk));
+ assert (b != nullptr);
+
+ // Re-evaluate up to the earliest position.
+ //
+ assert (ed.dependency_position.first != 0);
+
+ build_package_refs dep_chain;
+ collect_build_prerequisites (o,
+ *b,
+ fdb,
+ rpt_depts,
+ apc,
+ false /* initial_collection */,
+ replaced_vers,
+ dep_chain,
+ &postponed_repo,
+ &postponed_alts,
+ numeric_limits<size_t>::max (),
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss,
+ ed.dependency_position);
+
+ ed.reevaluated = true;
+
+ if (pi != postponed_poss.end ())
+ {
+ // Otherwise we should have thrown skip_configuration above.
+ //
+ assert (di <= pi->second.first);
+
+ pi->second.reevaluated = true;
+ }
+ }
+ }
+ }
+ }
+
+ l5 ([&]{trace << "cfg-negotiate begin " << *pcfg;});
+
+ // Negotiate the configuration.
+ //
+ // The overall plan is as follows: continue refining the configuration
+ // until there are no more changes by giving each dependent a chance
+ // to make further adjustments.
+ //
+ for (auto b (pcfg->dependents.begin ()),
+ i (b),
+ e (pcfg->dependents.end ()); i != e; )
+ {
+ // Resolve package skeletons for the dependent and its dependencies.
+ //
+ // For the dependent, the skeleton should be already there (since we
+ // should have started recursively collecting it). For a dependency,
+ // it should not already be there (since we haven't yet started
+ // recursively collecting it). But we could be re-resolving the same
+ // dependency multiple times.
+ //
+ package_skeleton* dept;
+ {
+ build_package* b (entered_build (i->first));
+ assert (b != nullptr && b->skeleton);
+ dept = &*b->skeleton;
+ }
+
+ pair<size_t, size_t> pos;
+ small_vector<reference_wrapper<package_skeleton>, 1> depcs;
+ {
+ // A non-negotiated cluster must only have one depends position
+ // for each dependent.
+ //
+ assert (i->second.dependencies.size () == 1);
+
+ const postponed_configuration::dependency& ds (
+ i->second.dependencies.front ());
+
+ pos = ds.position;
+
+ depcs.reserve (ds.size ());
+ for (const package_key& pk: ds)
+ {
+ build_package* b (entered_build (pk));
+ assert (b != nullptr);
+
+ depcs.push_back (b->skeleton
+ ? *b->skeleton
+ : b->init_skeleton (o /* options */));
+ }
+ }
+
+ if (negotiate_configuration (
+ pcfg->dependency_configurations, *dept, pos, depcs))
+ {
+ if (i != b)
+ {
+ i = b; // Restart from the beginning.
+ continue;
+ }
+ }
+
+ ++i;
+ }
+
+ // Being negotiated (so can only be up-negotiated).
+ //
+ pcfg->negotiated = false;
+
+ // Note that we can be adding new packages to the being negotiated
+ // cluster by calling collect_build_prerequisites() for its
+ // dependencies and dependents. Thus, we need to stash the current
+ // list of dependencies and dependents and iterate over them.
+ //
+ // Note that whomever is adding new packages is expected to process
+ // them (they may also process existing packages, which we are
+ // prepared to ignore).
+ //
+ packages dependencies (pcfg->dependencies);
+
+ packages dependents;
+ dependents.reserve (pcfg->dependents.size ());
+
+ for (const auto& p: pcfg->dependents)
+ dependents.push_back (p.first);
+
+ // Process dependencies recursively with this config.
+ //
+ // Note that there could be inter-dependecies between these packages,
+ // which means the configuration can only be up-negotiated.
+ //
+ l5 ([&]{trace << "recursively collect cfg-negotiated dependencies";});
+
+ for (const package_key& p: dependencies)
+ {
+ build_package* b (entered_build (p));
+ assert (b != nullptr);
+
+ // Reconfigure the configured dependencies.
+ //
+ // Note that potentially this can be an overkill if the dependency
+ // configuration doesn't really change. Later we can implement some
+ // precise detection for that using configuration checksum or
+ // similar.
+ //
+ // Also note that for configured dependents which belong to the
+ // configuration cluster this flag is already set (see above).
+ //
+ if (b->selected != nullptr &&
+ b->selected->state == package_state::configured)
+ b->flags |= build_package::adjust_reconfigure;
+
+ // Skip the dependencies which are already collected recursively.
+ //
+ if (!b->recursive_collection)
+ {
+ // Verify and set the dependent configuration for this dependency.
+ //
+ // Note: see similar code for the up-negotiation case.
+ //
+ {
+ assert (b->skeleton); // Should have been init'ed above.
+
+ const package_configuration& pc (
+ pcfg->dependency_configurations[p]);
+
+ // Skip the verification if this is a system package
+ // without skeleton info.
+ //
+ pair<bool, string> pr (b->skeleton->available != nullptr
+ ? b->skeleton->verify_sensible (pc)
+ : make_pair (true, string ()));
+
+ if (!pr.first)
+ {
+ // Note that the diagnostics from the dependency will most
+ // likely be in the "error ..." form (potentially with
+ // additional info lines) and by printing it with a two-space
+ // indentation we make it "fit" into our diag record.
+ //
+ diag_record dr (fail);
+ dr << "unable to negotiate sensible configuration for "
+ << "dependency " << p << '\n'
+ << " " << pr.second;
+
+ dr << info << "negotiated configuration:\n";
+ pc.print (dr, " "); // Note 4 spaces since in nested info.
+ }
+
+ b->skeleton->dependent_config (pc);
+ }
+
+ build_package_refs dep_chain;
+ collect_build_prerequisites (o,
+ *b,
+ fdb,
+ rpt_depts,
+ apc,
+ false /* initial_collection */,
+ replaced_vers,
+ dep_chain,
+ &postponed_repo,
+ &postponed_alts,
+ 0 /* max_alt_index */,
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
+ }
+ else
+ l5 ([&]{trace << "dependency " << b->available_name_version_db ()
+ << " is already (being) recursively collected, "
+ << "skipping";});
+ }
+
+ // Continue processing dependents with this config.
+ //
+ l5 ([&]{trace << "recursively collect cfg-negotiated dependents";});
+
+ for (const auto& p: dependents)
+ {
+ // Select the dependency alternative for which configuration has
+ // been negotiated and collect this dependent starting from the next
+ // depends value.
+ //
+ build_package* b (entered_build (p));
+
+ // We should have been started recursively collecting the dependent
+ // and it should have been postponed.
+ //
+ assert (b != nullptr &&
+ b->available != nullptr &&
+ b->dependencies &&
+ b->skeleton &&
+ b->postponed_dependency_alternatives);
+
+ // Select the dependency alternative (evaluate reflect if present,
+ // etc) and position to the next depends value (see
+ // collect_build_prerequisites() for details).
+ //
+ {
+ const bpkg::dependencies& deps (b->available->dependencies);
+ bpkg::dependencies& sdeps (*b->dependencies);
+ vector<size_t>& salts (*b->alternatives);
+
+ size_t di (sdeps.size ());
+
+ // Skip the dependent if it has been already collected as some
+ // package's dependency or some such.
+ //
+ if (di == deps.size ())
+ {
+ l5 ([&]{trace << "dependent " << b->available_name_version_db ()
+ << " is already recursively collected, skipping";});
+
+ continue;
+ }
+
+ l5 ([&]{trace << "select cfg-negotiated dependency alternative "
+ << "for dependent "
+ << b->available_name_version_db ();});
+
+ // Find the postponed dependency alternative.
+ //
+ auto i (pcfg->dependents.find (p));
+
+ assert (i != pcfg->dependents.end () &&
+ i->second.dependencies.size () == 1);
+
+ pair<size_t, size_t> dp (i->second.dependencies[0].position);
+ assert (dp.first == sdeps.size () + 1);
+
+ build_package::dependency_alternatives_refs pdas (
+ move (*b->postponed_dependency_alternatives));
+
+ b->postponed_dependency_alternatives = nullopt;
+
+ auto j (find_if (pdas.begin (), pdas.end (),
+ [&dp] (const auto& da)
+ {
+ return da.second + 1 == dp.second;
+ }));
+
+ assert (j != pdas.end ());
+
+ const dependency_alternative& da (j->first);
+ size_t dai (j->second);
+
+ // Select the dependency alternative and position to the next
+ // depends value.
+ //
+ const dependency_alternatives_ex& das (deps[di]);
+ dependency_alternatives_ex sdas (das.buildtime, das.comment);
+
+ sdas.emplace_back (nullopt /* enable */,
+ nullopt /* reflect */,
+ da.prefer,
+ da.accept,
+ da.require,
+ da /* dependencies */);
+
+ sdeps.push_back (move (sdas));
+ salts.push_back (dai);
+
+ // Evaluate reflect, if present.
+ //
+ if (da.reflect)
+ b->skeleton->evaluate_reflect (*da.reflect, make_pair (di, dai));
+ }
+
+ // Continue recursively collecting the dependent.
+ //
+ build_package_refs dep_chain;
+
+ collect_build_prerequisites (
+ o,
+ *b,
+ fdb,
+ rpt_depts,
+ apc,
+ false /* initial_collection */,
+ replaced_vers,
+ dep_chain,
+ &postponed_repo,
+ &postponed_alts,
+ 0 /* max_alt_index */,
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
+ }
+
+ // Negotiated (so can only be rolled back).
+ //
+ pcfg->negotiated = true;
+
+ l5 ([&]{trace << "cfg-negotiate end " << *pcfg;});
+
+ // Fall through (to start another iteration of the below loop).
+ }
+
// Try collecting postponed packages for as long as we are making
// progress.
//
vector<build_package*> spas; // Reuse.
- for (bool prog (!postponed_repo.empty () || !postponed_alts.empty ());
+ for (bool prog (!postponed_repo.empty () ||
+ !postponed_cfgs.negotiated () ||
+ !postponed_alts.empty () ||
+ postponed_deps.has_bogus ());
prog; )
{
postponed_packages prs;
@@ -2808,6 +6171,9 @@ namespace bpkg
//
for (build_package* p: postponed_repo)
{
+ l5 ([&]{trace << "collect rep-postponed "
+ << p->available_name_version_db ();});
+
build_package_refs dep_chain;
collect_build_prerequisites (o,
@@ -2815,13 +6181,18 @@ namespace bpkg
fdb,
rpt_depts,
apc,
+ false /* initial_collection */,
+ replaced_vers,
+ dep_chain,
&prs,
&pas,
0 /* max_alt_index */,
- dep_chain);
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
}
- // Save the potential new dependency alternative-related postpones.
+ // Save the potential new dependency alternative-related postponements.
//
postponed_alts.insert (pas.begin (), pas.end ());
@@ -2834,12 +6205,260 @@ namespace bpkg
}
// Now, as there is no more progress made in collecting repository-
- // related postpones, try to collect the dependency alternative-
- // related postpones.
+ // related postponements, collect the dependency configuration-related
+ // postponements.
+ //
+ // Note that we do it before alternatives since configurations we do
+ // perfectly (via backtracking) while alternatives -- heuristically.
+ //
+ // Note that since the potential snapshot restore replaces all the
+ // list entries we cannot iterate using the iterator here. Also note
+ // that the list size may change during iterating.
+ //
+ for (size_t ci (0); ci != postponed_cfgs.size (); ++ci)
+ {
+ postponed_configuration* pc (&postponed_cfgs[ci]);
+
+ // Find the next configuration to try to negotiate, skipping the
+ // already negotiated ones.
+ //
+ if (pc->negotiated)
+ continue;
+
+ size_t pcd (depth + 1);
+ pc->depth = pcd;
+
+ // Either return or retry the same cluster or skip this cluster and
+ // proceed to the next one.
+ //
+ for (;;)
+ {
+ // First assume we can negotiate this configuration rolling back
+ // if this doesn't pan out.
+ //
+ snapshot s (*this,
+ postponed_repo,
+ postponed_alts,
+ postponed_deps,
+ postponed_cfgs);
+
+ try
+ {
+ collect_build_postponed (o,
+ replaced_vers,
+ postponed_repo,
+ postponed_alts,
+ postponed_deps,
+ postponed_cfgs,
+ postponed_cfgs_history,
+ postponed_poss,
+ fdb,
+ rpt_depts,
+ apc,
+ pc);
+
+ // If collect() returns (instead of throwing), this means it
+ // processed everything that was postponed.
+ //
+ assert (postponed_repo.empty () &&
+ postponed_cfgs.negotiated () &&
+ postponed_alts.empty () &&
+ !postponed_deps.has_bogus ());
+
+ l5 ([&]{trace << "end" << trace_suffix;});
+
+ return;
+ }
+ catch (skip_configuration& e)
+ {
+ // Restore the state from snapshot.
+ //
+ // Note: postponed_cfgs is re-assigned.
+ //
+ s.restore (*this,
+ postponed_repo,
+ postponed_alts,
+ postponed_deps,
+ postponed_cfgs);
+
+ pc = &postponed_cfgs[ci];
+
+ // Note that in this case we keep the accumulated configuration,
+ // if any.
+
+ pc->depth = 0;
+
+ // If requested, "replace" the "later" dependent-dependency
+ // cluster with an earlier.
+ //
+ if (e.dependent)
+ {
+ existing_dependent& ed (*e.dependent);
+ pair<size_t, size_t> pos (e.new_position);
+
+ const build_package* bp (
+ replace_existing_dependent_dependency (
+ trace,
+ o,
+ ed, // Note: modified.
+ pos,
+ fdb,
+ rpt_depts,
+ apc,
+ false /* initial_collection */,
+ replaced_vers,
+ postponed_cfgs));
+
+ postponed_cfgs.add (package_key (ed.db, ed.selected->name),
+ pos,
+ package_key (bp->db, bp->selected->name));
+ }
+
+ l5 ([&]{trace << "postpone cfg-negotiation of " << *pc;});
+
+ break;
+ }
+ catch (const retry_configuration& e)
+ {
+ // If this is not "our problem", then keep looking.
+ //
+ if (e.depth != pcd)
+ throw;
+
+ package_configurations cfgs (
+ move (pc->dependency_configurations));
+
+ // Restore the state from snapshot.
+ //
+ // Note: postponed_cfgs is re-assigned.
+ //
+ s.restore (*this,
+ postponed_repo,
+ postponed_alts,
+ postponed_deps,
+ postponed_cfgs);
+
+ pc = &postponed_cfgs[ci];
+
+ l5 ([&]{trace << "cfg-negotiation of " << *pc << " failed due "
+ << "to dependent " << e.dependent << ", refining "
+ << "configuration";});
+
+ // Copy over the configuration for further refinement.
+ //
+ // Note that there is also a possibility of ending up with
+ // "bogus" configuration variables that were set by a dependent
+ // during up-negotiation but, due to changes to the overall
+ // configuration, such a dependent were never re-visited.
+ //
+ // The way we are going to deal with this is by detecting such
+ // bogus variables based on the confirmed flag, cleaning them
+ // out, and doing another retry. Here we clear the confirmed
+ // flag and the detection happens in collect_build_postponed()
+ // after we have processed everything postponed (since that's
+ // the only time we can be certain there could no longer be a
+ // re-visit).
+ //
+ for (package_configuration& cfg: cfgs)
+ for (config_variable_value& v: cfg)
+ if (v.dependent)
+ v.confirmed = false;
+
+ pc->dependency_configurations = move (cfgs);
+ }
+ catch (merge_configuration& e)
+ {
+ // If this is not "our problem", then keep looking.
+ //
+ if (e.depth != pcd)
+ throw;
+
+ postponed_configuration shadow (move (*pc));
+
+ // Restore the state from snapshot.
+ //
+ // Note: postponed_cfgs is re-assigned.
+ //
+ s.restore (*this,
+ postponed_repo,
+ postponed_alts,
+ postponed_deps,
+ postponed_cfgs);
+
+ pc = &postponed_cfgs[ci];
+
+ assert (!pc->negotiated);
+
+ // Drop any accumulated configuration (which could be carried
+ // over from retry_configuration logic).
+ //
+ pc->dependency_configurations.clear ();
+
+ l5 ([&]{trace << "cfg-negotiation of " << *pc << " failed due "
+ << "to non-negotiated clusters, force-merging "
+ << "based on shadow cluster " << shadow;});
+
+ // Pre-merge into this cluster those non-negotiated clusters
+ // which were merged into the shadow cluster.
+ //
+ for (size_t id: shadow.merged_ids)
+ {
+ postponed_configuration* c (postponed_cfgs.find (id));
+
+ if (c != nullptr)
+ {
+ // Otherwise we would be handling the exception in the
+ // higher stack frame.
+ //
+ assert (!c->negotiated);
+
+ l5 ([&]{trace << "force-merge " << *c << " into " << *pc;});
+
+ pc->merge (move (*c));
+
+ // Mark configuration as the one being merged from for
+ // subsequent erasing from the list.
+ //
+ c->dependencies.clear ();
+ }
+ }
+
+ // Erase clusters which we have merged from. Also re-translate
+ // the current cluster address into index which may change as a
+ // result of the merge.
+ //
+ auto i (postponed_cfgs.begin ());
+ auto j (postponed_cfgs.before_begin ()); // Precedes iterator i.
+
+ for (size_t k (0); i != postponed_cfgs.end (); )
+ {
+ if (!i->dependencies.empty ())
+ {
+ if (&*i == pc)
+ ci = k;
+
+ ++i;
+ ++j;
+ ++k;
+ }
+ else
+ i = postponed_cfgs.erase_after (j);
+ }
+
+ pc->set_shadow_cluster (move (shadow));
+ }
+ }
+ }
+
+ // Note that we only get here if we didn't make any progress on the
+ // previous loop (the only "progress" path ends with return).
+
+ // Now, try to collect the dependency alternative-related
+ // postponements.
//
if (!postponed_alts.empty ())
{
- // Sort the postpones in the unprocessed dependencies count
+ // Sort the postponments in the unprocessed dependencies count
// descending order.
//
// The idea here is to preferably handle those postponed packages
@@ -2901,19 +6520,28 @@ namespace bpkg
build_package_refs dep_chain;
+ l5 ([&]{trace << "index " << i << " collect alt-postponed "
+ << p->available_name_version_db ();});
+
collect_build_prerequisites (o,
*p,
fdb,
rpt_depts,
apc,
+ false /* initial_collection */,
+ replaced_vers,
+ dep_chain,
&prs,
&pas,
i,
- dep_chain);
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
- prog = (ndep != p->dependencies->size ());
+ prog = (pas.find (p) == pas.end () ||
+ ndep != p->dependencies->size ());
- // Save the potential new postpones.
+ // Save the potential new postponements.
//
if (prog)
{
@@ -2924,9 +6552,14 @@ namespace bpkg
size_t npr (postponed_repo.size ());
postponed_repo.insert (prs.begin (), prs.end ());
- // Note that not collecting any alternative-relative postpones
- // but producing new repository-related postpones is progress
- // nevertheless.
+ // Note that not collecting any alternative-relative
+ // postponements but producing new repository-related
+ // postponements is progress nevertheless.
+ //
+ // Note that we don't need to check for new configuration-
+ // related postponements here since if they are present, then
+ // this package wouldn't be in pas and so prog would be true
+ // (see above for details).
//
if (!prog)
prog = (npr != postponed_repo.size ());
@@ -2935,10 +6568,194 @@ namespace bpkg
break;
}
}
+
+ if (prog)
+ continue;
+ }
+
+ assert (!prog);
+
+ // If we still have any non-negotiated clusters and non-replace
+ // postponed positions, then it's possible one of them is the cross-
+ // dependent pathological case where we will never hit it unless we
+ // force the re-evaluation to earlier position (similar to the
+ // single-dependent case, which we handle accurately). For example:
+ //
+ // tex: depends: libbar(c)
+ // depends: libfoo(c)
+ //
+ // tix: depends: libbar(c)
+ // depends: tex(c)
+ //
+ // Here tex and tix are existing dependent and we are upgrading tex.
+ //
+ // While it would be ideal to handle such cases accurately, it's not
+ // trivial. So for now we resort to the following heuristics: when
+ // left with no other option, we treat the first encountered non-
+ // replace position as replace and see if that helps move things
+ // forward.
+ //
+ if (!postponed_cfgs.negotiated () &&
+ find_if (postponed_poss.begin (), postponed_poss.end (),
+ [] (const auto& v) {return !v.second.replace;}) !=
+ postponed_poss.end () &&
+ !postponed_poss.replace)
+ {
+ l5 ([&]{trace << "non-negotiated clusters left and non-replace "
+ << "postponed positions are present, overriding first "
+ << "encountered non-replace position to replace";});
+
+ postponed_poss.replace = true;
+ prog = true;
+ continue; // Go back to negotiating skipped cluster.
+ }
+
+ // Finally, erase the bogus postponements and re-collect from scratch,
+ // if any (see postponed_dependencies for details).
+ //
+ // Note that we used to re-collect such postponements in-place but
+ // re-doing from scratch feels more correct (i.e., we may end up doing
+ // it earlier which will affect dependency alternatives).
+ //
+ postponed_deps.cancel_bogus (trace, false /* initial_collection */);
+ }
+
+ // Check if any negotiatiated configurations ended up with any bogus
+ // variables (see retry_configuration catch block for background).
+ //
+ // Note that we could potentially end up yo-yo'ing: we remove a bogus
+ // and that causes the original dependent to get re-visited which in
+ // turn re-introduces the bogus. In other words, one of the bogus
+ // variables which we have removed are actually the cause of no longer
+ // needing the dependent that introduced it. Feels like the correct
+ // outcome of this should be keeping the bogus variable that triggered
+ // yo-yo'ing. Of course, there could be some that we should keep and
+ // some that we should drop and figuring this out would require retrying
+ // all possible combinations. An alternative solution would be to detect
+ // yo-yo'ing, print the bogus variables involved, and ask the user to
+ // choose (with an override) which ones to keep. Let's go with this for
+ // now.
+ //
+ {
+ // On the first pass see if we have anything bogus.
+ //
+ bool bogus (false);
+ for (postponed_configuration& pcfg: postponed_cfgs)
+ {
+ if (pcfg.negotiated && *pcfg.negotiated) // Negotiated.
+ {
+ for (package_configuration& cfg: pcfg.dependency_configurations)
+ {
+ for (config_variable_value& v: cfg)
+ {
+ if (v.dependent && !v.confirmed)
+ {
+ bogus = true;
+ break;
+ }
+ }
+ if (bogus) break;
+ }
+ if (bogus) break;
+ }
+ }
+
+ if (bogus)
+ {
+ // On the second pass calculate the checksum of all the negotiated
+ // clusters.
+ //
+ sha256 cs;
+ for (postponed_configuration& pcfg: postponed_cfgs)
+ {
+ if (pcfg.negotiated && *pcfg.negotiated)
+ {
+ for (package_configuration& cfg: pcfg.dependency_configurations)
+ {
+ for (config_variable_value& v: cfg)
+ {
+ if (v.dependent)
+ to_checksum (cs, v);
+ }
+ }
+ }
+ }
+
+ bool cycle;
+ {
+ string s (cs.string ());
+ if (find (postponed_cfgs_history.begin (),
+ postponed_cfgs_history.end (),
+ s) == postponed_cfgs_history.end ())
+ {
+ postponed_cfgs_history.push_back (move (s));
+ cycle = false;
+ }
+ else
+ cycle = true;
+ }
+
+ // On the third pass we either retry or diagnose.
+ //
+ diag_record dr;
+ if (cycle)
+ {
+ dr <<
+ fail << "unable to remove bogus configuration values without "
+ << "causing configuration refinement cycle" <<
+ info << "consider manually specifying one or more of the "
+ << "following variables as user configuration";
+ }
+
+ for (postponed_configuration& pcfg: postponed_cfgs)
+ {
+ optional<package_key> dept; // Bogus dependent.
+
+ if (pcfg.negotiated && *pcfg.negotiated)
+ {
+ for (package_configuration& cfg: pcfg.dependency_configurations)
+ {
+ // Note that the entire dependency configuration may end up
+ // being "bogus" (i.e., it does not contain any configuration
+ // variables with a confirmed dependent). But that will be
+ // handled naturally: we will either no longer have this
+ // dependency in the cluster and thus never call its
+ // skeleton's dependent_config() or this call will be no-op
+ // since it won't find any dependent variables.
+ //
+ for (config_variable_value& v: cfg)
+ {
+ if (v.dependent && !v.confirmed)
+ {
+ if (!dept)
+ dept = move (v.dependent);
+
+ if (cycle)
+ dr << "\n " << v.serialize_cmdline ();
+ else
+ v.undefine ();
+ }
+ }
+ }
+
+ if (dept)
+ {
+ if (cycle)
+ break;
+ else
+ throw retry_configuration {pcfg.depth, move (*dept)};
+ }
+ }
+
+ if (dept)
+ break;
+ }
}
}
- // If any postponed builds remained, then perform the diagnostics run.
+ // If any postponed_{repo,alts} builds remained, then perform the
+ // diagnostics run. Naturally we shouldn't have any postponed_cfgs
+ // without one of the former.
//
if (!postponed_repo.empty ())
{
@@ -2949,10 +6766,15 @@ namespace bpkg
fdb,
rpt_depts,
apc,
+ false /* initial_collection */,
+ replaced_vers,
+ dep_chain,
nullptr,
nullptr,
0,
- dep_chain);
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
assert (false); // Can't be here.
}
@@ -2966,13 +6788,35 @@ namespace bpkg
fdb,
rpt_depts,
apc,
+ false /* initial_collection */,
+ replaced_vers,
+ dep_chain,
nullptr,
nullptr,
0,
- dep_chain);
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
assert (false); // Can't be here.
}
+
+ // While the assumption is that we shouldn't leave any non-negotiated
+ // clusters, we can potentially miss some corner cases in the above
+ // "skip configuration" logic. Let's thus trace the non-negotiated
+ // clusters before the assertion.
+ //
+#ifndef NDEBUG
+ for (const postponed_configuration& cfg: postponed_cfgs)
+ {
+ if (!cfg.negotiated || !*cfg.negotiated)
+ trace << "unexpected non-negotiated cluster " << cfg;
+ }
+
+ assert (postponed_cfgs.negotiated ());
+#endif
+
+ l5 ([&]{trace << "end" << trace_suffix;});
}
// Order the previously-collected package with the specified name
@@ -2982,7 +6826,7 @@ namespace bpkg
// only the specified configuration. Otherwise, treat the package as a
// dependency and use the custom search function to find its build
// configuration. Failed that, search for it recursively (see
- // config_package_map::find_dependency() for details).
+ // package_map::find_dependency() for details).
//
// Recursively order the package dependencies being ordered failing if a
// dependency cycle is detected. If reorder is true, then reorder this
@@ -2995,7 +6839,7 @@ namespace bpkg
const function<find_database_function>& fdb,
bool reorder = true)
{
- config_package_names chain;
+ package_refs chain;
return order (db, name, buildtime, chain, fdb, reorder);
}
@@ -3070,8 +6914,8 @@ namespace bpkg
auto i (map_.find (ddb, dn));
// Make sure the up/downgraded package still satisfies this
- // dependent. But first "prune" if this is a replaced prerequisite
- // of the repointed dependent.
+ // dependent. But first "prune" if the dependent is being dropped or
+ // this is a replaced prerequisite of the repointed dependent.
//
// Note that the repointed dependents are always collected and have
// all their collected prerequisites ordered (including new and old
@@ -3081,37 +6925,34 @@ namespace bpkg
if (i != map_.end () && i->second.position != end ())
{
+ build_package& dp (i->second.package);
+
+ // Skip the droped dependent.
+ //
+ if (dp.action && *dp.action == build_package::drop)
+ continue;
+
repointed_dependents::const_iterator j (
- rpt_depts.find (config_package {ddb, dn}));
+ rpt_depts.find (package_key {ddb, dn}));
if (j != rpt_depts.end ())
{
- const map<config_package, bool>& prereqs_flags (j->second);
+ const map<package_key, bool>& prereqs_flags (j->second);
- auto k (prereqs_flags.find (config_package {pdb, n}));
+ auto k (prereqs_flags.find (package_key {pdb, n}));
if (k != prereqs_flags.end () && !k->second)
continue;
}
- build_package& dp (i->second.package);
- const shared_ptr<selected_package>& dsp (dp.selected);
-
// There is one tricky aspect: the dependent could be in the
- // process of being up/downgraded as well. In this case all we
- // need to do is detect this situation and skip the test since all
- // the (new) contraints of this package have been satisfied in
- // collect_build().
+ // process of being reconfigured or up/downgraded as well. In this
+ // case all we need to do is detect this situation and skip the
+ // test since all the (new) constraints of this package have been
+ // satisfied in collect_build().
//
if (check)
- {
- check = dp.available == nullptr ||
- (dsp->system () == dp.system &&
- dsp->version == dp.available_version () &&
- (dp.system ||
- dp.config_vars.empty () ||
- !has_buildfile_clause (dp.available->dependencies)));
- }
+ check = !dp.dependencies;
}
if (check)
@@ -3140,8 +6981,8 @@ namespace bpkg
string rb;
if (!p.user_selection ())
{
- for (const config_package& cp: p.required_by)
- rb += (rb.empty () ? " " : ", ") + cp.string ();
+ for (const package_key& pk: p.required_by)
+ rb += (rb.empty () ? " " : ", ") + pk.string ();
}
if (!rb.empty ())
@@ -3164,7 +7005,9 @@ namespace bpkg
{
shared_ptr<selected_package> dsp (ddb.load<selected_package> (dn));
- bool system (dsp->system ()); // Save before the move(dsp) call.
+ // A system package cannot be a dependent.
+ //
+ assert (!dsp->system ());
return build_package {
build_package::adjust,
@@ -3173,19 +7016,21 @@ namespace bpkg
nullptr, // No available pkg/repo fragment.
nullptr,
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
nullopt, // Hold package.
nullopt, // Hold version.
{}, // Constraints.
- system,
+ false, // System.
false, // Keep output directory.
false, // Disfigure (from-scratch reconf).
false, // Configure-only.
nullopt, // Checkout root.
false, // Checkout purge.
strings (), // Configuration variables.
- {config_package {pdb, n}}, // Required by (dependency).
+ {package_key {pdb, n}}, // Required by (dependency).
false, // Required by dependents.
build_package::adjust_reconfigure};
};
@@ -3194,11 +7039,10 @@ namespace bpkg
// list, the package is in the map (but not on the list) and it
// is in neither.
//
- // If the existing entry is a drop, then we skip it. If it is
- // pre-entered, is an adjustment, or is a build that is not supposed
- // to be built (not in the list), then we merge it into the new
- // adjustment entry. Otherwise (is a build in the list), we just add
- // the reconfigure adjustment flag to it.
+ // If the existing entry is pre-entered, is an adjustment, or is a
+ // build that is not supposed to be built (not in the list), then we
+ // merge it into the new adjustment entry. Otherwise (is a build in
+ // the list), we just add the reconfigure adjustment flag to it.
//
if (i != map_.end ())
{
@@ -3209,11 +7053,6 @@ namespace bpkg
*dp.action != build_package::build || // Non-build.
dpos == end ()) // Build not in the list.
{
- // Skip the droped package.
- //
- if (dp.action && *dp.action == build_package::drop)
- continue;
-
build_package bp (adjustment ());
bp.merge (move (dp));
dp = move (bp);
@@ -3246,7 +7085,7 @@ namespace bpkg
{
// Don't move dn since it is used by adjustment().
//
- i = map_.emplace (config_package {ddb, dn},
+ i = map_.emplace (package_key {ddb, dn},
data_type {end (), adjustment ()}).first;
i->second.position = insert (pos, i->second.package);
@@ -3279,29 +7118,272 @@ namespace bpkg
p.second.position = end ();
}
+ // Verify that builds ordering is consistent across all the data
+ // structures and the ordering expectations are fulfilled (real build
+ // actions are all ordered, etc).
+ //
+ void
+ verify_ordering () const
+ {
+ for (const auto& b: map_)
+ {
+ const build_package& bp (b.second.package);
+
+ auto i (find_if (begin (), end (),
+ [&bp] (const build_package& p) {return &p == &bp;}));
+
+ // List ordering must properly be reflected in the tree entries.
+ //
+ assert (i == b.second.position);
+
+ // Pre-entered builds must never be ordered and the real build actions
+ // (builds, adjustments, etc) must all be ordered.
+ //
+ // Note that the later was not the case until we've implemented
+ // re-collection from scratch after the package version replacement
+ // (see replaced_versions for details). Before that the whole
+ // dependency trees from the being replaced dependent stayed in the
+ // map.
+ //
+ assert (bp.action.has_value () == (i != end ()));
+ }
+ }
+
+ private:
+ // Return the list of existing dependents that has a configuration clause
+ // for the specified dependency. Skip dependents which are being built and
+ // require recursive recollection or dropped (present in the map) or
+ // expected to be built or dropped (present in rpt_depts or replaced_vers).
+ //
+ // Optionally, specify the function which can verify the dependent build
+ // and decide whether to override the default behavior and still add the
+ // dependent package to the resulting list, returning true in this case.
+ //
+ struct existing_dependent
+ {
+ reference_wrapper<database> db;
+ shared_ptr<selected_package> selected;
+ pair<size_t, size_t> dependency_position;
+ };
+
+ using verify_dependent_build_function = bool (const package_key&,
+ pair<size_t, size_t>);
+
+ vector<existing_dependent>
+ query_existing_dependents (
+ tracer& trace,
+ database& db,
+ const package_name& name,
+ const replaced_versions& replaced_vers,
+ const repointed_dependents& rpt_depts,
+ const function<verify_dependent_build_function>& vdb = nullptr)
+ {
+ vector<existing_dependent> r;
+
+ lazy_shared_ptr<selected_package> sp (db, name);
+
+ for (database& ddb: db.dependent_configs ())
+ {
+ for (auto& pd: query_dependents (ddb, name, db))
+ {
+ shared_ptr<selected_package> dsp (
+ ddb.load<selected_package> (pd.name));
+
+ auto i (dsp->prerequisites.find (sp));
+ assert (i != dsp->prerequisites.end ());
+
+ const auto& pos (i->second.config_position);
+
+ if (pos.first != 0) // Has config clause?
+ {
+ package_key pk (ddb, pd.name);
+
+ if (rpt_depts.find (pk) != rpt_depts.end ())
+ {
+ l5 ([&]{trace << "skip repointed existing dependent " << pk
+ << " of dependency " << name << db;});
+ continue;
+ }
+
+ // Ignore dependent which is already being built or dropped.
+ //
+ const build_package* p (entered_build (pk));
+
+ if (p != nullptr && p->action)
+ {
+ bool build;
+ if (((build = *p->action == build_package::build) &&
+ (p->system || p->recollect_recursively (rpt_depts))) ||
+ *p->action == build_package::drop)
+ {
+ if (!build || !vdb || !vdb (pk, pos))
+ {
+ l5 ([&]{trace << "skip being "
+ << (build ? "built" : "dropped")
+ << " existing dependent " << pk
+ << " of dependency " << name << db;});
+ continue;
+ }
+ }
+ }
+
+ // Ignore dependent which is expected to be built or dropped.
+ //
+ auto vi (replaced_vers.find (pk));
+ if (vi != replaced_vers.end () && !vi->second.replaced)
+ {
+ bool build (vi->second.available != nullptr);
+
+ l5 ([&]{trace << "skip expected to be "
+ << (build ? "built" : "dropped")
+ << " existing dependent " << pk
+ << " of dependency " << name << db;});
+
+ continue;
+ }
+
+ r.push_back (existing_dependent {ddb, move (dsp), pos});
+ }
+ }
+ }
+
+ return r;
+ }
+
+ // Update the existing dependent object (previously obtained with the
+ // query_existing_dependents() call) with the new dependency position and
+ // collect the dependency referred by this position. Return the pointer to
+ // the collected build package object.
+ //
+ const build_package*
+ replace_existing_dependent_dependency (
+ tracer& trace,
+ const pkg_build_options& o,
+ existing_dependent& ed,
+ pair<size_t, size_t> pos,
+ const function<find_database_function>& fdb,
+ const repointed_dependents& rpt_depts,
+ const function<add_priv_cfg_function>& apc,
+ bool initial_collection,
+ replaced_versions& replaced_vers,
+ postponed_configurations& postponed_cfgs)
+ {
+ // The repointed dependent cannot be returned by
+ // query_existing_dependents(). Note that the repointed dependent
+ // references both old and new prerequisites.
+ //
+ assert (rpt_depts.find (package_key (ed.db, ed.selected->name)) ==
+ rpt_depts.end ());
+
+ shared_ptr<selected_package> dsp;
+ database* pdb (nullptr);
+ const version_constraint* vc (nullptr);
+
+ // Find the dependency for this earlier dependency position. We know
+ // it must be there since it's with configuration.
+ //
+ for (const auto& p: ed.selected->prerequisites)
+ {
+ if (p.second.config_position == pos)
+ {
+ pdb = &p.first.database ();
+
+ dsp = p.first.load ();
+
+ l5 ([&]{trace << "replace dependency at index "
+ << ed.dependency_position.first
+ << " of existing dependent " << *ed.selected
+ << ed.db << " with dependency " << *dsp
+ << *pdb << " at index " << pos.first;});
+
+ if (p.second.constraint)
+ vc = &*p.second.constraint;
+ }
+ }
+
+ assert (dsp != nullptr);
+
+ package_key pk (*pdb, dsp->name);
+
+ // Adjust the existing dependent entry.
+ //
+ ed.dependency_position = pos;
+
+ // Collect the package build for this dependency.
+ //
+ pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>> rp (
+ find_available_fragment (o, pk.db, dsp));
+
+ bool system (dsp->system ());
+
+ package_key dpk (ed.db, ed.selected->name);
+
+ build_package p {
+ build_package::build,
+ pk.db,
+ move (dsp),
+ move (rp.first),
+ move (rp.second),
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ system, // System.
+ false, // Keep output directory.
+ false, // Disfigure (from-scratch reconf).
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ {dpk}, // Required by (dependent).
+ true, // Required by dependents.
+ build_package::adjust_reconfigure};
+
+ if (vc != nullptr)
+ p.constraints.emplace_back (dpk.db, dpk.name.string (), *vc);
+
+ // Note: not recursive.
+ //
+ collect_build (o,
+ move (p),
+ fdb,
+ rpt_depts,
+ apc,
+ initial_collection,
+ replaced_vers,
+ postponed_cfgs);
+
+ return entered_build (pk);
+ }
+
private:
- struct config_package_name
+ struct package_ref
{
database& db;
const package_name& name;
bool
- operator== (const config_package_name& v)
+ operator== (const package_ref& v)
{
return name == v.name && db == v.db;
}
};
- using config_package_names = small_vector<config_package_name, 16>;
+ using package_refs = small_vector<package_ref, 16>;
iterator
order (database& db,
const package_name& name,
optional<bool> buildtime,
- config_package_names& chain,
+ package_refs& chain,
const function<find_database_function>& fdb,
bool reorder)
{
- config_package_map::iterator mi;
+ package_map::iterator mi;
if (buildtime)
{
@@ -3326,7 +7408,7 @@ namespace bpkg
// Make sure there is no dependency cycle.
//
- config_package_name cp {pdb, name};
+ package_ref cp {pdb, name};
{
auto i (find (chain.begin (), chain.end (), cp));
@@ -3335,7 +7417,7 @@ namespace bpkg
diag_record dr (fail);
dr << "dependency cycle detected involving package " << name << pdb;
- auto nv = [this] (const config_package_name& cp)
+ auto nv = [this] (const package_ref& cp)
{
auto mi (map_.find (cp.db, cp.name));
assert (mi != map_.end ());
@@ -3554,15 +7636,17 @@ namespace bpkg
build_package package;
};
- class config_package_map: public map<config_package, data_type>
+ class package_map: public map<package_key, data_type>
{
public:
- using base_type = map<config_package, data_type>;
+ using base_type = map<package_key, data_type>;
+
+ using base_type::find;
iterator
find (database& db, const package_name& pn)
{
- return base_type::find (config_package {db, pn});
+ return find (package_key {db, pn});
}
// Try to find a package build in the dependency configurations (see
@@ -3587,7 +7671,7 @@ namespace bpkg
else
fail << "building package " << pn << " in multiple "
<< "configurations" <<
- info << r->first.db.config_orig <<
+ info << r->first.db.get().config_orig <<
info << ldb.config_orig <<
info << "use --config-* to select package configuration";
}
@@ -3596,7 +7680,7 @@ namespace bpkg
return r;
}
};
- config_package_map map_;
+ package_map map_;
};
// Return a patch version constraint for the selected package if it has a
@@ -3699,19 +7783,19 @@ namespace bpkg
bool system;
};
- struct config_package_dependent
+ struct dependent_constraint
{
database& db;
shared_ptr<selected_package> package;
optional<version_constraint> constraint;
- config_package_dependent (database& d,
- shared_ptr<selected_package> p,
- optional<version_constraint> c)
+ dependent_constraint (database& d,
+ shared_ptr<selected_package> p,
+ optional<version_constraint> c)
: db (d), package (move (p)), constraint (move (c)) {}
};
- using config_package_dependents = vector<config_package_dependent>;
+ using dependent_constraints = vector<dependent_constraint>;
static optional<evaluate_result>
evaluate_dependency (database&,
@@ -3723,7 +7807,7 @@ namespace bpkg
bool patch,
bool explicitly,
const config_repo_fragments&,
- const config_package_dependents&,
+ const dependent_constraints&,
bool ignore_unsatisfiable);
// If there are no user expectations regarding this dependency, then we give
@@ -3927,7 +8011,7 @@ namespace bpkg
// dependency.
//
config_repo_fragments repo_frags;
- config_package_dependents dependents;
+ dependent_constraints dpt_constrs;
for (auto& pd: pds)
{
@@ -3941,7 +8025,7 @@ namespace bpkg
available_package_id (p->name, p->version),
repo_frags);
- dependents.emplace_back (ddb, move (p), move (dep.constraint));
+ dpt_constrs.emplace_back (ddb, move (p), move (dep.constraint));
}
return evaluate_dependency (db,
@@ -3953,7 +8037,7 @@ namespace bpkg
i->patch,
true /* explicitly */,
repo_frags,
- dependents,
+ dpt_constrs,
ignore_unsatisfiable);
}
@@ -3990,7 +8074,7 @@ namespace bpkg
bool patch,
bool explicitly,
const config_repo_fragments& rfs,
- const config_package_dependents& dependents,
+ const dependent_constraints& dpt_constrs,
bool ignore_unsatisfiable)
{
tracer trace ("evaluate_dependency");
@@ -4009,8 +8093,10 @@ namespace bpkg
// Build the list of available packages for the potential up/down-grade
// to, in the version-descending order. If patching, then we constrain the
// choice with the latest patch version and place no constraints if
- // upgrading. For a system package we also put no constraints just to make
- // sure that the package is recognized.
+ // upgrading. For a system package we will try to find the available
+ // package that matches the user-specified system version (preferable for
+ // the configuration negotiation machinery) and, if fail, fallback to
+ // picking the latest one just to make sure the package is recognized.
//
optional<version_constraint> c;
@@ -4029,13 +8115,16 @@ namespace bpkg
}
}
}
- else if (!dsys)
+ else if (!dsys || !wildcard (*dvc))
c = dvc;
vector<pair<shared_ptr<available_package>,
lazy_shared_ptr<repository_fragment>>> afs (
find_available (nm, c, rfs));
+ if (afs.empty () && dsys && c)
+ afs = find_available (nm, nullopt, rfs);
+
// Go through up/down-grade candidates and pick the first one that
// satisfies all the dependents. Collect (and sort) unsatisfied dependents
// per the unsatisfiable version in case we need to print them.
@@ -4090,7 +8179,7 @@ namespace bpkg
bool satisfactory (true);
sp_set unsatisfied_dependents;
- for (const auto& dp: dependents)
+ for (const auto& dp: dpt_constrs)
{
if (!satisfies (av, dp.constraint))
{
@@ -4327,7 +8416,7 @@ namespace bpkg
// dependency.
//
config_repo_fragments repo_frags;
- config_package_dependents dependents;
+ dependent_constraints dpt_constrs;
// Only collect repository fragments (for best version selection) of
// (immediate) dependents that have a hit (direct or indirect) in recs.
@@ -4341,7 +8430,7 @@ namespace bpkg
{
shared_ptr<selected_package> p (ddb.load<selected_package> (pd.name));
- dependents.emplace_back (ddb, p, move (pd.constraint));
+ dpt_constrs.emplace_back (ddb, p, move (pd.constraint));
if (optional<bool> u = upgrade_dependencies (ddb, pd.name, recs))
{
@@ -4380,7 +8469,7 @@ namespace bpkg
!*upgrade /* patch */,
false /* explicitly */,
repo_frags,
- dependents,
+ dpt_constrs,
ignore_unsatisfiable));
// Translate the "no change" result into nullopt.
@@ -5564,7 +9653,7 @@ namespace bpkg
// List of package configurations specified on the command line.
//
- vector<config_package> pkg_confs;
+ vector<package_key> pkg_confs;
// Separate the packages specified on the command line into to hold and to
// up/down-grade as dependencies, and save dependents whose dependencies
@@ -5578,16 +9667,16 @@ namespace bpkg
// Check if the package is a duplicate. Return true if it is but
// harmless.
//
- struct config_package_key // Like config_package but with NULL'able db.
+ struct sys_package_key // Like package_key but with NULL'able db.
{
package_name name;
database* db; // Can be NULL for system dependency.
- config_package_key (package_name n, database* d)
+ sys_package_key (package_name n, database* d)
: name (move (n)), db (d) {}
bool
- operator< (const config_package_key& v) const
+ operator< (const sys_package_key& v) const
{
if (int r = name.compare (v.name))
return r < 0;
@@ -5598,14 +9687,14 @@ namespace bpkg
}
};
- map<config_package_key, pkg_arg> package_map;
+ map<sys_package_key, pkg_arg> package_map;
auto check_dup = [&package_map, &arg_string, &arg_parsed]
(const pkg_arg& pa) -> bool
{
assert (arg_parsed (pa));
- auto r (package_map.emplace (config_package_key {pa.name, pa.db}, pa));
+ auto r (package_map.emplace (sys_package_key {pa.name, pa.db}, pa));
const pkg_arg& a (r.first->second);
assert (arg_parsed (a));
@@ -5852,14 +9941,19 @@ namespace bpkg
lazy_shared_ptr<repository_fragment> root (*pdb, empty_string);
// Either get the user-specified version or the latest allowed
- // for a source code package. For a system package we pick the
- // latest one just to make sure the package is recognized.
+ // for a source code package. For a system package we will try
+ // to find the available package that matches the user-specified
+ // system version (preferable for the configuration negotiation
+ // machinery) and, if fail, fallback to picking the latest one
+ // just to make sure the package is recognized.
//
optional<version_constraint> c;
+ bool sys (arg_sys (pa));
+
if (!pa.constraint)
{
- assert (!arg_sys (pa));
+ assert (!sys);
if (pa.options.patch () &&
(sp = pdb->find<selected_package> (pa.name)) != nullptr)
@@ -5878,11 +9972,14 @@ namespace bpkg
patch = true;
}
}
- else if (!arg_sys (pa))
+ else if (!sys || !wildcard (*pa.constraint))
c = pa.constraint;
auto rp (find_available_one (pa.name, c, root));
+ if (rp.first == nullptr && sys && c)
+ rp = find_available_one (pa.name, nullopt, root);
+
ap = move (rp.first);
af = move (rp.second);
}
@@ -5918,8 +10015,7 @@ namespace bpkg
if (r)
{
- l4 ([&]{trace << "stashing recursive package "
- << arg_string (pa);});
+ l4 ([&]{trace << "stash recursive package " << arg_string (pa);});
// The above options are meaningless for system packages, so we
// just ignore them for a system dependency with unspecified
@@ -5934,8 +10030,7 @@ namespace bpkg
//
if (pa.options.dependency ())
{
- l4 ([&]{trace << "stashing dependency package "
- << arg_string (pa);});
+ l4 ([&]{trace << "stash dependency package " << arg_string (pa);});
bool sys (arg_sys (pa));
@@ -6146,8 +10241,10 @@ namespace bpkg
move (ap),
move (af),
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
true, // Hold package.
pa.constraint.has_value (), // Hold version.
{}, // Constraints.
@@ -6160,11 +10257,11 @@ namespace bpkg
: optional<dir_path> ()),
pa.options.checkout_purge (),
move (pa.config_vars),
- {config_package {mdb, ""}}, // Required by (command line).
+ {package_key {mdb, ""}}, // Required by (command line).
false, // Required by dependents.
0}; // State flags.
- l4 ([&]{trace << "stashing held package "
+ l4 ([&]{trace << "stash held package "
<< p.available_name_version_db ();});
// "Fix" the version the user asked for by adding the constraint.
@@ -6256,24 +10353,26 @@ namespace bpkg
move (sp),
move (ap),
move (apr.second),
- nullopt, // Dependencies.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- true, // Hold package.
- false, // Hold version.
- {}, // Constraints.
- false, // System package.
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ true, // Hold package.
+ false, // Hold version.
+ {}, // Constraints.
+ false, // System package.
keep_out,
o.disfigure (),
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {config_package {mdb, ""}}, // Required by (command line).
- false, // Required by dependents.
- 0}; // State flags.
-
- l4 ([&]{trace << "stashing held package "
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ {package_key {mdb, ""}}, // Required by (command line).
+ false, // Required by dependents.
+ 0}; // State flags.
+
+ l4 ([&]{trace << "stash held package "
<< p.available_name_version_db ();});
hold_pkgs.push_back (move (p));
@@ -6323,18 +10422,18 @@ namespace bpkg
linked_databases ddbs (db.dependency_configs (nm, buildtime));
- for (const config_package& cp: pkg_confs)
+ for (const package_key& p: pkg_confs)
{
- if (cp.name == nm &&
- find (ddbs.begin (), ddbs.end (), cp.db) != ddbs.end ())
+ if (p.name == nm &&
+ find (ddbs.begin (), ddbs.end (), p.db) != ddbs.end ())
{
if (r == nullptr)
- r = &cp.db;
+ r = &p.db.get ();
else
- fail << "multiple " << cp.db.type << " configurations "
+ fail << "multiple " << p.db.get ().type << " configurations "
<< "specified for package " << nm <<
info << r->config_orig <<
- info << cp.db.config_orig;
+ info << p.db.get ().config_orig;
}
}
@@ -6401,6 +10500,10 @@ namespace bpkg
};
vector<dep> deps;
+ replaced_versions replaced_vers;
+ postponed_dependencies postponed_deps;
+ postponed_positions postponed_poss;
+
// Map the repointed dependents to the replacement flags (see
// repointed_dependents for details), unless --no-move is specified.
//
@@ -6427,7 +10530,7 @@ namespace bpkg
for (shared_ptr<selected_package> sp:
pointer_result (cdb.query<selected_package> (q)))
{
- map<config_package, bool> ps; // Old/new prerequisites.
+ map<package_key, bool> ps; // Old/new prerequisites.
for (const auto& p: sp->prerequisites)
{
@@ -6447,13 +10550,13 @@ namespace bpkg
if (pdb != nullptr && *pdb != db && pdb->type == db.type)
{
- ps.emplace (config_package {*pdb, name}, true);
- ps.emplace (config_package { db, name}, false);
+ ps.emplace (package_key {*pdb, name}, true);
+ ps.emplace (package_key { db, name}, false);
}
}
if (!ps.empty ())
- rpt_depts.emplace (config_package {cdb, sp->name}, move (ps));
+ rpt_depts.emplace (package_key {cdb, sp->name}, move (ps));
}
}
@@ -6462,9 +10565,23 @@ namespace bpkg
// Iteratively refine the plan with dependency up/down-grades/drops.
//
- for (bool refine (true), scratch (true); refine; )
+ // Note that we should not clean the deps list on scratch_col (scratch
+ // during the package collection) because we want to enter them before
+ // collect_build_postponed() and they could be the dependents that have
+ // the config clauses. In a sense, change to replaced_vers,
+ // postponed_deps, or postponed_poss maps should not affect the deps
+ // list. But not the other way around: a dependency erased from the deps
+ // list could have caused an entry in the replaced_vers, postponed_deps,
+ // and/or postponed_poss maps. And so we clean replaced_vers,
+ // postponed_deps, and postponed_poss on scratch_exe (scratch during the
+ // plan execution).
+ //
+ for (bool refine (true), scratch_exe (true), scratch_col (false);
+ refine; )
{
- l4 ([&]{trace << "refining execution plan"
+ bool scratch (scratch_exe || scratch_col);
+
+ l4 ([&]{trace << "refine package collection/plan execution"
<< (scratch ? " from scratch" : "");});
transaction t (mdb);
@@ -6486,38 +10603,81 @@ namespace bpkg
// Temporarily add the replacement prerequisites to the repointed
// dependent prerequisites sets and persist the changes.
//
- // Note that we don't copy the prerequisite constraints into the
- // replacements, since they are unused in the collecting/ordering
- // logic.
- //
for (auto& rd: rpt_depts)
{
database& db (rd.first.db);
const package_name& nm (rd.first.name);
shared_ptr<selected_package> sp (db.load<selected_package> (nm));
+ package_prerequisites& prereqs (sp->prerequisites);
for (const auto& prq: rd.second)
{
if (prq.second) // Prerequisite replacement?
{
- const config_package& cp (prq.first);
+ const package_key& p (prq.first);
- auto i (sp->prerequisites.emplace (
- lazy_shared_ptr<selected_package> (cp.db, cp.name),
- nullopt));
+ // Find the being replaced prerequisite to copy it's information
+ // into the replacement.
+ //
+ auto i (find_if (prereqs.begin (), prereqs.end (),
+ [&p] (const auto& pr)
+ {
+ return pr.first.object_id () == p.name;
+ }));
+
+ assert (i != prereqs.end ());
+
+ auto j (prereqs.emplace (
+ lazy_shared_ptr<selected_package> (p.db.get (),
+ p.name),
+ i->second));
// The selected package should only contain the old
// prerequisites at this time, so adding a replacement should
// always succeed.
//
- assert (i.second);
+ assert (j.second);
}
}
db.update (sp);
}
+ // Erase the replacements from the repointed dependents prerequisite
+ // sets and persist the changes.
+ //
+ auto restore_repointed_dependents = [&rpt_depts] ()
+ {
+ for (auto& rd: rpt_depts)
+ {
+ database& db (rd.first.db);
+ const package_name& nm (rd.first.name);
+
+ shared_ptr<selected_package> sp (db.load<selected_package> (nm));
+
+ for (const auto& prq: rd.second)
+ {
+ if (prq.second) // Prerequisite replacement?
+ {
+ const package_key& p (prq.first);
+
+ size_t n (
+ sp->prerequisites.erase (
+ lazy_shared_ptr<selected_package> (p.db.get (), p.name)));
+
+ // The selected package should always contain the prerequisite
+ // replacement at this time, so its removal should always
+ // succeed.
+ //
+ assert (n == 1);
+ }
+ }
+
+ db.update (sp);
+ }
+ };
+
// Pre-enter dependency to keep track of the desired versions and
// options specified on the command line. In particular, if the
// version is specified and the dependency is used as part of the
@@ -6528,8 +10688,7 @@ namespace bpkg
// Also, if a dependency package already has selected package that
// is held, then we need to unhold it.
//
- auto enter = [&mdb, &pkgs] (database& db,
- const dependency_package& p)
+ auto enter = [&mdb, &pkgs] (database& db, const dependency_package& p)
{
build_package bp {
nullopt, // Action.
@@ -6538,8 +10697,10 @@ namespace bpkg
nullptr, // Available package/repo fragment.
nullptr,
nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
nullopt, // Package skeleton.
nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
false, // Hold package.
p.constraint.has_value (), // Hold version.
{}, // Constraints.
@@ -6550,7 +10711,7 @@ namespace bpkg
p.checkout_root,
p.checkout_purge,
p.config_vars,
- {config_package {mdb, ""}}, // Required by (command line).
+ {package_key {mdb, ""}}, // Required by (command line).
false, // Required by dependents.
0}; // State flags.
@@ -6620,179 +10781,329 @@ namespace bpkg
}
});
- build_packages::postponed_packages postponed_repo;
- build_packages::postponed_packages postponed_alts;
+ postponed_packages postponed_repo;
+ postponed_packages postponed_alts;
+ postponed_configurations postponed_cfgs;
+ strings postponed_cfgs_history;
- if (scratch)
+ try
{
- pkgs.clear ();
-
- // Pre-enter dependencies with specified configurations.
- //
- for (const dependency_package& p: dep_pkgs)
+ if (scratch)
{
- if (p.db != nullptr)
- enter (*p.db, p);
- }
+ pkgs.clear ();
- // Pre-enter system dependencies with unspecified configuration for
- // all dependency configurations, excluding those which already have
- // this dependency pre-entered.
- //
- for (const dependency_package& p: dep_pkgs)
- {
- if (p.db == nullptr)
+ if (scratch_exe)
+ {
+ replaced_vers.clear ();
+ postponed_deps.clear ();
+ postponed_poss.clear ();
+
+ scratch_exe = false;
+ }
+ else if (scratch_col)
+ {
+ // Reset to detect bogus entries.
+ //
+ for (auto& rv: replaced_vers)
+ rv.second.replaced = false;
+
+ for (auto& pd: postponed_deps)
+ {
+ pd.second.wout_config = false;
+ pd.second.with_config = false;
+ }
+
+ for (auto& pd: postponed_poss)
+ {
+ pd.second.skipped = false;
+ pd.second.reevaluated = false;
+ }
+
+ scratch_col = false;
+ }
+
+ // Pre-enter dependencies with specified configurations.
+ //
+ for (const dependency_package& p: dep_pkgs)
+ {
+ if (p.db != nullptr)
+ enter (*p.db, p);
+ }
+
+ // Pre-enter system dependencies with unspecified configuration
+ // for all dependency configurations, excluding those which
+ // already have this dependency pre-entered.
+ //
+ for (const dependency_package& p: dep_pkgs)
+ {
+ if (p.db == nullptr)
+ {
+ for (database& db: dep_dbs)
+ {
+ if (!pkgs.entered_build (db, p.name))
+ enter_system_dependency (db, p);
+ }
+ }
+ }
+
+ // Pre-collect user selection to make sure dependency-forced
+ // up/down-grades are handled properly (i.e., the order in which we
+ // specify packages on the command line does not matter).
+ //
+ for (const build_package& p: hold_pkgs)
+ pkgs.collect_build (o,
+ p,
+ find_prereq_database,
+ rpt_depts,
+ add_priv_cfg,
+ true /* initial_collection */,
+ replaced_vers,
+ postponed_cfgs);
+
+ // Collect all the prerequisites of the user selection.
+ //
+ // Note that some of the user-selected packages can well be
+ // dependencies whose recursive processing should be postponed.
+ //
+ for (const build_package& p: hold_pkgs)
+ {
+ package_key pk (p.db, p.name ());
+
+ auto i (postponed_deps.find (pk));
+
+ if (i == postponed_deps.end ())
+ {
+ pkgs.collect_build_prerequisites (
+ o,
+ p.db,
+ p.name (),
+ find_prereq_database,
+ rpt_depts,
+ add_priv_cfg,
+ true /* initial_collection */,
+ replaced_vers,
+ postponed_repo,
+ postponed_alts,
+ 0 /* max_alt_index */,
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss);
+ }
+ else
+ {
+ // Even though the user selection may have a configuration, we
+ // treat it as a dependent without any configuration because
+ // it is non-negotiable, known at the outset, and thus cannot
+ // be a reason to postpone anything.
+ //
+ i->second.wout_config = true;
+
+ l5 ([&]{trace << "dep-postpone user-specified " << pk;});
+ }
+ }
+
+ // Note that we need to collect unheld after prerequisites, not to
+ // overwrite the pre-entered entries before they are used to
+ // provide additional constraints for the collected prerequisites.
+ //
+ for (const dependency_package& p: dep_pkgs)
{
- for (database& db: dep_dbs)
+ auto unhold = [&p, &pkgs] (database& db)
{
- if (!pkgs.entered (db, p.name))
- enter_system_dependency (db, p);
+ shared_ptr<selected_package> sp (
+ p.db != nullptr
+ ? p.selected
+ : db.find<selected_package> (p.name));
+
+ if (sp != nullptr && sp->hold_package)
+ pkgs.collect_unhold (db, sp);
+ };
+
+ if (p.db != nullptr)
+ {
+ unhold (*p.db);
+ }
+ else
+ {
+ for (database& db: dep_dbs)
+ unhold (db);
}
}
+
+ // Collect dependents whose dependencies need to be repointed to
+ // packages from different configurations.
+ //
+ pkgs.collect_repointed_dependents (o,
+ rpt_depts,
+ replaced_vers,
+ postponed_repo,
+ postponed_alts,
+ postponed_deps,
+ postponed_cfgs,
+ postponed_poss,
+ find_prereq_database,
+ add_priv_cfg);
}
+ else
+ pkgs.clear_order (); // Only clear the ordered list.
- // Pre-collect user selection to make sure dependency-forced
- // up/down-grades are handled properly (i.e., the order in which we
- // specify packages on the command line does not matter).
- //
- for (const build_package& p: hold_pkgs)
- pkgs.collect_build (o,
- p,
- find_prereq_database,
- rpt_depts,
- add_priv_cfg);
-
- // Collect all the prerequisites of the user selection.
+ // Add to the plan dependencies to up/down-grade/drop that were
+ // discovered on the previous iterations.
//
- for (const build_package& p: hold_pkgs)
- pkgs.collect_build_prerequisites (o,
- p.db,
- p.name (),
- postponed_repo,
- postponed_alts,
- 0 /* max_alt_index */,
- find_prereq_database,
- rpt_depts,
- add_priv_cfg);
-
- // Note that we need to collect unheld after prerequisites, not to
- // overwrite the pre-entered entries before they are used to provide
- // additional constraints for the collected prerequisites.
+ // Note: this loop takes care of both the from-scratch and
+ // refinement cases.
//
- for (const dependency_package& p: dep_pkgs)
+ for (const dep& d: deps)
{
- auto unhold = [&p, &pkgs] (database& db)
- {
- shared_ptr<selected_package> sp (
- p.db != nullptr
- ? p.selected
- : db.find<selected_package> (p.name));
-
- if (sp != nullptr && sp->hold_package)
- pkgs.collect_unhold (db, sp);
- };
+ database& ddb (d.db);
- if (p.db != nullptr)
+ if (d.available == nullptr)
{
- unhold (*p.db);
+ pkgs.collect_drop (o,
+ ddb,
+ ddb.load<selected_package> (d.name),
+ replaced_vers);
}
else
{
- for (database& db: dep_dbs)
- unhold (db);
+ shared_ptr<selected_package> sp (
+ ddb.find<selected_package> (d.name));
+
+ // We will keep the output directory only if the external package
+ // is replaced with an external one (see above for details).
+ //
+ bool keep_out (o.keep_out () && sp->external ());
+
+ // Marking upgraded dependencies as "required by command line"
+ // may seem redundant as they should already be pre-entered as
+ // such (see above). But remember dependencies upgraded with
+ // -i|-r? Note that the required_by data member should never be
+ // empty, as it is used in prompts/diagnostics.
+ //
+ build_package p {
+ build_package::build,
+ ddb,
+ move (sp),
+ d.available,
+ d.repository_fragment,
+ nullopt, // Dependencies.
+ nullopt, // Dependencies alternatives.
+ nullopt, // Package skeleton.
+ nullopt, // Postponed dependency alternatives.
+ false, // Recursive collection.
+ nullopt, // Hold package.
+ nullopt, // Hold version.
+ {}, // Constraints.
+ d.system,
+ keep_out,
+ o.disfigure (),
+ false, // Configure-only.
+ nullopt, // Checkout root.
+ false, // Checkout purge.
+ strings (), // Configuration variables.
+ {package_key {mdb, ""}}, // Required by (command line).
+ false, // Required by dependents.
+ 0}; // State flags.
+
+ build_package_refs dep_chain;
+
+ // Note: recursive.
+ //
+ pkgs.collect_build (o,
+ move (p),
+ find_prereq_database,
+ rpt_depts,
+ add_priv_cfg,
+ true /* initial_collection */,
+ replaced_vers,
+ postponed_cfgs,
+ &dep_chain,
+ &postponed_repo,
+ &postponed_alts,
+ &postponed_deps,
+ &postponed_poss);
}
}
- // Collect dependents whose dependencies need to be repointed to
- // packages from different configurations.
+ // Erase the bogus postponements and re-collect from scratch, if any
+ // (see postponed_dependencies for details).
//
- pkgs.collect_repointed_dependents (o,
- rpt_depts,
- postponed_repo,
- postponed_alts,
- find_prereq_database,
- add_priv_cfg);
+ // Note that we used to re-collect such postponements in-place but
+ // re-doing from scratch feels more correct (i.e., we may end up
+ // doing it earlier which will affect dependency alternatives).
+ //
+ postponed_deps.cancel_bogus (trace, true /* initial_collection */);
- scratch = false;
- }
- else
- pkgs.clear_order (); // Only clear the ordered list.
+ // Now remove all the dependencies postponed during the initial
+ // collection since all this information is already in
+ // postponed_cfgs.
+ //
+ for (auto i (postponed_deps.begin ()); i != postponed_deps.end (); )
+ {
+ if (i->second.initial_collection)
+ i = postponed_deps.erase (i);
+ else
+ ++i;
+ }
- // Add to the plan dependencies to up/down-grade/drop that were
- // discovered on the previous iterations.
- //
- for (const dep& d: deps)
+ // Handle the (combined) postponed collection.
+ //
+ if (!postponed_repo.empty () ||
+ !postponed_alts.empty () ||
+ postponed_deps.has_bogus () ||
+ !postponed_cfgs.empty ())
+ pkgs.collect_build_postponed (o,
+ replaced_vers,
+ postponed_repo,
+ postponed_alts,
+ postponed_deps,
+ postponed_cfgs,
+ postponed_cfgs_history,
+ postponed_poss,
+ find_prereq_database,
+ rpt_depts,
+ add_priv_cfg);
+
+ // Erase the bogus replacements and re-collect from scratch, if any
+ // (see replaced_versions for details).
+ //
+ replaced_vers.cancel_bogus (trace, true /* scratch */);
+
+ // Erase the bogus existing dependent re-evaluation postponements
+ // and re-collect from scratch, if any (see postponed_positions for
+ // details).
+ //
+ postponed_poss.cancel_bogus (trace);
+ }
+ catch (const scratch_collection& e)
{
- database& ddb (d.db);
+ // Re-collect from scratch (but keep deps).
+ //
+ scratch_col = true;
- if (d.available == nullptr)
- {
- pkgs.collect_drop (ddb, ddb.load<selected_package> (d.name));
- }
- else
- {
- shared_ptr<selected_package> sp (
- ddb.find<selected_package> (d.name));
+ l5 ([&]{trace << "collection failed due to " << e.description
+ << (e.package != nullptr
+ ? " (" + e.package->string () + ")"
+ : empty_string)
+ << ", retry from scratch";});
- // We will keep the output directory only if the external package
- // is replaced with an external one (see above for details).
- //
- bool keep_out (o.keep_out () && sp->external ());
+ // Erase the package version replacements that we didn't apply
+ // during the current (re-)collection iteration since the dependents
+ // demanding this version are not collected anymore.
+ //
+ replaced_vers.cancel_bogus (trace, false /* scratch */);
- // Marking upgraded dependencies as "required by command line" may
- // seem redundant as they should already be pre-entered as such
- // (see above). But remember dependencies upgraded with -i|-r?
- // Note that the required_by data member should never be empty, as
- // it is used in prompts/diagnostics.
- //
- build_package p {
- build_package::build,
- ddb,
- move (sp),
- d.available,
- d.repository_fragment,
- nullopt, // Dependencies.
- nullopt, // Package skeleton.
- nullopt, // Postponed dependency alternatives.
- nullopt, // Hold package.
- nullopt, // Hold version.
- {}, // Constraints.
- d.system,
- keep_out,
- o.disfigure (),
- false, // Configure-only.
- nullopt, // Checkout root.
- false, // Checkout purge.
- strings (), // Configuration variables.
- {config_package {mdb, ""}}, // Required by (command line).
- false, // Required by dependents.
- 0}; // State flags.
+ restore_repointed_dependents ();
- build_package_refs dep_chain;
+ // Commit linking of private configurations that were potentially
+ // created during the collection of the package builds with their
+ // parent configurations.
+ //
+ t.commit ();
- // Note: recursive.
- //
- pkgs.collect_build (o,
- move (p),
- find_prereq_database,
- rpt_depts,
- add_priv_cfg,
- &postponed_repo,
- &postponed_alts,
- &dep_chain);
- }
+ continue;
}
- // Handle the (combined) postponed collection.
- //
- if (!postponed_repo.empty () || !postponed_alts.empty ())
- pkgs.collect_build_postponed (o,
- postponed_repo,
- postponed_alts,
- find_prereq_database,
- rpt_depts,
- add_priv_cfg);
-
// Now that we have collected all the package versions that we need to
// build, arrange them in the "dependency order", that is, with every
// package on the list only possibly depending on the ones after
@@ -6826,6 +11137,22 @@ namespace bpkg
find_prereq_database,
false /* reorder */);
+ for (const postponed_configuration& cfg: postponed_cfgs)
+ {
+ for (const auto& d: cfg.dependents)
+ {
+ if (d.second.existing)
+ {
+ const package_key& p (d.first);
+
+ pkgs.order (p.db,
+ p.name,
+ nullopt /* buildtime */,
+ find_prereq_database);
+ }
+ }
+ }
+
// Collect and order all the dependents that we will need to
// reconfigure because of the up/down-grades of packages that are now
// on the list.
@@ -6863,36 +11190,14 @@ namespace bpkg
}
}
+#ifndef NDEBUG
+ pkgs.verify_ordering ();
+#endif
// Now, as we are done with package builds collecting/ordering, erase
// the replacements from the repointed dependents prerequisite sets
// and persist the changes.
//
- for (auto& rd: rpt_depts)
- {
- database& db (rd.first.db);
- const package_name& nm (rd.first.name);
-
- shared_ptr<selected_package> sp (db.load<selected_package> (nm));
-
- for (const auto& prq: rd.second)
- {
- if (prq.second) // Prerequisite replacement?
- {
- const config_package& cp (prq.first);
-
- size_t n (sp->prerequisites.erase (
- lazy_shared_ptr<selected_package> (cp.db, cp.name)));
-
- // The selected package should always contain the prerequisite
- // replacement at this time, so its removal should always
- // succeed.
- //
- assert (n == 1);
- }
- }
-
- db.update (sp);
- }
+ restore_repointed_dependents ();
// We are about to execute the plan on the database (but not on the
// filesystem / actual packages). Save the session state for the
@@ -7034,7 +11339,7 @@ namespace bpkg
if (s)
{
- scratch = true; // Rebuild the plan from scratch.
+ scratch_exe = true; // Rebuild the plan from scratch.
i = deps.erase (i);
}
else
@@ -7052,13 +11357,13 @@ namespace bpkg
//
if (!changed && dep_pkgs.empty () && rec_pkgs.empty ())
{
- assert (!scratch); // No reason to change any previous decision.
+ assert (!scratch_exe); // No reason to change any previous decision.
if (o.keep_unused () || o.no_refinement ())
refine = false;
}
- if (!scratch && refine)
+ if (!scratch_exe && refine)
{
// First, we check if the refinement is required, ignoring the
// unsatisfiable dependency version constraints. If we end up
@@ -7152,7 +11457,7 @@ namespace bpkg
using prerequisites = set<lazy_shared_ptr<selected_package>,
compare_lazy_ptr_id>;
- map<config_package, prerequisites> package_prereqs;
+ map<package_key, prerequisites> package_prereqs;
small_vector<config_selected_package, 16> chain;
auto verify_dependencies = [&package_prereqs, &chain]
@@ -7163,9 +11468,9 @@ namespace bpkg
{
// Return the cached value, if present.
//
- config_package cp {db, sp->name};
+ package_key pk {db, sp->name};
{
- auto i (package_prereqs.find (cp));
+ auto i (package_prereqs.find (pk));
if (i != package_prereqs.end ())
return i->second;
@@ -7208,15 +11513,15 @@ namespace bpkg
//
// Note, however, that we cannot easily determine if the
// prerequisite corresponds to the runtime or build-time
- // dependency, since we only store its version constraint. The
- // current implementation relies on the fact that the build-time
- // dependency configuration type (host or build2) differs from the
- // dependent configuration type (target is a common case) and
- // doesn't work well, for example, for the self-hosted
- // configurations. For them it can fail erroneously. We can
- // potentially fix that by additionally storing the build-time
- // flag besides the version constraint. However, let's first see
- // if it ever becomes a problem.
+ // dependency, since we don't store this information for
+ // prerequisites. The current implementation relies on the fact
+ // that the build-time dependency configuration type (host or
+ // build2) differs from the dependent configuration type (target
+ // is a common case) and doesn't work well, for example, for the
+ // self-hosted configurations. For them it can fail
+ // erroneously. We can potentially fix that by additionally
+ // storing the build-time flag for a prerequisite. However, let's
+ // first see if it ever becomes a problem.
//
prerequisites r;
const package_prerequisites& prereqs (sp->prerequisites);
@@ -7275,7 +11580,7 @@ namespace bpkg
// Cache the resulting package prerequisites set and return a
// reference to it.
//
- auto j (package_prereqs.emplace (move (cp), move (r)));
+ auto j (package_prereqs.emplace (move (pk), move (r)));
assert (j.second); // A package cannot depend on itself.
return j.first->second;
@@ -7298,22 +11603,22 @@ namespace bpkg
// List of module packages together with the linked configuration
// clusters they belong to.
//
- vector<pair<config_package, linked_databases>> build2_mods;
+ vector<pair<package_key, linked_databases>> build2_mods;
for (const auto& pp: package_prereqs)
{
- const config_package& cp (pp.first);
+ const package_key& pk (pp.first);
// Skip packages other than the build2 modules.
//
- if (!build2_module (cp.name))
+ if (!build2_module (pk.name))
continue;
// Skip build2 modules configured as system.
//
{
shared_ptr<selected_package> sp (
- cp.db.find<selected_package> (cp.name));
+ pk.db.get ().find<selected_package> (pk.name));
assert (sp != nullptr);
@@ -7326,28 +11631,28 @@ namespace bpkg
//
for (const auto& m: build2_mods)
{
- if (m.first.name != cp.name)
+ if (m.first.name != pk.name)
continue;
// The `package_prereqs` map can only contain the same package
// twice if databases differ.
//
- assert (m.first.db != cp.db);
+ assert (m.first.db != pk.db);
const linked_databases& lcc (m.second);
- if (find (lcc.begin (), lcc.end (), cp.db) != lcc.end ())
+ if (find (lcc.begin (), lcc.end (), pk.db) != lcc.end ())
{
- fail << "building build system module " << cp.name
+ fail << "building build system module " << pk.name
<< " in multiple configurations" <<
- info << m.first.db.config_orig <<
- info << cp.db.config_orig;
+ info << m.first.db.get ().config_orig <<
+ info << pk.db.get ().config_orig;
}
}
// Add the module and its cluster to the list.
//
- build2_mods.emplace_back (cp, cp.db.cluster_configs ());
+ build2_mods.emplace_back (pk, pk.db.get ().cluster_configs ());
}
}
}
@@ -7507,6 +11812,13 @@ namespace bpkg
// While at it, detect if we have any dependents that the user may want to
// update.
//
+ // For the packages being printed also print the configuration specified
+ // by the user, dependents, and via the reflect clauses. For that we will
+ // use the package skeletons, initializing them if required. Note that for
+ // a system package the skeleton may already be initialized during the
+ // dependency negotiation process. Also note that the freshly-initialized
+ // skeletons will be reused during the plan execution.
+ //
bool update_dependents (false);
// We need the plan and to ask for the user's confirmation only if some
@@ -7524,17 +11836,22 @@ namespace bpkg
o.plan_specified () ||
o.rebuild_checksum_specified ())
{
+ // Start the transaction since we may query available packages for
+ // skeleton initializations.
+ //
+ transaction t (mdb);
+
bool first (true); // First entry in the plan.
- for (const build_package& p: reverse_iterate (pkgs))
+ for (build_package& p: reverse_iterate (pkgs))
{
+ assert (p.action);
+
database& pdb (p.db);
const shared_ptr<selected_package>& sp (p.selected);
string act;
- assert (p.action);
-
if (*p.action == build_package::drop)
{
act = "drop " + sp->string (pdb) + " (unused)";
@@ -7542,6 +11859,13 @@ namespace bpkg
}
else
{
+ // Print configuration variables.
+ //
+ // The idea here is to only print configuration for those packages
+ // for which we call pkg_configure*() in execute_plan().
+ //
+ package_skeleton* cfg (nullptr);
+
string cause;
if (*p.action == build_package::adjust)
{
@@ -7577,14 +11901,43 @@ namespace bpkg
const string& s (pdb.string);
if (!s.empty ())
act += ' ' + s;
+
+ // This is an adjustment and so there is no available package
+ // specified for the build package object and thus the skeleton
+ // cannot be present.
+ //
+ assert (p.available == nullptr && !p.skeleton);
+
+ // We shouldn't be printing configurations for plain unholds.
+ //
+ if (p.reconfigure ())
+ {
+ // Since there is no available package specified we need to find
+ // it (or create a transient one).
+ //
+ cfg = &p.init_skeleton (o, find_available (o, pdb, sp));
+ }
}
else
{
+ assert (p.available != nullptr); // This is a package build.
+
// Even if we already have this package selected, we have to
// make sure it is configured and updated.
//
if (sp == nullptr)
+ {
act = p.system ? "configure" : "new";
+
+ // For a new non-system package the skeleton must already be
+ // initialized.
+ //
+ assert (p.system || p.skeleton.has_value ());
+
+ // Initialize the skeleton if it is not initialized yet.
+ //
+ cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o));
+ }
else if (sp->version == p.available_version ())
{
// If this package is already configured and is not part of the
@@ -7606,6 +11959,13 @@ namespace bpkg
? "reconfigure"
: "reconfigure/update")
: "update");
+
+ if (p.reconfigure ())
+ {
+ // Initialize the skeleton if it is not initialized yet.
+ //
+ cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o));
+ }
}
else
{
@@ -7615,6 +11975,15 @@ namespace bpkg
? "upgrade"
: "downgrade";
+ // For a non-system package up/downgrade the skeleton must
+ // already be initialized.
+ //
+ assert (p.system || p.skeleton.has_value ());
+
+ // Initialize the skeleton if it is not initialized yet.
+ //
+ cfg = &(p.skeleton ? *p.skeleton : p.init_skeleton (o));
+
need_prompt = true;
}
@@ -7637,8 +12006,8 @@ namespace bpkg
// dependent-dependency structure change without any of the
// package versions changing? Doesn't feel like it should.
//
- for (const config_package& cp: p.required_by)
- rb += (rb.empty () ? " " : ", ") + cp.string ();
+ for (const package_key& pk: p.required_by)
+ rb += (rb.empty () ? " " : ", ") + pk.string ();
// If not user-selected, then there should be another (implicit)
// reason for the action.
@@ -7650,6 +12019,14 @@ namespace bpkg
if (!rb.empty ())
act += " (" + cause + rb + ')';
+
+ if (cfg != nullptr && !cfg->empty_print ())
+ {
+ ostringstream os;
+ cfg->print_config (os, o.print_only () ? " " : " ");
+ act += '\n';
+ act += os.str ();
+ }
}
if (first)
@@ -7677,6 +12054,8 @@ namespace bpkg
if (o.rebuild_checksum_specified ())
csum.append (act);
}
+
+ t.commit ();
}
if (o.rebuild_checksum_specified ())
@@ -7882,7 +12261,7 @@ namespace bpkg
}
if (*p.action != build_package::drop &&
- !p.skeleton &&
+ !p.dependencies &&
!sp->prerequisites.empty ())
{
vector<package_name>& ps (previous_prerequisites[&p]);
@@ -7913,7 +12292,6 @@ namespace bpkg
assert (sp->state == package_state::unpacked ||
sp->state == package_state::transient);
-
if (result || progress)
{
const char* what (sp->state == package_state::transient
@@ -8280,6 +12658,9 @@ namespace bpkg
// source code one, or just available, in which case it is a system
// one. Note that a system package gets selected as being configured.
//
+ // NOTE: remember to update the preparation of the plan to be presented
+ // to the user if changing anything here.
+ //
assert (sp != nullptr || p.system);
database& pdb (p.db);
@@ -8314,9 +12695,11 @@ namespace bpkg
}
else if (ap != nullptr)
{
+ assert (*p.action == build_package::build);
+
// If the package prerequisites builds are collected, then use the
- // resulting package skeleton and dependency list for optimization
- // (not to re-evaluate enable conditions, etc).
+ // resulting package skeleton and the pre-selected dependency
+ // alternatives.
//
// Note that we may not collect the package prerequisites builds if
// the package is already configured but we still need to reconfigure
@@ -8333,17 +12716,19 @@ namespace bpkg
// the package manually). Maybe that a good reason not to allow
// this? Or we could store this information in the database.
//
- if (p.skeleton)
+ if (p.dependencies)
{
- assert (p.dependencies);
+ assert (p.skeleton);
pkg_configure (o,
pdb,
t,
sp,
*p.dependencies,
+ &*p.alternatives,
move (*p.skeleton),
nullptr /* previous_prerequisites */,
+ p.disfigure,
simulate,
fdb);
}
@@ -8351,85 +12736,77 @@ namespace bpkg
{
assert (sp != nullptr); // See above.
- optional<dir_path> src_root (p.external_dir ());
-
- optional<dir_path> out_root (
- src_root && !p.disfigure
- ? dir_path (pdb.config) /= p.name ().string ()
- : optional<dir_path> ());
+ // Note that the skeleton can be present if, for example, this is a
+ // dependency which configuration has been negotiated but it is not
+ // collected recursively since it has no buildfile clauses.
+ //
+ if (!p.skeleton)
+ p.init_skeleton (o);
pkg_configure (o,
pdb,
t,
sp,
ap->dependencies,
- package_skeleton (o,
- pdb,
- *ap,
- move (p.config_vars),
- move (src_root),
- move (out_root)),
+ nullptr /* alternatives */,
+ move (*p.skeleton),
prereqs (),
+ p.disfigure,
simulate,
fdb);
}
}
else // Dependent.
{
+ // This is an adjustment of a dependent which cannot be system
+ // (otherwise it wouldn't be a dependent) and cannot become system
+ // (otherwise it would be a build).
+ //
+ assert (*p.action == build_package::adjust &&
+ !p.system &&
+ !sp->system ());
+
// Must be in the unpacked state since it was disfigured on the first
// pass (see above).
//
assert (sp->state == package_state::unpacked);
- // First try to avoid the package manifest parsing, searching for an
- // existing available package for the selected package and, if not
- // found, create a transient one.
+ // Initialize the skeleton if it is not initialized yet.
//
- // Note that we don't use find_available*() here since we don't care
- // about the repository fragment the package comes from and only need
- // its manifest information.
+ // Note that the skeleton can only be present here if it was
+ // initialized during the preparation of the plan and so this plan
+ // execution is not simulated (see above for details).
//
- shared_ptr<available_package> dap;
-
- available_package_id pid (sp->name, sp->version);
- for (database& db: dependent_repo_configs (pdb))
- {
- shared_ptr<available_package> ap (db.find<available_package> (pid));
-
- if (ap != nullptr && !ap->stub ())
- {
- dap = move (ap);
- break;
- }
- }
+ // Also note that there is no available package specified for the
+ // build package object here and so we need to find it (or create a
+ // transient one).
+ //
+ assert (p.available == nullptr && (!p.skeleton || !simulate));
- if (dap == nullptr)
- dap = make_available (o, pdb, sp);
+ if (!p.skeleton)
+ p.init_skeleton (o, find_available (o, pdb, sp));
- optional<dir_path> src_root (p.external_dir ());
+ assert (p.skeleton->available != nullptr); // Can't be system.
- optional<dir_path> out_root (
- src_root && !p.disfigure
- ? dir_path (pdb.config) /= p.name ().string ()
- : optional<dir_path> ());
+ const dependencies& deps (p.skeleton->available->dependencies);
// @@ Note that on reconfiguration the dependent looses the potential
// configuration variables specified by the user on some previous
// build, which can be quite surprising. Should we store this
// information in the database?
//
+ // I believe this now works for external packages via package
+ // skeleton (which extracts user configuration).
+ //
pkg_configure (o,
pdb,
t,
sp,
- dap->dependencies,
- package_skeleton (o,
- pdb,
- *dap,
- move (p.config_vars),
- move (src_root),
- move (out_root)),
+ deps,
+ nullptr /* alternatives */,
+ move (*p.skeleton),
prereqs (),
+ false /* disfigured */,
simulate,
fdb);
}
diff --git a/bpkg/pkg-configure.cxx b/bpkg/pkg-configure.cxx
index 1392545..a86752e 100644
--- a/bpkg/pkg-configure.cxx
+++ b/bpkg/pkg-configure.cxx
@@ -36,7 +36,7 @@ namespace bpkg
// package skeleton, excluding those user-specified variables which are
// not the project variables for the specified package (module
// configuration variables, etc). Thus, it is not parallel to the
- // variables member.
+ // config_variables member.
//
vector<config_variable> config_sources; // Note: name and source.
};
@@ -48,14 +48,19 @@ namespace bpkg
database& db,
transaction&,
const dependencies& deps,
+ const vector<size_t>* alts,
package_skeleton&& ps,
const vector<package_name>* prev_prereqs,
bool simulate,
const function<find_database_function>& fdb)
{
- package_prerequisites prereqs;
- strings vars;
- vector<config_variable> srcs;
+ package_prerequisites prereqs;
+ strings vars;
+
+ // Alternatives argument must be parallel to the dependencies argument if
+ // specified.
+ //
+ assert (alts == nullptr || alts->size () == deps.size ());
for (size_t di (0); di != deps.size (); ++di)
{
@@ -64,19 +69,55 @@ namespace bpkg
//
const dependency_alternatives_ex& das (deps[di]);
- if (das.empty () || toolchain_buildtime_dependency (o, das, ps.name ()))
+ if (das.empty ())
continue;
- small_vector<reference_wrapper<const dependency_alternative>, 2> edas;
+ small_vector<pair<reference_wrapper<const dependency_alternative>,
+ size_t>,
+ 2> edas;
- for (const dependency_alternative& da: das)
+ // If the dependency alternatives are not pre-selected, then evaluate
+ // the enable clauses.
+ //
+ // Note that evaluating the require and prefer clauses in this case is
+ // meaningless since we don't reconfigure the dependencies nor negotiate
+ // configurations with other dependents. What we should probably do is
+ // load configurations of the dependencies and use them while evaluating
+ // the dependent's enable and reflect clauses as we go along. Probably
+ // we should still evaluate the accept clauses to make sure that the
+ // dependency is configured acceptably for the dependent. For now we
+ // fail and will support this maybe later.
+ //
+ if (alts == nullptr)
{
- if (!da.enable || ps.evaluate_enable (*da.enable, di))
- edas.push_back (da);
+ if (toolchain_buildtime_dependency (o, das, &ps.package.name))
+ continue;
+
+ for (size_t i (0); i != das.size (); ++i)
+ {
+ const dependency_alternative& da (das[i]);
+
+ if (!da.enable || ps.evaluate_enable (*da.enable, make_pair (di, i)))
+ {
+ if (da.prefer || da.require)
+ fail << "manual configuration of dependents with prefer or "
+ << "require clauses is not yet supported";
+
+ edas.push_back (make_pair (ref (da), i));
+ }
+ }
+
+ if (edas.empty ())
+ continue;
}
+ else
+ {
+ // Must only contain the selected alternative.
+ //
+ assert (das.size () == 1);
- if (edas.empty ())
- continue;
+ edas.push_back (make_pair (ref (das.front ()), (*alts)[di]));
+ }
// Pick the first alternative with dependencies that can all be resolved
// to the configured packages, satisfying the respective constraints.
@@ -91,16 +132,19 @@ namespace bpkg
for (const vector<package_name>* pps (prev_prereqs);;)
{
bool satisfied (false);
- for (const dependency_alternative& da: edas)
+ for (const auto& eda: edas)
{
+ const dependency_alternative& da (eda.first);
+ size_t dai (eda.second);
+
// Cache the selected packages which correspond to the alternative
// dependencies, pairing them with the respective constraints. If
// the alternative turns out to be fully resolvable, we will add the
// cached packages into the dependent's prerequisites map.
//
small_vector<
- pair<lazy_shared_ptr<selected_package>,
- const optional<version_constraint>&>, 1> prerequisites;
+ pair<lazy_shared_ptr<selected_package>, prerequisite_info>,
+ 1> prerequisites;
dependency_alternative::const_iterator b (da.begin ());
dependency_alternative::const_iterator i (b);
@@ -132,9 +176,13 @@ namespace bpkg
// See the package_prerequisites definition for details on
// creating the map keys with the database passed.
//
+ bool conf (da.prefer || da.require);
+
prerequisites.emplace_back (
lazy_shared_ptr<selected_package> (*spd.second, dp),
- d.constraint);
+ prerequisite_info {d.constraint,
+ make_pair (conf ? di + 1 : 0,
+ conf ? dai + 1 : 0)});
}
// Try the next alternative if there are unresolved dependencies for
@@ -150,9 +198,9 @@ namespace bpkg
for (auto& pr: prerequisites)
{
const package_name& pn (pr.first.object_id ());
- const optional<version_constraint>& pc (pr.second);
+ const prerequisite_info& pi (pr.second);
- auto p (prereqs.emplace (pr.first, pc));
+ auto p (prereqs.emplace (pr.first, pi));
// Currently we can only capture a single constraint, so if we
// already have a dependency on this package and one constraint is
@@ -160,18 +208,28 @@ namespace bpkg
//
if (!p.second)
{
- auto& c (p.first->second);
+ auto& c1 (p.first->second.constraint);
+ auto& c2 (pi.constraint);
- bool s1 (satisfies (c, pc));
- bool s2 (satisfies (pc, c));
+ bool s1 (satisfies (c1, c2));
+ bool s2 (satisfies (c2, c1));
if (!s1 && !s2)
fail << "multiple dependencies on package " << pn <<
- info << pn << " " << *c <<
- info << pn << " " << *pc;
+ info << pn << " " << *c1 <<
+ info << pn << " " << *c2;
if (s2 && !s1)
- c = pc;
+ c1 = c2;
+
+ // Keep position of the first dependency alternative with a
+ // configuration clause.
+ //
+ pair<size_t, size_t>& p1 (p.first->second.config_position);
+ pair<size_t, size_t> p2 (pi.config_position);
+
+ if (p1.first == 0 && p2.first != 0)
+ p1 = p2;
}
// If the prerequisite is configured in the linked configuration,
@@ -215,7 +273,7 @@ namespace bpkg
// Evaluate the dependency alternative reflect clause, if present.
//
if (da.reflect)
- ps.evaluate_reflect (*da.reflect, di);
+ ps.evaluate_reflect (*da.reflect, make_pair (di, dai));
satisfied = true;
break;
@@ -244,34 +302,28 @@ namespace bpkg
}
}
- // Add the configuration variables collected from the reflect clauses, if
- // any.
+ // Add the rest of the configuration variables (user overrides, reflects,
+ // etc) as well as their sources.
//
+ vector<config_variable> srcs;
+
if (!simulate)
{
- auto rvs (move (ps).collect_config ());
+ pair<strings, vector<config_variable>> rvs (move (ps).collect_config ());
- strings& vs (rvs.first);
- vector<optional<config_source>>& ss (rvs.second);
+ strings& vs (rvs.first);
+ srcs = move (rvs.second);
if (!vs.empty ())
{
- vars.reserve (vars.size () + vs.size ());
-
- for (size_t i (0); i != vs.size (); ++i)
+ if (vars.empty ())
+ vars = move (vs);
+ else
{
- string& v (vs[i]);
- const optional<config_source>& s (ss[i]);
-
- if (s)
- {
- size_t p (v.find_first_of ("=+ \t"));
- assert (p != string::npos);
-
- srcs.push_back (config_variable {string (v, 0, p), *s});
- }
+ vars.reserve (vars.size () + vs.size ());
- vars.push_back (move (v));
+ for (string& v: vs)
+ vars.push_back (move (v));
}
}
}
@@ -287,8 +339,10 @@ namespace bpkg
transaction& t,
const shared_ptr<selected_package>& p,
const dependencies& deps,
+ const vector<size_t>* alts,
package_skeleton&& ps,
const vector<package_name>* pps,
+ bool disfigured,
bool simulate,
const function<find_database_function>& fdb)
{
@@ -322,6 +376,7 @@ namespace bpkg
db,
t,
deps,
+ alts,
move (ps),
pps,
simulate,
@@ -346,31 +401,26 @@ namespace bpkg
l4 ([&]{trace << "buildspec: " << bspec;});
- // Deduce the configuration variables which are not reflected anymore
- // and disfigure them.
+ // Unless this package has been completely disfigured, disfigure all the
+ // package configuration variables to reset all the old values to
+ // defaults (all the new user/dependent/reflec values, including old
+ // user, are returned by collect_config() and specified as overrides).
+ // Note that this semantics must be consistent with how we load things
+ // in the package skeleton during configuration negotiation.
+ //
+ // Note also that this means we don't really use the dependent and
+ // reflect sources that we save in the database. But let's keep them
+ // for the completeness of information (maybe could be useful during
+ // configuration reset or some such).
//
string dvar;
- for (const config_variable& cv: p->config_variables)
+ if (!disfigured)
{
- if (cv.source == config_source::reflect)
- {
- const vector<config_variable>& ss (cpr.config_sources);
- auto i (find_if (ss.begin (), ss.end (),
- [&cv] (const config_variable& v)
- {
- return v.name == cv.name;
- }));
-
- if (i == ss.end ())
- {
- if (dvar.empty ())
- dvar = "config.config.disfigure=";
- else
- dvar += ' ';
-
- dvar += cv.name;
- }
- }
+ // Note: must be quoted to preserve the pattern.
+ //
+ dvar = "config.config.disfigure='config.";
+ dvar += p->name.variable ();
+ dvar += "**'";
}
// Configure.
@@ -554,18 +604,30 @@ namespace bpkg
? dir_path (db.config) /= p->name.string ()
: optional<dir_path> ());
+ // Note on the disfigure logic: while we don't know whether the package
+ // has been disfigured with --keep-config or not, it has already been
+ // done physically and if without --keep-config, then config.build has
+ // been removed and config_variables cleaned. As a result, we can just
+ // proceed as disfigure=false and disfigure=true will be taken care
+ // automatically (because then things have been removed/cleaned).
+ //
pkg_configure (o,
db,
t,
p,
ap->dependencies,
+ nullptr /* alternatives */,
package_skeleton (o,
- db,
- *ap,
+ package_key (db, ap->id.name),
+ false /* system */,
+ ap,
move (vars),
+ false /* disfigure */,
+ &p->config_variables,
move (src_root),
move (out_root)),
nullptr /* prerequisites */,
+ false /* disfigured */,
false /* simulate */);
}
diff --git a/bpkg/pkg-configure.hxx b/bpkg/pkg-configure.hxx
index 23dab83..16ed96f 100644
--- a/bpkg/pkg-configure.hxx
+++ b/bpkg/pkg-configure.hxx
@@ -33,9 +33,16 @@ namespace bpkg
// Configure the package, update its state, and commit the transaction.
//
- // The package dependency constraints are expected to be complete. Empty
- // dependency alternatives lists are allowed and are ignored (see pkg-build
- // for the use-case).
+ // The package dependency constraints are expected to be complete.
+ //
+ // The dependencies argument may contain pre-selected dependency
+ // alternatives (with the potential empty entries for the toolchain
+ // build-time dependencies or for dependencies with all the alternatives
+ // disabled; see pkg-build for the use-case). In this case the number of
+ // dependency alternatives for each dependency must be 1 (or 0) and the
+ // alternatives argument must be specified. The alternatives argument must
+ // be parallel to the dependencies argument and specify indexes of the
+ // selected alternatives.
//
// If prerequisites corresponding to the previous configured state of the
// package are specified, then for each depends value try to select an
@@ -49,8 +56,10 @@ namespace bpkg
transaction&,
const shared_ptr<selected_package>&,
const dependencies&,
+ const vector<size_t>* alternatives,
package_skeleton&&,
const vector<package_name>* prerequisites,
+ bool disfigured,
bool simulate,
const function<find_database_function>& = {});
diff --git a/bpkg/pkg-drop.cxx b/bpkg/pkg-drop.cxx
index 08168d4..0aadaa7 100644
--- a/bpkg/pkg-drop.cxx
+++ b/bpkg/pkg-drop.cxx
@@ -77,7 +77,7 @@ namespace bpkg
drop_reason r = drop_reason::user)
{
package_name n (p->name); // Because of move(p) below.
- return map_.emplace (config_package {db, move (n)},
+ return map_.emplace (package_key {db, move (n)},
data_type {end (), {db, move (p), r}}).second;
}
@@ -278,7 +278,7 @@ namespace bpkg
if (!keep)
{
i = erase (i);
- map_.erase (config_package {db, p->name});
+ map_.erase (package_key {db, p->name});
continue;
}
@@ -298,18 +298,18 @@ namespace bpkg
drop_package package;
};
- class config_package_map: public map<config_package, data_type>
+ class package_map: public map<package_key, data_type>
{
public:
- using base_type = map<config_package, data_type>;
+ using base_type = map<package_key, data_type>;
iterator
find (database& db, const package_name& pn)
{
- return base_type::find (config_package {db, pn});
+ return base_type::find (package_key {db, pn});
}
};
- config_package_map map_;
+ package_map map_;
};
// Drop ordered list of packages.
diff --git a/bpkg/pkg-fetch.cxx b/bpkg/pkg-fetch.cxx
index 531bf84..d065ff1 100644
--- a/bpkg/pkg-fetch.cxx
+++ b/bpkg/pkg-fetch.cxx
@@ -256,12 +256,12 @@ namespace bpkg
//
assert (ap->sha256sum);
- const string& sha256sum (sha256 (co, a));
- if (sha256sum != *ap->sha256sum)
+ const string& cs (sha256sum (co, a));
+ if (cs != *ap->sha256sum)
{
fail << "checksum mismatch for " << n << " " << v <<
info << pl->repository_fragment->name << " has " << *ap->sha256sum <<
- info << "fetched archive has " << sha256sum <<
+ info << "fetched archive has " << cs <<
info << "consider re-fetching package list and trying again" <<
info << "if problem persists, consider reporting this to "
<< "the repository maintainer";
diff --git a/bpkg/pkg-status.cxx b/bpkg/pkg-status.cxx
index 45ea519..09a9424 100644
--- a/bpkg/pkg-status.cxx
+++ b/bpkg/pkg-status.cxx
@@ -144,7 +144,7 @@ namespace bpkg
{
shared_ptr<selected_package> d (pair.first.load ());
database& db (pair.first.database ());
- const optional<version_constraint>& c (pair.second);
+ const optional<version_constraint>& c (pair.second.constraint);
r.push_back (package {db, rdb, d->name, version (), move (d), c});
}
return r;
diff --git a/bpkg/rep-create.cxx b/bpkg/rep-create.cxx
index b4944b7..c9ee924 100644
--- a/bpkg/rep-create.cxx
+++ b/bpkg/rep-create.cxx
@@ -24,7 +24,7 @@ using namespace butl;
namespace bpkg
{
- struct package_key
+ struct package_version_key
{
package_name name;
bpkg::version version;
@@ -34,20 +34,20 @@ namespace bpkg
// revision.
//
bool
- operator< (const package_key& y) const
+ operator< (const package_version_key& y) const
{
int r (name.compare (y.name));
return r < 0 || (r == 0 && version.compare (y.version, true) < 0);
}
};
- struct package_data
+ struct package_version_data
{
path archive;
package_manifest manifest;
};
- using package_map = map<package_key, package_data>;
+ using package_map = map<package_version_key, package_version_data>;
static void
collect (const rep_create_options& o,
@@ -106,7 +106,7 @@ namespace bpkg
// Calculate its checksum.
//
- m.sha256sum = sha256 (o, a);
+ m.sha256sum = sha256sum (o, a);
l4 ([&]{trace << m.name << " " << m.version << " in " << a
<< " sha256sum " << *m.sha256sum;});
@@ -115,8 +115,8 @@ namespace bpkg
//
m.location = a.leaf (root);
- package_key k {m.name, m.version}; // Argument evaluation order.
- auto r (map.emplace (move (k), package_data {a, move (m)}));
+ package_version_key k {m.name, m.version}; // Argument evaluation order.
+ auto r (map.emplace (move (k), package_version_data {a, move (m)}));
// Diagnose duplicates.
//
@@ -183,7 +183,7 @@ namespace bpkg
collect (o, pm, d, d);
pkg_package_manifests manifests;
- manifests.sha256sum = sha256 (o, path (d / repositories_file));
+ manifests.sha256sum = sha256sum (o, path (d / repositories_file));
for (auto& p: pm)
{
@@ -235,7 +235,7 @@ namespace bpkg
info << "run 'bpkg help rep-create' for more information";
signature_manifest m;
- m.sha256sum = sha256 (o, p);
+ m.sha256sum = sha256sum (o, p);
m.signature = sign_repository (o, m.sha256sum, key, *cert, d);
p = path (d / signature_file);
diff --git a/bpkg/rep-info.cxx b/bpkg/rep-info.cxx
index 5184048..7d78173 100644
--- a/bpkg/rep-info.cxx
+++ b/bpkg/rep-info.cxx
@@ -5,7 +5,6 @@
#include <iostream> // cout
-#include <libbutl/sha256.hxx> // sha256_to_fingerprint()
#include <libbutl/manifest-serializer.hxx>
#include <libbpkg/manifest.hxx>
diff --git a/bpkg/types.hxx b/bpkg/types.hxx
index a8cd0f4..2b6a1f8 100644
--- a/bpkg/types.hxx
+++ b/bpkg/types.hxx
@@ -26,6 +26,7 @@
#include <libbutl/path.hxx>
#include <libbutl/uuid.hxx>
#include <libbutl/uuid-io.hxx>
+#include <libbutl/sha256.hxx>
#include <libbutl/process.hxx>
#include <libbutl/utility.hxx> // icase_compare_string,
// compare_reference_target
@@ -103,6 +104,12 @@ namespace bpkg
//
using butl::url;
+ // <libbutl/sha256.hxx>
+ //
+ using butl::sha256;
+ using butl::sha256_to_fingerprint;
+ using butl::fingerprint_to_sha256;
+
// <libbutl/process.hxx>
//
using butl::process;
diff --git a/bpkg/utility.hxx b/bpkg/utility.hxx
index 2dcf46d..597800c 100644
--- a/bpkg/utility.hxx
+++ b/bpkg/utility.hxx
@@ -48,6 +48,10 @@ namespace bpkg
using butl::digit;
using butl::xdigit;
+ using butl::trim;
+ using butl::trim_left;
+ using butl::trim_right;
+
using butl::make_guard;
using butl::make_exception_guard;
diff --git a/tests/common/dependency-alternatives/t11a/bac-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bac-1.0.0.tar.gz
new file mode 100644
index 0000000..7a7670d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bac-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bar-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/bar-0.1.0.tar.gz
new file mode 100644
index 0000000..34774a8
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bar-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..15d819e
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bas-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bas-1.0.0.tar.gz
new file mode 100644
index 0000000..c6365e3
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bas-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bat-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bat-1.0.0.tar.gz
new file mode 100644
index 0000000..bb92104
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bat-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bax-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bax-1.0.0.tar.gz
new file mode 100644
index 0000000..d488f1a
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bax-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/baz-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/baz-0.1.0.tar.gz
new file mode 100644
index 0000000..a1f37b0
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/baz-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..1fd57fe
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bex-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bex-1.0.0.tar.gz
new file mode 100644
index 0000000..4afa0f8
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bex-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bix-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bix-1.0.0.tar.gz
new file mode 100644
index 0000000..2109914
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/biz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/biz-1.0.0.tar.gz
new file mode 100644
index 0000000..e81a027
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/biz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/boo-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/boo-1.0.0.tar.gz
new file mode 100644
index 0000000..778b253
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/boo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/box-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/box-0.1.0.tar.gz
new file mode 100644
index 0000000..8e91f91
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/box-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/box-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/box-1.0.0.tar.gz
new file mode 100644
index 0000000..d205dc1
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/box-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/buc-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/buc-1.0.0.tar.gz
new file mode 100644
index 0000000..88183f7
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/buc-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bus-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bus-1.0.0.tar.gz
new file mode 100644
index 0000000..1530f14
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bus-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/bux-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/bux-1.0.0.tar.gz
new file mode 100644
index 0000000..210941a
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/bux-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/buz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/buz-1.0.0.tar.gz
new file mode 100644
index 0000000..7419d8a
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/buz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/dex-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/dex-1.0.0.tar.gz
new file mode 100644
index 0000000..58bb16d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/dex-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/dix-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/dix-1.0.0.tar.gz
new file mode 100644
index 0000000..2236190
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/dix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/diz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/diz-1.0.0.tar.gz
new file mode 100644
index 0000000..a7fc8fa
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/diz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/dox-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/dox-1.0.0.tar.gz
new file mode 100644
index 0000000..00c730a
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/dox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fex-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/fex-1.0.0.tar.gz
new file mode 100644
index 0000000..00e925a
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/fex-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fix-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/fix-0.1.0.tar.gz
new file mode 100644
index 0000000..1d4ab42
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/fix-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fix-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/fix-1.0.0.tar.gz
new file mode 100644
index 0000000..3613136
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/fix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/foo-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/foo-0.1.0.tar.gz
new file mode 100644
index 0000000..ebf3f01
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/foo-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/foo-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/foo-1.0.0.tar.gz
new file mode 100644
index 0000000..c9a4d6d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/foo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fox-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/fox-1.0.0.tar.gz
new file mode 100644
index 0000000..17b7278
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/fox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/fux-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/fux-1.0.0.tar.gz
new file mode 100644
index 0000000..b045fcd
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/fux-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libbar-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbar-0.1.0.tar.gz
new file mode 100644
index 0000000..57b9ccc
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libbar-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libbar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbar-1.0.0.tar.gz
new file mode 100644
index 0000000..7c5a840
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libbar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libbaz-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbaz-0.1.0.tar.gz
new file mode 100644
index 0000000..b8bfaec
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libbaz-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libbaz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbaz-1.0.0.tar.gz
new file mode 100644
index 0000000..9fde627
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libbaz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libbox-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbox-0.1.0.tar.gz
new file mode 100644
index 0000000..3388a94
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libbox-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libbox-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/libbox-1.0.0.tar.gz
new file mode 100644
index 0000000..8a417e4
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libbox-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libfoo-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/libfoo-0.1.0.tar.gz
new file mode 100644
index 0000000..a94b8fe
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libfoo-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gz
new file mode 100644
index 0000000..52ba91b
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/repositories.manifest b/tests/common/dependency-alternatives/t11a/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t11a/tax-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tax-1.0.0.tar.gz
new file mode 100644
index 0000000..616cb05
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tax-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tex-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/tex-0.1.0.tar.gz
new file mode 100644
index 0000000..eb7d09f
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tex-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tex-0.2.0.tar.gz b/tests/common/dependency-alternatives/t11a/tex-0.2.0.tar.gz
new file mode 100644
index 0000000..0b21183
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tex-0.2.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tex-0.3.0.tar.gz b/tests/common/dependency-alternatives/t11a/tex-0.3.0.tar.gz
new file mode 100644
index 0000000..836a032
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tex-0.3.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tex-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tex-1.0.0.tar.gz
new file mode 100644
index 0000000..3c9093d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tex-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tez-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tez-1.0.0.tar.gz
new file mode 100644
index 0000000..edf378b
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tez-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tix-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/tix-0.1.0.tar.gz
new file mode 100644
index 0000000..2badf78
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tix-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tix-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tix-1.0.0.tar.gz
new file mode 100644
index 0000000..a1f2930
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tiz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tiz-1.0.0.tar.gz
new file mode 100644
index 0000000..63c5876
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tiz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/toz-0.1.0.tar.gz b/tests/common/dependency-alternatives/t11a/toz-0.1.0.tar.gz
new file mode 100644
index 0000000..b99803c
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/toz-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/toz-0.2.0.tar.gz b/tests/common/dependency-alternatives/t11a/toz-0.2.0.tar.gz
new file mode 100644
index 0000000..b2bd931
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/toz-0.2.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/toz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/toz-1.0.0.tar.gz
new file mode 100644
index 0000000..ccfc094
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/toz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t11a/tux-1.0.0.tar.gz b/tests/common/dependency-alternatives/t11a/tux-1.0.0.tar.gz
new file mode 100644
index 0000000..62c4e73
--- /dev/null
+++ b/tests/common/dependency-alternatives/t11a/tux-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13a/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13a/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..db3c22d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13a/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13a/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13a/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..f86b0aa
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13a/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13a/biz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13a/biz-1.0.0.tar.gz
new file mode 100644
index 0000000..cfa8fa2
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13a/biz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13a/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13a/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..c177a1b
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13a/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13a/repositories.manifest b/tests/common/dependency-alternatives/t13a/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13a/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13b/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13b/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..5b49774
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13b/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13b/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13b/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..cb136b4
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13b/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13b/biz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13b/biz-1.0.0.tar.gz
new file mode 100644
index 0000000..27fe077
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13b/biz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13b/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13b/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..ee1dd3a
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13b/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13b/repositories.manifest b/tests/common/dependency-alternatives/t13b/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13b/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13c/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13c/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..83ad484
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13c/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13c/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13c/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..b64552e
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13c/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13c/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13c/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..5b79dc9
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13c/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13c/repositories.manifest b/tests/common/dependency-alternatives/t13c/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13c/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13d/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13d/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..5683176
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13d/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13d/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13d/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..8101c5d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13d/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13d/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13d/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..f2965f5
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13d/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13d/libb-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13d/libb-1.0.0.tar.gz
new file mode 100644
index 0000000..0f13429
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13d/libb-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13d/repositories.manifest b/tests/common/dependency-alternatives/t13d/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13d/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13e/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13e/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..7211afb
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13e/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13e/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13e/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..e5f2880
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13e/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13e/biz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13e/biz-1.0.0.tar.gz
new file mode 100644
index 0000000..afd7db3
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13e/biz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13e/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13e/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..f3cb165
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13e/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13e/repositories.manifest b/tests/common/dependency-alternatives/t13e/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13e/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13f/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13f/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..7a255a1
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13f/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13f/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13f/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..f697c81
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13f/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13f/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13f/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..877305f
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13f/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13f/repositories.manifest b/tests/common/dependency-alternatives/t13f/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13f/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13g/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13g/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..5c8a596
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13g/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13g/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13g/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..011ffea
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13g/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13g/biz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13g/biz-1.0.0.tar.gz
new file mode 100644
index 0000000..77cb421
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13g/biz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13g/box-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13g/box-1.0.0.tar.gz
new file mode 100644
index 0000000..5217e88
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13g/box-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13g/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13g/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..2ee35ae
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13g/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13g/libb-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13g/libb-1.0.0.tar.gz
new file mode 100644
index 0000000..0f13429
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13g/libb-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13g/repositories.manifest b/tests/common/dependency-alternatives/t13g/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13g/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13h/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13h/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..7e85fca
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13h/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13h/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13h/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..6fbdf82
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13h/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13h/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13h/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..ffd380c
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13h/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13h/repositories.manifest b/tests/common/dependency-alternatives/t13h/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13h/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13i/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13i/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..6c1076d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13i/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13i/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13i/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..b086ef4
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13i/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13i/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13i/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..4a7bd22
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13i/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13i/repositories.manifest b/tests/common/dependency-alternatives/t13i/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13i/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13j/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13j/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..8660e0f
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13j/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13j/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13j/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..7483377
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13j/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13j/biz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13j/biz-1.0.0.tar.gz
new file mode 100644
index 0000000..948c1c4
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13j/biz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13j/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13j/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..0c94586
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13j/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13j/repositories.manifest b/tests/common/dependency-alternatives/t13j/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13j/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13k/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13k/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..51de0c5
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13k/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13k/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13k/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..a8c62ba
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13k/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13k/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13k/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..c4a4b32
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13k/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13k/repositories.manifest b/tests/common/dependency-alternatives/t13k/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13k/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13l/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13l/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..d114c5c
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13l/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13l/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13l/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..e884965
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13l/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13l/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13l/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..3590340
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13l/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13l/libb-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13l/libb-1.0.0.tar.gz
new file mode 100644
index 0000000..409f438
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13l/libb-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13l/repositories.manifest b/tests/common/dependency-alternatives/t13l/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13l/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13m/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13m/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..7a2bc53
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13m/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13m/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13m/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..c5028f7
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13m/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13m/bix-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13m/bix-1.0.0.tar.gz
new file mode 100644
index 0000000..9d45acc
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13m/bix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13m/biz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13m/biz-1.0.0.tar.gz
new file mode 100644
index 0000000..d12852b
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13m/biz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13m/box-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13m/box-1.0.0.tar.gz
new file mode 100644
index 0000000..316458d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13m/box-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13m/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13m/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..3857354
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13m/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13m/repositories.manifest b/tests/common/dependency-alternatives/t13m/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13m/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13n/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13n/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..d3d3a24
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13n/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13n/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13n/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..fd96b61
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13n/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13n/libb-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13n/libb-1.0.0.tar.gz
new file mode 100644
index 0000000..409f438
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13n/libb-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13n/repositories.manifest b/tests/common/dependency-alternatives/t13n/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13n/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/dependency-alternatives/t13o/bar-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13o/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..d6ed94c
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13o/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13o/baz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13o/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..7c1f3b7
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13o/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13o/bix-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13o/bix-1.0.0.tar.gz
new file mode 100644
index 0000000..cdbba8d
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13o/bix-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13o/biz-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13o/biz-1.0.0.tar.gz
new file mode 100644
index 0000000..a7908c1
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13o/biz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13o/liba-1.0.0.tar.gz b/tests/common/dependency-alternatives/t13o/liba-1.0.0.tar.gz
new file mode 100644
index 0000000..d9dcd50
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13o/liba-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/dependency-alternatives/t13o/repositories.manifest b/tests/common/dependency-alternatives/t13o/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/dependency-alternatives/t13o/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/satisfy/t12a/libbar-0.1.0.tar.gz b/tests/common/satisfy/t12a/libbar-0.1.0.tar.gz
new file mode 100644
index 0000000..10c7f29
--- /dev/null
+++ b/tests/common/satisfy/t12a/libbar-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t12a/libbaz-1.0.0.tar.gz b/tests/common/satisfy/t12a/libbaz-1.0.0.tar.gz
new file mode 100644
index 0000000..1d498b8
--- /dev/null
+++ b/tests/common/satisfy/t12a/libbaz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t12a/repositories.manifest b/tests/common/satisfy/t12a/repositories.manifest
new file mode 100644
index 0000000..5b70556
--- /dev/null
+++ b/tests/common/satisfy/t12a/repositories.manifest
@@ -0,0 +1 @@
+: 1
diff --git a/tests/common/satisfy/t12b/bar-1.0.0.tar.gz b/tests/common/satisfy/t12b/bar-1.0.0.tar.gz
new file mode 100644
index 0000000..8999e1a
--- /dev/null
+++ b/tests/common/satisfy/t12b/bar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t12b/baz-0.1.0.tar.gz b/tests/common/satisfy/t12b/baz-0.1.0.tar.gz
new file mode 100644
index 0000000..2676c52
--- /dev/null
+++ b/tests/common/satisfy/t12b/baz-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t12b/baz-1.0.0.tar.gz b/tests/common/satisfy/t12b/baz-1.0.0.tar.gz
new file mode 100644
index 0000000..1aec461
--- /dev/null
+++ b/tests/common/satisfy/t12b/baz-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t12b/foo-0.1.0.tar.gz b/tests/common/satisfy/t12b/foo-0.1.0.tar.gz
new file mode 100644
index 0000000..a282f20
--- /dev/null
+++ b/tests/common/satisfy/t12b/foo-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t12b/foo-1.0.0.tar.gz b/tests/common/satisfy/t12b/foo-1.0.0.tar.gz
new file mode 100644
index 0000000..4c66d3d
--- /dev/null
+++ b/tests/common/satisfy/t12b/foo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t12b/libbar-1.0.0.tar.gz b/tests/common/satisfy/t12b/libbar-1.0.0.tar.gz
new file mode 100644
index 0000000..c0fe278
--- /dev/null
+++ b/tests/common/satisfy/t12b/libbar-1.0.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t12b/libbaz-0.1.0.tar.gz b/tests/common/satisfy/t12b/libbaz-0.1.0.tar.gz
new file mode 100644
index 0000000..73c0edb
--- /dev/null
+++ b/tests/common/satisfy/t12b/libbaz-0.1.0.tar.gz
Binary files differ
diff --git a/tests/common/satisfy/t12b/repositories.manifest b/tests/common/satisfy/t12b/repositories.manifest
new file mode 100644
index 0000000..6387e01
--- /dev/null
+++ b/tests/common/satisfy/t12b/repositories.manifest
@@ -0,0 +1,4 @@
+: 1
+:
+location: ../t12a
+role: prerequisite
diff --git a/tests/pkg-build.testscript b/tests/pkg-build.testscript
index b5954f2..86a63f1 100644
--- a/tests/pkg-build.testscript
+++ b/tests/pkg-build.testscript
@@ -171,6 +171,211 @@
# | |-- libfoo-tests-1.0.0.tar.gz
# | `-- repositories.manifest
# |
+# |-- t11a
+# | |-- libfoo-0.1.0.tar.gz
+# | |-- libfoo-1.0.0.tar.gz
+# | |-- libbar-0.1.0.tar.gz
+# | |-- libbar-1.0.0.tar.gz
+# | |-- libbaz-0.1.0.tar.gz
+# | |-- libbaz-1.0.0.tar.gz
+# | |-- libbox-0.1.0.tar.gz
+# | |-- libbox-1.0.0.tar.gz
+# | |-- foo-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}}
+# | |-- fox-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}}
+# | |-- fux-1.0.0.tar.gz -> libfoo
+# | |-- fix-1.0.0.tar.gz -> foo {require {config.foo.extras=true}}
+# | |-- fex-1.0.0.tar.gz -> foo, libfoo {require {config.libfoo.extras=true}}
+# | |-- bar-0.1.0.tar.gz -> libbar == 0.1.0 {require {config.libbar.extras=true}}
+# | |-- bar-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}}
+# | |-- baz-0.1.0.tar.gz -> {libbar libfoo} == 0.1.0 {require {config.libbar.extras=true config.libfoo.extras=true}}
+# | |-- baz-1.0.0.tar.gz -> {libbar libfoo} {require {config.libbar.extras=true config.libfoo.extras=true}}
+# | |-- bac-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
+# | | libbaz {require {config.libbaz.extras=true}},
+# | | libfoo {require {config.libfoo.extras=true}}
+# | |-- bat-1.0.0.tar.gz -> libbaz {require {config.libbaz.extras=true}}
+# | |-- bas-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
+# | | bus {require {config.bus.extras=true}}
+# | |-- bus-1.0.0.tar.gz -> libaz {require {config.libbox.extras=true}},
+# | | foo {require {config.foo.extras=true}}
+# | |-- box-0.1.0.tar.gz -> libbox {require {config.libbox.extras=true}}
+# | |-- box-1.0.0.tar.gz -> {libbar libfoo} {require {config.libbar.extras=true config.libfoo.extras=true}} |
+# | | libbox
+# | |-- bax-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}},
+# | | {libbox libbar} {require {config.libbox.extras=true config.libbar.extras=true}}
+# | |-- bux-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}}
+# | |-- bix-1.0.0.tar.gz -> {libbar bar} {require {config.libbar.extras=true config.bar.extras=true}},
+# | | bux
+# | |-- bex-1.0.0.tar.gz -> libbar
+# | |-- boo-1.0.0.tar.gz -> libbar | libfoo {require {config.libfoo.extras=true}} | libbox
+# | |-- biz-1.0.0.tar.gz -> boo {require {config.boo.extras=true}}
+# | |-- buz-1.0.0.tar.gz -> bux {require {config.bux.extras=true}}
+# | |-- buc-1.0.0.tar.gz -> libfoo {require {config.libfoo.extras=true}},
+# | | bux {require {config.bux.extras=true}}
+# | |-- tax-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
+# | | libfoo
+# | |-- tex-0.1.0.tar.gz -> libfoo {require {config.libfoo.extras=true}}
+# | |-- tex-0.2.0.tar.gz -> libbar,
+# | | libfoo {require {config.libfoo.extras=true}}
+# | |-- tex-0.3.0.tar.gz -> libbar {require {config.libbar.extras=true}},
+# | | libfoo {require {config.libfoo.extras=true}}
+# | |-- tex-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
+# | | libfoo {require {config.libfoo.extras=true}}
+# | |-- tix-0.1.0.tar.gz
+# | |-- tix-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
+# | | tex {require {config.tex.extras=true}}
+# | |-- tiz-1.0.0.tar.gz -> tex {require {config.tex.extras=true}},
+# | | libbar {require {config.libbar.extras=true}}
+# | |-- toz-0.1.0.tar.gz
+# | |-- toz-0.2.0.tar.gz -> libfoo {require {config.libfoo.extras=true}},
+# | | libbar {require {config.libbar.extras=true}}
+# | |-- toz-1.0.0.tar.gz -> libbaz {require {config.libbaz.extras=true}},
+# | | libfoo {require {config.libfoo.extras=true}},
+# | | libbar {require {config.libbar.extras=true}}
+# | |-- tez-1.0.0.tar.gz -> libbox {require {config.libbox.extras=true}},
+# | | toz == 0.1.0 {require {config.toz.extras=true}},
+# | | libbar {require {config.libbar.extras=true}}
+# | |-- tux-1.0.0.tar.gz -> libbox {require {config.libbox.extras=true}},
+# | | tix == 0.1.0
+# | |-- dex-1.0.0.tar.gz -> bar {require {config.bar.extras=true}},
+# | | libfoo {require {config.libfoo.extras=true}}
+# | |-- dix-1.0.0.tar.gz -> libbar {require {config.libbar.extras=true}},
+# | | libbox {require {config.libbox.extras=true}},
+# | | dox {require {config.dox.extras=true}}
+# | |-- diz-1.0.0.tar.gz -> dox {require {config.dox.extras=true}},
+# | | libbox {require {config.libbox.extras=true}},
+# | | libbar {require {config.libbar.extras=true}}
+# | |-- dox-1.0.0.tar.gz -> dex {require {config.dex.extras=true}}
+# | `-- repositories.manifest
+# |
+# |-- t12a
+# | |-- libbaz-1.0.0.tar.gz
+# | |-- libbar-0.1.0.tar.gz -> libbaz
+# | `-- repositories.manifest
+# |
+# |-- t12b -> t12b (prerequisite repository)
+# | |-- libbaz-0.1.0.tar.gz
+# | |-- libbar-1.0.0.tar.gz -> libbaz == 0.1.0
+# | |-- foo-0.1.0.tar.gz
+# | |-- foo-1.0.0.tar.gz -> libbar
+# | |-- bar-1.0.0.tar.gz -> libbar == 0.1.0
+# | |-- baz-0.1.0.tar.gz -> libbaz
+# | |-- baz-1.0.0.tar.gz -> libbaz == 1.0.0
+# | `-- repositories.manifest
+# |
+# |-- t13a
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- biz-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | `-- repositories.manifest
+# |
+# |-- t13b
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- biz-1.0.0.tar.gz -> liba {require {...}}
+# | `-- repositories.manifest
+# |
+# |-- t13c
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)}
+# | |-- baz-1.0.0.tar.gz -> liba {require {...}}
+# | `-- repositories.manifest
+# |
+# |-- t13d
+# | |-- liba-0.1.0.tar.gz
+# | |-- libb-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
+# | | libb ? (...)
+# | |-- baz-1.0.0.tar.gz -> bar, liba {require {...}}
+# | `-- repositories.manifest
+# |
+# |-- t13e
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...)},
+# | | bar ? (...),
+# | | biz
+# | |-- biz-1.0.0.tar.gz -> liba {require {...}}
+# | `-- repositories.manifest
+# |
+# |-- t13f
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | `-- repositories.manifest
+# |
+# |-- t13g
+# | |-- liba-0.1.0.tar.gz
+# | |-- libb-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
+# | | libb {prefer {...} accept (...) reflect (...)}
+# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
+# | | libb ? (...)
+# | |-- biz-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
+# | | libb {prefer {...} accept (...) reflect (...)}
+# | |-- box-1.0.0.tar.gz -> liba {prefer {...} accept (...) reflect (...)},
+# | | libb {prefer {...} accept (...) reflect (...)}
+# | `-- repositories.manifest
+# |
+# |-- t13h
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | `-- repositories.manifest
+# |
+# |-- t13i
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {require {...} reflect (...)}
+# | `-- repositories.manifest
+# |
+# |-- t13j
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- baz-1.0.0.tar.gz -> liba {require {...}}
+# | |-- biz-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | `-- repositories.manifest
+# |
+# |-- t13k
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...)}
+# | `-- repositories.manifest
+# |
+# |-- t13l
+# | |-- liba-0.1.0.tar.gz
+# | |-- libb-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {require {...}},
+# | | libb ? (...)
+# | |-- baz-1.0.0.tar.gz -> liba {prefer {...} accept (...)},
+# | | libb ? (...)
+# | `-- repositories.manifest
+# |
+# |-- t13m
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {require {...}}
+# | |-- baz-1.0.0.tar.gz -> liba {require {...}},
+# | | bar { enable (...) reflect {...}}
+# | |-- biz-1.0.0.tar.gz -> liba {require {...}}
+# | |-- bix-1.0.0.tar.gz -> liba {require {...}}
+# | |-- box-1.0.0.tar.gz -> liba {require {...}}
+# | `-- repositories.manifest
+# |
+# |-- t13n
+# | |-- liba-0.1.0.tar.gz
+# | |-- libb-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {reflect {...}},
+# | | libb {reflect {...}}
+# | `-- repositories.manifest
+# |
+# |-- t13o
+# | |-- liba-0.1.0.tar.gz
+# | |-- bar-1.0.0.tar.gz -> liba {reflect {...}}
+# | |-- baz-1.0.0.tar.gz -> bar {require {...}}
+# | |-- biz-1.0.0.tar.gz -> bar {prefer {...} accept (...)}
+# | |-- bix-1.0.0.tar.gz -> bar {prefer {...} accept (...)}
+# | `-- repositories.manifest
+# |
# `-- git
# |-- libbar.git -> style-basic.git (prerequisite repository)
# |-- libbaz.git
@@ -183,25 +388,43 @@ posix = ($cxx.target.class != 'windows')
+if! $remote
rep_create += 2>!
- cp -r $src/t0a $out/t0a && $rep_create $out/t0a &$out/t0a/packages.manifest
- cp -r $src/t0b $out/t0b && $rep_create $out/t0b &$out/t0b/packages.manifest
- cp -r $src/t0c $out/t0c && $rep_create $out/t0c &$out/t0c/packages.manifest
- cp -r $src/t0d $out/t0d && $rep_create $out/t0d &$out/t0d/packages.manifest
- cp -r $src/t1 $out/t1 && $rep_create $out/t1 &$out/t1/packages.manifest
- cp -r $src/t2 $out/t2 && $rep_create $out/t2 &$out/t2/packages.manifest
- cp -r $src/t3 $out/t3 && $rep_create $out/t3 &$out/t3/packages.manifest
- cp -r $src/t4a $out/t4a && $rep_create $out/t4a &$out/t4a/packages.manifest
- cp -r $src/t4b $out/t4b && $rep_create $out/t4b &$out/t4b/packages.manifest
- cp -r $src/t4c $out/t4c && $rep_create $out/t4c &$out/t4c/packages.manifest
- cp -r $src/t4d $out/t4d && $rep_create $out/t4d &$out/t4d/packages.manifest
- cp -r $src/t4e $out/t4e && $rep_create $out/t4e &$out/t4e/packages.manifest
- cp -r $src/t5 $out/t5 && $rep_create $out/t5 &$out/t5/packages.manifest
- cp -r $src/t6 $out/t6 && $rep_create $out/t6 &$out/t6/packages.manifest
- cp -r $src/t7a $out/t7a && $rep_create $out/t7a &$out/t7a/packages.manifest
- cp -r $src/t7b $out/t7b && $rep_create $out/t7b &$out/t7b/packages.manifest
- cp -r $src/t8a $out/t8a && $rep_create $out/t8a &$out/t8a/packages.manifest
- cp -r $src/t9 $out/t9 && $rep_create $out/t9 &$out/t9/packages.manifest
- cp -r $src/t10 $out/t10 && $rep_create $out/t10 &$out/t10/packages.manifest
+ cp -r $src/t0a $out/t0a && $rep_create $out/t0a &$out/t0a/packages.manifest
+ cp -r $src/t0b $out/t0b && $rep_create $out/t0b &$out/t0b/packages.manifest
+ cp -r $src/t0c $out/t0c && $rep_create $out/t0c &$out/t0c/packages.manifest
+ cp -r $src/t0d $out/t0d && $rep_create $out/t0d &$out/t0d/packages.manifest
+ cp -r $src/t1 $out/t1 && $rep_create $out/t1 &$out/t1/packages.manifest
+ cp -r $src/t2 $out/t2 && $rep_create $out/t2 &$out/t2/packages.manifest
+ cp -r $src/t3 $out/t3 && $rep_create $out/t3 &$out/t3/packages.manifest
+ cp -r $src/t4a $out/t4a && $rep_create $out/t4a &$out/t4a/packages.manifest
+ cp -r $src/t4b $out/t4b && $rep_create $out/t4b &$out/t4b/packages.manifest
+ cp -r $src/t4c $out/t4c && $rep_create $out/t4c &$out/t4c/packages.manifest
+ cp -r $src/t4d $out/t4d && $rep_create $out/t4d &$out/t4d/packages.manifest
+ cp -r $src/t4e $out/t4e && $rep_create $out/t4e &$out/t4e/packages.manifest
+ cp -r $src/t5 $out/t5 && $rep_create $out/t5 &$out/t5/packages.manifest
+ cp -r $src/t6 $out/t6 && $rep_create $out/t6 &$out/t6/packages.manifest
+ cp -r $src/t7a $out/t7a && $rep_create $out/t7a &$out/t7a/packages.manifest
+ cp -r $src/t7b $out/t7b && $rep_create $out/t7b &$out/t7b/packages.manifest
+ cp -r $src/t8a $out/t8a && $rep_create $out/t8a &$out/t8a/packages.manifest
+ cp -r $src/t9 $out/t9 && $rep_create $out/t9 &$out/t9/packages.manifest
+ cp -r $src/t10 $out/t10 && $rep_create $out/t10 &$out/t10/packages.manifest
+ cp -r $src/t11a $out/t11a && $rep_create $out/t11a &$out/t11a/packages.manifest
+ cp -r $src/t12a $out/t12a && $rep_create $out/t12a &$out/t12a/packages.manifest
+ cp -r $src/t12b $out/t12b && $rep_create $out/t12b &$out/t12b/packages.manifest
+ cp -r $src/t13a $out/t13a && $rep_create $out/t13a &$out/t13a/packages.manifest
+ cp -r $src/t13b $out/t13b && $rep_create $out/t13b &$out/t13b/packages.manifest
+ cp -r $src/t13c $out/t13c && $rep_create $out/t13c &$out/t13c/packages.manifest
+ cp -r $src/t13d $out/t13d && $rep_create $out/t13d &$out/t13d/packages.manifest
+ cp -r $src/t13e $out/t13e && $rep_create $out/t13e &$out/t13e/packages.manifest
+ cp -r $src/t13f $out/t13f && $rep_create $out/t13f &$out/t13f/packages.manifest
+ cp -r $src/t13g $out/t13g && $rep_create $out/t13g &$out/t13g/packages.manifest
+ cp -r $src/t13h $out/t13h && $rep_create $out/t13h &$out/t13h/packages.manifest
+ cp -r $src/t13i $out/t13i && $rep_create $out/t13i &$out/t13i/packages.manifest
+ cp -r $src/t13j $out/t13j && $rep_create $out/t13j &$out/t13j/packages.manifest
+ cp -r $src/t13k $out/t13k && $rep_create $out/t13k &$out/t13k/packages.manifest
+ cp -r $src/t13l $out/t13l && $rep_create $out/t13l &$out/t13l/packages.manifest
+ cp -r $src/t13m $out/t13m && $rep_create $out/t13m &$out/t13m/packages.manifest
+ cp -r $src/t13n $out/t13n && $rep_create $out/t13n &$out/t13n/packages.manifest
+ cp -r $src/t13o $out/t13o && $rep_create $out/t13o &$out/t13o/packages.manifest
# Create git repositories.
#
@@ -2712,6 +2935,30 @@ test.options += --no-progress
$pkg_drop libbar libbaz
}
+ : sys-to-src-unhold-same-ver
+ :
+ : Same as above but the version does not change.
+ :
+ {
+ $clone_cfg;
+
+ $* 'sys:libbaz/0.1.0' 2>>EOE;
+ configured sys:libbaz/0.1.0
+ EOE
+
+ $* ?libbaz libbar/0.0.3 2>>EOE;
+ purged libbaz/0.1.0
+ fetched libbaz/0.1.0
+ unpacked libbaz/0.1.0
+ fetched libbar/0.0.3
+ unpacked libbar/0.0.3
+ configured libbaz/0.1.0
+ configured libbar/0.0.3
+ EOE
+
+ $pkg_drop libbar libbaz
+ }
+
: sys-to-src
:
: As above but keep held.
@@ -3382,7 +3629,7 @@ test.options += --no-progress
{
+$clone_cfg
- test.arguments += --yes
+ test.arguments += --yes --plan 'build plan:'
: ambiguity
:
@@ -3409,6 +3656,10 @@ test.options += --no-progress
$clone_cfg;
$* fox ?libbaz 2>>~%EOE%;
+ build plan:
+ new libbaz/1.1.0
+ new fox/1.0.0
+ config.fox.backend=libbaz (set by fox)
fetched libbaz/1.1.0
unpacked libbaz/1.1.0
fetched fox/1.0.0
@@ -3430,6 +3681,10 @@ test.options += --no-progress
$clone_cfg;
$* fox libbaz 2>>~%EOE%;
+ build plan:
+ new libbaz/1.1.0
+ new fox/1.0.0
+ config.fox.backend=libbaz (set by fox)
fetched libbaz/1.1.0
unpacked libbaz/1.1.0
fetched fox/1.0.0
@@ -3454,6 +3709,9 @@ test.options += --no-progress
$* libbaz 2>!;
$* fox 2>>~%EOE%;
+ build plan:
+ new fox/1.0.0
+ config.fox.backend=libbaz (set by fox)
fetched fox/1.0.0
unpacked fox/1.0.0
configured fox/1.0.0
@@ -3473,6 +3731,10 @@ test.options += --no-progress
$pkg_fetch libbaz/1.0.0;
$* fox 2>>~%EOE%;
+ build plan:
+ update libbaz/1.0.0 (required by fox)
+ new fox/1.0.0
+ config.fox.backend=libbaz (set by fox)
unpacked libbaz/1.0.0
fetched fox/1.0.0
unpacked fox/1.0.0
@@ -3497,6 +3759,12 @@ test.options += --no-progress
$clone_cfg;
$* fox foo 2>>~%EOE%;
+ build plan:
+ new libbaz/1.1.0 (required by foo)
+ new libbar/1.0.0 (required by foo, fox)
+ new fox/1.0.0
+ config.fox.backend=libbar (set by fox)
+ new foo/1.0.0
fetched libbaz/1.1.0
unpacked libbaz/1.1.0
fetched libbar/1.0.0
@@ -3525,6 +3793,13 @@ test.options += --no-progress
$clone_cfg;
$* baz fox bar 2>>~%EOE%;
+ build plan:
+ new libbaz/1.1.0 (required by baz)
+ new baz/1.0.0
+ new libbar/1.0.0 (required by bar, fox)
+ new fox/1.0.0
+ config.fox.backend=libbar (set by fox)
+ new bar/1.0.0
fetched libbaz/1.1.0
unpacked libbaz/1.1.0
fetched baz/1.0.0
@@ -3566,6 +3841,10 @@ test.options += --no-progress
$clone_cfg;
$* fox ?libbaz/1.0.0 2>>~%EOE%;
+ build plan:
+ new libbaz/1.0.0
+ new fox/1.0.0
+ config.fox.backend=libbaz (set by fox)
fetched libbaz/1.0.0
unpacked libbaz/1.0.0
fetched fox/1.0.0
@@ -3579,6 +3858,9 @@ test.options += --no-progress
EOE
$* ?libbaz 2>>~%EOE%;
+ build plan:
+ upgrade libbaz/1.1.0
+ reconfigure fox (dependent of libbaz)
disfigured fox/1.0.0
disfigured libbaz/1.0.0
fetched libbaz/1.1.0
@@ -3621,6 +3903,10 @@ test.options += --no-progress
$* box libbox 2>!;
$* box +{ config.box.extras=true } ?libbiz 2>>~%EOE%;
+ build plan:
+ reconfigure/update box/1.0.0
+ config.box.extras=true (user configuration)
+ config.box.backend=libbox (set by box)
disfigured box/1.0.0
configured box/1.0.0
%info: .+box-1.0.0.+ is up to date%
@@ -3628,6 +3914,11 @@ test.options += --no-progress
EOE
$* box +{ config.box.extras=false } libbiz 2>>~%EOE%;
+ build plan:
+ reconfigure/update box/1.0.0
+ config.box.extras=false (user configuration)
+ config.box.backend=libbox (set by box)
+ new libbiz/1.0.0
disfigured box/1.0.0
fetched libbiz/1.0.0
unpacked libbiz/1.0.0
@@ -3667,6 +3958,12 @@ test.options += --no-progress
$* box libbox 2>!;
$* box +{ config.box.extras=true } ?libbox/0.1.0 2>>~%EOE%;
+ build plan:
+ new libbiz/1.0.0 (required by box)
+ drop libbox/1.0.0 (unused)
+ reconfigure/update box/1.0.0
+ config.box.extras=true (user configuration)
+ config.box.backend=libbiz (set by box)
disfigured box/1.0.0
disfigured libbox/1.0.0
fetched libbiz/1.0.0
@@ -3702,6 +3999,12 @@ test.options += --no-progress
$* box libbox 2>!;
$* box +{ config.box.extras=true } libbox/0.1.0 2>>~%EOE%;
+ build plan:
+ new libbiz/1.0.0 (required by box)
+ downgrade libbox/0.1.0
+ reconfigure/update box/1.0.0
+ config.box.extras=true (user configuration)
+ config.box.backend=libbiz (set by box)
disfigured box/1.0.0
disfigured libbox/1.0.0
fetched libbiz/1.0.0
@@ -3739,6 +4042,11 @@ test.options += --no-progress
$clone_cfg;
$* box ?libbiz/0.1.0 2>>~%EOE%;
+ build plan:
+ new libbox/1.0.0 (required by box)
+ new libbaz/1.1.0 (required by box)
+ new box/1.0.0
+ config.box.backend=libbox (set by box)
fetched libbox/1.0.0
unpacked libbox/1.0.0
fetched libbaz/1.1.0
@@ -3767,6 +4075,10 @@ test.options += --no-progress
# libbox as a prerequisite of box.
#
$* libbiz ?libbaz/1.0.0 2>>~%EOE%;
+ build plan:
+ new libbiz/1.0.0
+ downgrade libbaz/1.0.0
+ reconfigure box (dependent of libbaz)
disfigured box/1.0.0
disfigured libbaz/1.1.0
fetched libbiz/1.0.0
@@ -3799,6 +4111,9 @@ test.options += --no-progress
# Make sure the decision is hold for downgraded dependency either.
#
$* ?libbox/0.1.1 2>>~%EOE%;
+ build plan:
+ downgrade libbox/0.1.1
+ reconfigure box (dependent of libbox)
disfigured box/1.0.0
disfigured libbox/1.0.0
fetched libbox/0.1.1
@@ -4134,7 +4449,7 @@ test.options += --no-progress
$* fax/ 2>>~%EOE% != 0;
<depends-enable-clause>:1: error: invalid bool value: multiple names
info: enable condition: (config.fax.libbiz = true)
- % .+fax.manifest:10:10: info: depends value defined here%
+ % fax.manifest:10:10: info: in depends manifest value defined here%
info: while satisfying fax/1.0.0#3
EOE
@@ -4403,6 +4718,8351 @@ test.options += --no-progress
}
}
}
+
+ : version-replacement
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t12b && $rep_fetch
+
+ test.arguments += --yes
+
+ : not-replaced
+ :
+ {
+ $clone_cfg;
+
+ $* bar foo 2>!;
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ libbar configured 0.1.0 available 1.0.0
+ libbaz configured 1.0.0
+ !foo configured 1.0.0
+ libbar configured 0.1.0 available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop bar foo
+ }
+
+ : replaced-scratch
+ :
+ : Test that changing package order on the command line does not result
+ : in a sub-optimal choice of the libbaz version (0.1.0).
+ :
+ : Note that this was not the case until we implemented the builds
+ : re-collection on the package version change.
+ :
+ {
+ $clone_cfg;
+
+ $* foo bar --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ %.*
+ trace: collect_build: add libbaz/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/0.1.0 of dependent libbar/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/0.1.0
+ trace: collect_build_prerequisites: end libbaz/0.1.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0
+ trace: collect_build: libbar/1.0.0 package version needs to be replaced with libbar/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: apply version replacement for libbar/1.0.0
+ trace: collect_build: replacement: libbar/0.1.0
+ trace: collect_build: add libbar/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent foo/1.0.0
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ %.*
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/1.0.0 of dependent libbar/0.1.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/0.1.0 of dependent bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libbar configured 0.1.0 available 1.0.0
+ libbaz configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 0.1.0 available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop foo bar
+ }
+
+ : replaced-inplace
+ :
+ : Test the version replacement optimization. Here libbaz/1.0.0 get
+ : replaced with 0.1.0 but without re-collection from scratch since it
+ : does not have any dependencies.
+ :
+ {
+ $clone_cfg && $rep_add $rep/t12a && $rep_fetch;
+
+ $* libbaz libbar --verbose 5 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ %.*
+ trace: collect_build: pick libbaz/0.1.0 over libbaz/1.0.0
+ trace: collect_build: libbaz/1.0.0 package version needs to be replaced in-place with libbaz/0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/0.1.0 of dependent libbar/1.0.0
+ trace: collect_build_prerequisites: begin libbaz/0.1.0
+ trace: collect_build_prerequisites: end libbaz/0.1.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libbaz configured 0.1.0 available 1.0.0
+ !libbar configured 1.0.0
+ !libbaz configured 0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop libbaz libbar
+ }
+ }
+
+ : drop-dependent
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t12b && $rep_fetch
+
+ test.arguments += --yes
+
+ : unhold
+ :
+ : Test that the being dropped dependent does not constrain a dependency
+ : anymore.
+ :
+ {
+ $clone_cfg;
+
+ $* libbar 2>!;
+
+ $pkg_status -r >>EOO;
+ !libbar configured 1.0.0
+ libbaz configured 0.1.0 available [1.0.0]
+ EOO
+
+ $* baz/0.1.0 ?libbar ?libbaz 2>!;
+
+ $pkg_status -r >>EOO;
+ !baz configured !0.1.0 available 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop baz
+ }
+
+ : unuse
+ :
+ : Unlike the previous test, at the time we check the constraint applied
+ : by libbar on libbaz (== 0.1.0) there is no evidence that libbar will be
+ : dropped, which will happen some later execution plan refinement
+ : iteration.
+ :
+ : @@ This scenario is not supported yet and fails with:
+ :
+ : error: unable to upgrade package libbaz/0.1.0 to 1.0.0
+ : info: because package libbar depends on (libbaz == 0.1.0)
+ : info: package libbaz/1.0.0 required by baz
+ : info: explicitly request up/downgrade of package libbar
+ : info: or explicitly specify package libbaz version to manually satisfy these constraints
+ :
+ : We could probably fix this postponing the constraints check in
+ : collect_order_dependents() until the final execution plan is produced
+ : (after all that refinement iterations). We could have an additional
+ : iteration after all the refinements which would enable the constraint
+ : check in collect_order_dependents().
+ :
+ if false
+ {
+ $clone_cfg;
+
+ $* foo 2>!;
+
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 0.1.0 available [1.0.0]
+ EOO
+
+ $* baz foo/0.1.0 2>|;
+
+ $pkg_status -r >>EOO;
+ EOO
+
+ $pkg_drop foo
+ }
+ }
+
+ : configuration-negotiation-order
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t11a && $rep_fetch
+
+ test.arguments += --yes --plan 'build plan:' --verbose 5 --build-option --quiet
+
+ : initial-collection
+ :
+ {
+ +$clone_cfg
+
+ : postpone
+ :
+ {
+ $clone_cfg;
+
+ $* foo fox fux 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fox/1.0.0
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin fox/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent fox/1.0.0
+ trace: postponed_configurations::add: add {fox 1,1: libfoo} to {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone fox/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fox/1.0.0
+ trace: collect_build_prerequisites: resume fox/1.0.0
+ trace: collect_build_prerequisites: end fox/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo fox | libfoo->{foo/1,1 fox/1,1}}!
+ trace: collect_build_postponed (1): end {foo fox | libfoo->{foo/1,1 fox/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ new libfoo/1.0.0 (required by foo, fox, fux)
+ config.libfoo.extras=true (set by foo)
+ new foo/1.0.0
+ new fox/1.0.0
+ new fux/1.0.0
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !fox configured 1.0.0
+ libfoo configured 1.0.0
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop foo fox fux
+ }
+
+ : postpone-system
+ :
+ {
+ $clone_cfg;
+
+ $* foo fox '?sys:libfoo/*' 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fox/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency sys:libfoo/* of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin fox/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency sys:libfoo/* of dependent fox/1.0.0
+ trace: postponed_configurations::add: add {fox 1,1: libfoo} to {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone fox/1.0.0
+ %.*
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip system sys:libfoo/*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fox/1.0.0
+ trace: collect_build_prerequisites: resume fox/1.0.0
+ trace: collect_build_prerequisites: end fox/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo fox | libfoo->{foo/1,1 fox/1,1}}!
+ trace: collect_build_postponed (1): end {foo fox | libfoo->{foo/1,1 fox/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ configure sys:libfoo/*
+ config.libfoo.extras=true (expected by foo)
+ new foo/1.0.0
+ new fox/1.0.0
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libfoo configured,system !* available 1.0.0 0.1.0
+ !fox configured 1.0.0
+ libfoo configured,system !* available 1.0.0 0.1.0
+ EOO
+
+ $pkg_drop foo fox
+ }
+
+ : postpone-merge
+ :
+ {
+ $clone_cfg;
+
+ $* foo bar baz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: postpone bar/1.0.0
+ trace: collect_build_prerequisites: begin baz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent baz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent baz/1.0.0
+ trace: postponed_configurations::add: add {baz 1,1: libbar libfoo} to {foo | libfoo->{foo/1,1}}
+ trace: postponed_configurations::add: merge {bar | libbar->{bar/1,1}} into {baz foo | libfoo->{baz/1,1 foo/1,1} libbar->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone baz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bar baz foo | libfoo->{baz/1,1 foo/1,1} libbar->{bar/1,1 baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar baz foo | libfoo->{baz/1,1 foo/1,1} libbar->{bar/1,1 baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent baz/1.0.0
+ trace: collect_build_prerequisites: resume baz/1.0.0
+ trace: collect_build_prerequisites: end baz/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar baz foo | libfoo->{baz/1,1 foo/1,1} libbar->{bar/1,1 baz/1,1}}!
+ trace: collect_build_postponed (1): end {bar baz foo | libfoo->{baz/1,1 foo/1,1} libbar->{bar/1,1 baz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ new libfoo/1.0.0 (required by baz, foo)
+ config.libfoo.extras=true (set by baz)
+ new foo/1.0.0
+ new libbar/1.0.0 (required by bar, baz)
+ config.libbar.extras=true (set by bar)
+ new bar/1.0.0
+ new baz/1.0.0
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ !baz configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop foo bar baz
+ }
+
+ : postpone-dependency-dependent
+ :
+ {
+ $clone_cfg;
+
+ $* fex 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fex/1.0.0
+ trace: collect_build_prerequisites: begin fex/1.0.0
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency foo/1.0.0 of dependent fex/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent fex/1.0.0
+ trace: postponed_configurations::add: add {fex 2,1: libfoo} to {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone fex/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fex foo | libfoo->{fex/2,1 foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fex foo | libfoo->{fex/2,1 foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fex/1.0.0
+ trace: collect_build_prerequisites: resume fex/1.0.0
+ trace: collect_build_prerequisites: end fex/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {fex foo | libfoo->{fex/2,1 foo/1,1}}!
+ trace: collect_build_postponed (1): end {fex foo | libfoo->{fex/2,1 foo/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !fex configured 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop fex
+ }
+
+ : premature
+ :
+ {
+ $clone_cfg;
+
+ $* fux foo fox 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fox/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fox/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin fox/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent fox/1.0.0
+ trace: postponed_configurations::add: add {fox 1,1: libfoo} to {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone fox/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo fox | libfoo->{foo/1,1 fox/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fox/1.0.0
+ trace: collect_build_prerequisites: resume fox/1.0.0
+ trace: collect_build_prerequisites: end fox/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo fox | libfoo->{foo/1,1 fox/1,1}}!
+ trace: collect_build_postponed (1): end {foo fox | libfoo->{foo/1,1 fox/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !fox configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop fux foo fox
+ }
+
+ : bogus-postponment
+ :
+ {
+ $clone_cfg;
+
+ $* fux foo fix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (foo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: pkg_build: dep-postpone user-specified foo
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: pkg_build: erase bogus postponement libfoo
+ trace: pkg_build: bogus postponements erased, throwing
+ trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: pkg_build: dep-postpone user-specified foo
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (foo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: pkg_build: dep-postpone user-specified foo
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fix/1.0.0
+ trace: collect_build_prerequisites: resume fix/1.0.0
+ trace: collect_build_prerequisites: end fix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {fix | foo->{fix/1,1}}!
+ trace: collect_build_postponed (2): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (2): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (1): end {fix | foo->{fix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop fux foo fix
+ }
+ }
+
+ : existing
+ :
+ {
+ +$clone_cfg
+
+ : dependency
+ :
+ {
+ $clone_cfg;
+
+ $* libfoo 2>!;
+
+ $* foo 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (1): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ reconfigure/update libfoo/1.0.0 (required by foo)
+ config.libfoo.extras=true (set by foo)
+ new foo/1.0.0
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libfoo configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop foo libfoo
+ }
+
+ : dependent-single-position
+ :
+ {
+ +$clone_cfg
+
+ : basic
+ :
+ {
+ $clone_cfg;
+
+ $* foo 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (1): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ # Downgrade the dependency.
+ #
+ $* ?libfoo/0.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libfoo/1.0.0: update to libfoo/0.1.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: reeval foo/1.0.0
+ %.*
+ trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
+ trace: postponed_configurations::add: add {foo^ 1,1: libfoo} to {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent foo/1.0.0 results in {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluated foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo^ | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/0.1.0
+ trace: collect_build_prerequisites: end libfoo/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo^ | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (1): end {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ downgrade libfoo/0.1.0
+ config.libfoo.extras=true (set by foo)
+ reconfigure/update foo/1.0.0 (dependent of libfoo)
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ # Reconfigure the dependency and hold.
+ #
+ $* libfoo/0.1.0 +{ config.libfoo.extras=true } 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/0.1.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: reeval foo/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {foo^ 1,1: libfoo} to {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent foo/1.0.0 results in {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluated foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo^ | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo^ | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (1): end {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ reconfigure/update libfoo/0.1.0
+ config.libfoo.extras=true (user configuration)
+ reconfigure/update foo/1.0.0 (dependent of libfoo)
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libfoo configured !0.1.0 available 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ # Upgrade the dependency and unhold existing dependent.
+ #
+ $* libfoo ?foo 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo^ | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: reeval foo/1.0.0
+ %.*
+ trace: collect_build: pick libfoo/1.0.0 over libfoo/0.1.0
+ trace: postponed_configurations::add: add {foo^ 1,1: libfoo} to {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent foo/1.0.0 results in {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: re-evaluated foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo^ | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo^ | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (1): end {foo^ | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: foo/1.0.0: unused
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ %.*
+ trace: collect_drop: foo/1.0.0 package version needs to be replaced with drop
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: skip expected to be dropped existing dependent foo of dependency libfoo
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_drop: overwrite foo
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ upgrade libfoo/1.0.0
+ drop foo/1.0.0 (unused)
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop libfoo
+ }
+
+ : postpone-existing
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # fix/1.0.0: depends: foo(c)
+ # foo/1.0.0: depends: libfoo(c)
+ #
+ # fix/0.1.0: depends: foo == 0.1.0
+ # foo/0.1.0: depends: libfoo(c)
+ #
+ $* fix 2>!;
+
+ $* libfoo/0.1.0 fix/0.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/0.1.0
+ trace: collect_build: add fix/0.1.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo^ | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_prerequisites: begin fix/0.1.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/0.1.0
+ trace: collect_build: add fix/0.1.0
+ %.*
+ trace: collect_build_prerequisites: skip expected to be built existing dependent foo of dependency libfoo
+ trace: collect_build_prerequisites: begin libfoo/0.1.0
+ trace: collect_build_prerequisites: end libfoo/0.1.0
+ %.*
+ trace: collect_build_prerequisites: begin fix/0.1.0
+ %.*
+ trace: collect_build: apply version replacement for foo/0.1.0
+ trace: collect_build: replacement: foo/0.1.0
+ trace: collect_build: add foo/0.1.0
+ info: package fix dependency on (foo == 0.1.0) is forcing downgrade of foo/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency foo/0.1.0 of dependent fix/0.1.0
+ %.*
+ trace: collect_build_prerequisites: skip being built existing dependent fix of dependency foo
+ trace: collect_build_prerequisites: begin foo/0.1.0
+ %.*
+ trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/0.1.0 of dependent foo/0.1.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/0.1.0
+ trace: collect_build: add fix/0.1.0
+ trace: pkg_build: dep-postpone user-specified libfoo
+ %.*
+ trace: collect_build_prerequisites: begin fix/0.1.0
+ %.*
+ trace: collect_build: apply version replacement for foo/0.1.0
+ trace: collect_build: replacement: foo/0.1.0
+ trace: collect_build: add foo/0.1.0
+ info: package fix dependency on (foo == 0.1.0) is forcing downgrade of foo/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency foo/0.1.0 of dependent fix/0.1.0
+ %.*
+ trace: collect_build_prerequisites: skip being built existing dependent fix of dependency foo
+ trace: collect_build_prerequisites: begin foo/0.1.0
+ %.*
+ trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent foo/0.1.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/0.1.0
+ trace: collect_build_prerequisites: end fix/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent foo of dependency libfoo
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/0.1.0
+ trace: collect_build_prerequisites: end libfoo/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/0.1.0
+ trace: collect_build_prerequisites: resume foo/0.1.0
+ trace: collect_build_prerequisites: end foo/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (1): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libfoo configured !0.1.0 available 1.0.0
+ !fix configured !0.1.0 available 1.0.0
+ foo configured 0.1.0 available 1.0.0
+ !libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop fix libfoo --drop-dependent
+ }
+ }
+
+ : dependent-multiple-positions
+ :
+ {
+ +$clone_cfg
+
+ : non-negotiated
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ $* tex 2>!;
+
+ $* libfoo/0.1.0 libbar/0.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/0.1.0
+ trace: collect_build: add libbar/0.1.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of existing dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (1): cannot re-evaluate dependent tex to dependency index 2 due to earlier dependency index 1 in {tex^ | libbar->{tex/1,1}}, skipping {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (0): postpone cfg-negotiation of {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (1): begin {tex^ | libbar->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libbar->{tex/1,1}}
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ %.*
+ trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex^ | libbar->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libbar->{tex/1,1}}!
+ trace: collect_build_postponed (2): begin {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/0.1.0
+ trace: collect_build_prerequisites: end libfoo/0.1.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tex^ | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (2): end {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (1): end {tex^ | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ build plan:
+ downgrade libfoo/0.1.0
+ config.libfoo.extras=true (set by tex)
+ downgrade libbar/0.1.0
+ config.libbar.extras=true (set by tex)
+ reconfigure/update tex/1.0.0 (dependent of libbar)
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libbar configured !0.1.0 available 1.0.0
+ !libfoo configured !0.1.0 available 1.0.0
+ !tex configured 1.0.0
+ !libbar configured !0.1.0 available 1.0.0
+ !libfoo configured !0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop tex libfoo libbar
+ }
+
+ : negotiated
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # bar: depends: libbar == 0.1.0 (c)
+ #
+ $* tex 2>!;
+
+ $* libfoo/0.1.0 bar/0.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/0.1.0
+ trace: collect_build: add bar/0.1.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: begin bar/0.1.0
+ %.*
+ trace: collect_build: add libbar/0.1.0
+ info: package bar dependency on (libbar == 0.1.0) is forcing downgrade of libbar/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of dependent bar/0.1.0
+ trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: postpone bar/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ %.*
+ trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0
+ %.*
+ trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
+ trace: postponed_configurations::add: add {tex^ 2,1: libfoo} to {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/0.1.0
+ trace: collect_build_prerequisites: end libfoo/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tex^ | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (2): begin {bar | libbar->{bar/1,1}}
+ %.*
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {bar | libbar->{bar/1,1}}
+ trace: collect_build_postponed (2): cannot re-evaluate dependent tex to dependency index 1 due to greater dependency index 2 in {tex^ | libfoo->{tex/2,1}}!, throwing postpone_position
+ trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libfoo/0.1.0
+ trace: collect_build: add bar/0.1.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of existing dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: begin bar/0.1.0
+ %.*
+ trace: collect_build: add libbar/0.1.0
+ info: package bar dependency on (libbar == 0.1.0) is forcing downgrade of libbar/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of dependent bar/0.1.0
+ trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: postpone bar/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (1): pos-postpone existing dependent tex re-evaluation to dependency index 2 due to recorded index 1, skipping {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (0): postpone cfg-negotiation of {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (1): begin {bar | libbar->{bar/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bar | libbar->{bar/1,1}}
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ %.*
+ trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {bar | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {bar tex^ | libbar->{bar/1,1 tex/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar tex^ | libbar->{bar/1,1 tex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bar/0.1.0
+ trace: collect_build_prerequisites: resume bar/0.1.0
+ trace: collect_build_prerequisites: end bar/0.1.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar tex^ | libbar->{bar/1,1 tex/1,1}}!
+ trace: collect_build_postponed (2): begin {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex^ | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/0.1.0
+ trace: collect_build_prerequisites: end libfoo/0.1.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tex^ | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (2): end {tex^ | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (1): end {bar | libbar->{bar/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libfoo configured !0.1.0 available 1.0.0
+ !tex configured 1.0.0
+ libbar configured 0.1.0 available 1.0.0
+ !libfoo configured !0.1.0 available 1.0.0
+ !bar configured !0.1.0 available 1.0.0
+ libbar configured 0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop tex libfoo bar
+ }
+
+ : up-negotiate
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # baz: depends: {libbar libfoo} == 0.1.0 (c)
+ #
+ $* tex 2>!;
+
+ $* baz/0.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add baz/0.1.0
+ trace: collect_build_prerequisites: begin baz/0.1.0
+ %.*
+ trace: collect_build: add libbar/0.1.0
+ info: package baz dependency on (libbar == 0.1.0) is forcing downgrade of libbar/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/0.1.0 of dependent baz/0.1.0
+ trace: collect_build: add libfoo/0.1.0
+ info: package baz dependency on (libfoo == 0.1.0) is forcing downgrade of libfoo/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent baz/0.1.0
+ trace: postponed_configurations::add: create {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone baz/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ %.*
+ trace: collect_build: pick libbar/0.1.0 over libbar/1.0.0
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {baz tex^ | libbar->{baz/1,1 tex/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {baz tex^ | libbar->{baz/1,1 tex/1,1} libfoo->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/0.1.0
+ trace: collect_build_prerequisites: end libbar/0.1.0
+ trace: collect_build_prerequisites: begin libfoo/0.1.0
+ trace: collect_build_prerequisites: end libfoo/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent baz/0.1.0
+ trace: collect_build_prerequisites: resume baz/0.1.0
+ trace: collect_build_prerequisites: end baz/0.1.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build: pick libfoo/0.1.0 over libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/0.1.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {baz tex^ | libbar->{baz/1,1 tex/1,1} libfoo->{baz/1,1}}?
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/0.1.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {baz tex^ | libbar->{baz/1,1 tex/1,1} libfoo->{baz/1,1 tex/2,1}}!
+ trace: collect_build_postponed (1): end {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libbar configured 0.1.0 available 1.0.0
+ libfoo configured 0.1.0 available 1.0.0
+ !baz configured !0.1.0 available 1.0.0
+ libbar configured 0.1.0 available 1.0.0
+ libfoo configured 0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop tex baz
+ }
+
+ : replace-re-evaluation
+ :
+ {
+ +$clone_cfg
+
+ : initial-collection
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ # baz: depends: {libbar libfoo} (c)
+ #
+ $* bax baz 2>!;
+
+ $* libbox/0.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libbox/0.1.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of existing dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libbox->{bax/2,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bax^ | libbox->{bax/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1}}
+ %.*
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {bax^ 2,1: libbox libbar} to {bax^ | libbox->{bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
+ %.*
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build_prerequisites: reeval baz/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated baz/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libfoo
+ trace: collect_build_postponed (1): cannot re-evaluate dependent bax to dependency index 1 since it is already re-evaluated to greater index 2 in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}, throwing postpone_position
+ trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libbox/0.1.0
+ %.*
+ trace: collect_build_prerequisites: replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build_prerequisites: reeval baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated baz/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
+ %.*
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}?, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {bax^ | libfoo->{bax/1,1}} failed due to dependent bax, refining configuration
+ trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build_prerequisites: reeval baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated baz/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbox/0.1.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: begin libbox/0.1.0
+ trace: collect_build_prerequisites: end libbox/0.1.0
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent baz/1.0.0
+ trace: collect_build_prerequisites: resume baz/1.0.0
+ trace: collect_build_prerequisites: end baz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}!
+ trace: collect_build_postponed (1): end {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libbox configured !0.1.0 available 1.0.0
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ !libbox configured !0.1.0 available 1.0.0
+ libfoo configured 1.0.0
+ !baz configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop bax baz libbox
+ }
+
+ : collect-postponed
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ # baz: depends: {libbar libfoo} (c)
+ #
+ # box: depends: libbox == 0.1.0 (c)
+ #
+ $* bax baz 2>!;
+
+ $* box/0.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add box/0.1.0
+ trace: collect_build_prerequisites: begin box/0.1.0
+ %.*
+ trace: collect_build: add libbox/0.1.0
+ info: package box dependency on (libbox == 0.1.0) is forcing downgrade of libbox/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent box/0.1.0
+ trace: postponed_configurations::add: create {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: postpone box/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {bax^ 2,1: libbox libbar} to {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}
+ %.*
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build_prerequisites: reeval baz/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated baz/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libfoo
+ trace: collect_build_postponed (1): cannot re-evaluate dependent bax to dependency index 1 since it is already re-evaluated to greater index 2 in {bax^ baz^ box | libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}, throwing postpone_position
+ trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add box/0.1.0
+ trace: collect_build_prerequisites: begin box/0.1.0
+ %.*
+ trace: collect_build: add libbox/0.1.0
+ info: package box dependency on (libbox == 0.1.0) is forcing downgrade of libbox/1.0.0 to 0.1.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent box/0.1.0
+ trace: postponed_configurations::add: create {box | libbox->{box/1,1}}
+ trace: collect_build_prerequisites: postpone box/0.1.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {box | libbox->{box/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): pos-postpone existing dependent bax re-evaluation to dependency index 2 due to recorded index 1, skipping {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (0): replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1
+ trace: collect_build: add libfoo/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (0): postpone cfg-negotiation of {box | libbox->{box/1,1}}
+ trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build_prerequisites: reeval baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated baz/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
+ trace: postponed_configurations::add: merge {box | libbox->{box/1,1}} into {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}?
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 merges non-negotiated and/or being negotiated configurations in and results in {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1 box/1,1}}?, throwing merge_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {bax^ | libfoo->{bax/1,1}} failed due to non-negotiated clusters, force-merging based on shadow cluster {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1 box/1,1}}?
+ trace: collect_build_postponed (0): force-merge {box | libbox->{box/1,1}} into {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (1): begin {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build_prerequisites: reeval baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}} (shadow cluster-based)
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{box/1,1} libbar->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated baz/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{box/1,1} libbar->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: begin libbox/0.1.0
+ trace: collect_build_prerequisites: end libbox/0.1.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{box/1,1} libbar->{baz/1,1}}? (shadow cluster-based)
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is shadow-negotiated
+ trace: collect_build_prerequisites: dependency libbox/0.1.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent baz/1.0.0
+ trace: collect_build_prerequisites: resume baz/1.0.0
+ trace: collect_build_prerequisites: end baz/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent box/0.1.0
+ trace: collect_build_prerequisites: resume box/0.1.0
+ trace: collect_build_prerequisites: end box/0.1.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bax^ baz^ box | libfoo->{bax/1,1 baz/1,1} libbox->{bax/2,1 box/1,1} libbar->{bax/2,1 baz/1,1}}!
+ trace: collect_build_postponed (1): end {bax^ box | libfoo->{bax/1,1} libbox->{box/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 0.1.0 available 1.0.0
+ libfoo configured 1.0.0
+ !baz configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !box configured !0.1.0 available 1.0.0
+ libbox configured 0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop bax baz box
+ }
+
+ : bogus-harmless
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bax: depends: libfoo(c)
+ # depends: {libbox libbar} (c)
+ #
+ # baz: depends: {libbar libfoo} (c)
+ #
+ $* bax baz 2>!;
+
+ $* libbox/0.1.0 ?baz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libbox/0.1.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of existing dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libbox->{bax/2,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bax^ | libbox->{bax/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1}}
+ %.*
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {bax^ 2,1: libbox libbar} to {bax^ | libbox->{bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: reeval baz/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated baz/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libfoo
+ trace: collect_build_postponed (1): cannot re-evaluate dependent bax to dependency index 1 since it is already re-evaluated to greater index 2 in {bax^ baz^ | libbox->{bax/2,1} libbar->{bax/2,1 baz/1,1} libfoo->{baz/1,1}}, throwing postpone_position
+ trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libbox/0.1.0
+ %.*
+ trace: collect_build_prerequisites: replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_prerequisites: reeval baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated baz/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
+ %.*
+ trace: collect_build_prerequisites: cfg-postponing dependent bax/1.0.0 involves (being) negotiated configurations and results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}?, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {bax^ | libfoo->{bax/1,1}} failed due to dependent bax, refining configuration
+ trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_prerequisites: reeval baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: add {baz^ 1,1: libbar libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent baz/1.0.0 results in {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ trace: collect_build_prerequisites: re-evaluated baz/1.0.0
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (1): skip being built existing dependent baz of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: add {bax 2,1: libbox libbar} to {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{baz/1,1}}?
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bax/1.0.0 is negotiated
+ trace: collect_build_prerequisites: collecting cfg-postponed dependency libbox/0.1.0 of dependent bax/1.0.0
+ trace: collect_build_prerequisites: begin libbox/0.1.0
+ trace: collect_build_prerequisites: end libbox/0.1.0
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bax/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent baz/1.0.0
+ trace: collect_build_prerequisites: resume baz/1.0.0
+ trace: collect_build_prerequisites: end baz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bax^ baz^ | libfoo->{bax/1,1 baz/1,1} libbar->{bax/2,1 baz/1,1} libbox->{bax/2,1}}!
+ trace: collect_build_postponed (1): end {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: baz/1.0.0: unused
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ %.*
+ trace: collect_drop: baz/1.0.0 package version needs to be replaced with drop
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libbox/0.1.0
+ trace: pkg_build: dep-postpone user-specified libbox
+ trace: collect_drop: overwrite baz
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (0): erase bogus postponement libbox
+ trace: collect_build_postponed (0): bogus postponements erased, throwing
+ trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add libbox/0.1.0
+ %.*
+ trace: collect_build_prerequisites: replace dependency at index 2 of existing dependent bax/1.0.0 with dependency libfoo/1.0.0 at index 1
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of existing dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax^ | libfoo->{bax/1,1}}
+ trace: collect_drop: overwrite baz
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): skip being dropped existing dependent baz of dependency libfoo
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build: add bax/1.0.0
+ trace: collect_build_prerequisites: reeval bax/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {bax^ 1,1: libfoo} to {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bax/1.0.0 results in {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bax^ | libfoo->{bax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ %.*
+ trace: collect_build: pick libbox/0.1.0 over libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/0.1.0 of dependent bax/1.0.0
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bax/1.0.0
+ trace: postponed_configurations::add: create {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_prerequisites: postpone bax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bax^ | libfoo->{bax/1,1}}!
+ trace: collect_build_postponed (2): begin {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbox
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent bax of dependency libbar
+ trace: collect_build_postponed (2): skip being dropped existing dependent baz of dependency libbar
+ trace: collect_build_postponed (2): cfg-negotiate begin {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/0.1.0
+ trace: collect_build_prerequisites: end libbox/0.1.0
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bax/1.0.0
+ trace: collect_build_prerequisites: resume bax/1.0.0
+ trace: collect_build_prerequisites: end bax/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bax | libbox->{bax/2,1} libbar->{bax/2,1}}!
+ trace: collect_build_postponed (2): end {bax | libbox->{bax/2,1} libbar->{bax/2,1}}
+ trace: collect_build_postponed (1): end {bax^ | libfoo->{bax/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !libbox configured !0.1.0 available 1.0.0
+ !bax configured 1.0.0
+ libbar configured 1.0.0
+ !libbox configured !0.1.0 available 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop bax libbox
+ }
+ }
+ }
+ }
+
+ : postponed-collection
+ :
+ {
+ +$clone_cfg
+
+ : backtrace
+ :
+ {
+ $clone_cfg;
+
+ $* foo bar box 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build: add box/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: postpone bar/1.0.0
+ trace: collect_build_prerequisites: begin box/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent box/1.0.0 since max index is reached: 0
+ info: dependency alternative: {libbar libfoo}
+ {
+ require
+ {
+ config.libbar.extras = true
+ config.libfoo.extras = true
+ }
+ }
+ trace: collect_build_prerequisites: postpone box/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (2): begin {bar | libbar->{bar/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {bar | libbar->{bar/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bar | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): index 1 collect alt-postponed box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent box/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent box/1.0.0
+ trace: postponed_configurations::add: add {box 1,1: libbar libfoo} to {foo | libfoo->{foo/1,1}}!
+ trace: postponed_configurations::add: merge {bar | libbar->{bar/1,1}}! into {box foo | libfoo->{box/1,1 foo/1,1} libbar->{box/1,1}}!
+ %.*
+ trace: collect_build_prerequisites: cfg-postponing dependent box/1.0.0 involves (being) negotiated configurations and results in {bar box foo | libfoo->{box/1,1 foo/1,1} libbar->{bar/1,1 box/1,1}}!, throwing retry_configuration
+ trace: collect_build_postponed (0): cfg-negotiation of {foo | libfoo->{foo/1,1}} failed due to dependent box, refining configuration
+ trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (2): begin {bar | libbar->{bar/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {bar | libbar->{bar/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bar | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (2): index 1 collect alt-postponed box/1.0.0
+ trace: collect_build_prerequisites: resume box/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent box/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent box/1.0.0
+ trace: postponed_configurations::add: add {box 1,1: libbar libfoo} to {foo | libfoo->{foo/1,1}}!
+ trace: postponed_configurations::add: merge {bar | libbar->{bar/1,1}}! into {box foo | libfoo->{box/1,1 foo/1,1} libbar->{box/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent box/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent box/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent box/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end box/1.0.0
+ trace: collect_build_postponed (2): end {bar | libbar->{bar/1,1}}
+ trace: collect_build_postponed (1): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ !box configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop foo bar box
+ }
+
+ : premature
+ :
+ {
+ $clone_cfg;
+
+ $* fux fix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fix/1.0.0
+ trace: collect_build_prerequisites: resume fix/1.0.0
+ trace: collect_build_prerequisites: end fix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {fix | foo->{fix/1,1}}!
+ trace: collect_build_postponed (2): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (2): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (1): end {fix | foo->{fix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ !fix configured 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop fux fix
+ }
+
+ : double-premature
+ :
+ {
+ $clone_cfg;
+
+ $* fux bex fix buz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add bex/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build: add buz/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin bex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent bex/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end bex/1.0.0
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: collect_build_prerequisites: begin buz/1.0.0
+ %.*
+ trace: collect_build: add bux/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bux/1.0.0 of dependent buz/1.0.0
+ trace: postponed_configurations::add: create {buz | bux->{buz/1,1}}
+ trace: collect_build_prerequisites: postpone buz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add bex/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build: add buz/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin bex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent bex/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end bex/1.0.0
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: collect_build_prerequisites: begin buz/1.0.0
+ %.*
+ trace: collect_build: add bux/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bux/1.0.0 of dependent buz/1.0.0
+ trace: postponed_configurations::add: create {buz | bux->{buz/1,1}}
+ trace: collect_build_prerequisites: postpone buz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fix/1.0.0
+ trace: collect_build_prerequisites: resume fix/1.0.0
+ trace: collect_build_prerequisites: end fix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {fix | foo->{fix/1,1}}!
+ trace: collect_build_postponed (2): begin {buz | bux->{buz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {buz | bux->{buz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bux/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libbar/1.0.0 of dependent bux/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libbar), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add bex/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build: add buz/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin bex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libbar/1.0.0 of dependent bex/1.0.0
+ trace: collect_build_prerequisites: end bex/1.0.0
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: collect_build_prerequisites: begin buz/1.0.0
+ %.*
+ trace: collect_build: add bux/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bux/1.0.0 of dependent buz/1.0.0
+ trace: postponed_configurations::add: create {buz | bux->{buz/1,1}}
+ trace: collect_build_prerequisites: postpone buz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fix/1.0.0
+ trace: collect_build_prerequisites: resume fix/1.0.0
+ trace: collect_build_prerequisites: end fix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {fix | foo->{fix/1,1}}!
+ trace: collect_build_postponed (2): begin {buz | bux->{buz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {buz | bux->{buz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bux/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bux/1.0.0
+ trace: postponed_configurations::add: create {bux | libbar->{bux/1,1}}
+ trace: collect_build_prerequisites: postpone bux/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent buz/1.0.0
+ trace: collect_build_prerequisites: resume buz/1.0.0
+ trace: collect_build_prerequisites: end buz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {buz | bux->{buz/1,1}}!
+ trace: collect_build_postponed (3): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (4): begin {bux | libbar->{bux/1,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {bux | libbar->{bux/1,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent bux/1.0.0
+ trace: collect_build_prerequisites: resume bux/1.0.0
+ trace: collect_build_prerequisites: end bux/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {bux | libbar->{bux/1,1}}!
+ trace: collect_build_postponed (4): end {bux | libbar->{bux/1,1}}
+ trace: collect_build_postponed (3): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (2): end {buz | bux->{buz/1,1}}
+ trace: collect_build_postponed (1): end {fix | foo->{fix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ !fix configured 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ !bex configured 1.0.0
+ libbar configured 1.0.0
+ !buz configured 1.0.0
+ bux configured 1.0.0
+ libbar configured 1.0.0
+ EOO
+
+ $pkg_drop fux bex fix buz
+ }
+
+ : up-negotiate-dependency
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bar: depends: libbar(c)
+ #
+ # bux: depends: libbar(c)
+ #
+ # bix: depends: {libbar bar} (c)
+ # depends: bux
+ #
+ $* bix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add bix/1.0.0
+ trace: collect_build_prerequisites: begin bix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bix/1.0.0
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent bix/1.0.0
+ trace: postponed_configurations::add: create {bix | libbar->{bix/1,1} bar->{bix/1,1}}
+ trace: collect_build_prerequisites: postpone bix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bix | libbar->{bix/1,1} bar->{bix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {bix | libbar->{bix/1,1} bar->{bix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {bix | libbar->{bix/1,1} bar->{bix/1,1}}?
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bix/1.0.0
+ trace: collect_build_prerequisites: resume bix/1.0.0
+ %.*
+ trace: collect_build: add bux/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency bux/1.0.0 of dependent bix/1.0.0
+ trace: collect_build_prerequisites: begin bux/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bux/1.0.0
+ trace: postponed_configurations::add: add {bux 1,1: libbar} to {bar bix | libbar->{bar/1,1 bix/1,1} bar->{bix/1,1}}?
+ %.*
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bux/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bux/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bux/1.0.0
+ trace: collect_build_prerequisites: end bix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar bix bux | libbar->{bar/1,1 bix/1,1 bux/1,1} bar->{bix/1,1}}!
+ trace: collect_build_postponed (1): end {bix | libbar->{bix/1,1} bar->{bix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bix configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ bux configured 1.0.0
+ libbar configured 1.0.0
+ libbar configured 1.0.0
+ EOO
+
+ $pkg_drop bix
+ }
+
+ : postponed-alts
+ :
+ {
+ +$clone_cfg
+
+ : with-premature
+ :
+ {
+ $clone_cfg;
+
+ $* fux boo 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add boo/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent boo/1.0.0 since max index is reached: 0
+ info: dependency alternative: libbar
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (0): index 1 collect alt-postponed boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent boo/1.0.0 since max index is reached: 1
+ info: dependency alternative: libfoo
+ {
+ require
+ {
+ config.libfoo.extras = true
+ }
+ }
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (0): index 2 collect alt-postponed boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent boo/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add boo/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent boo/1.0.0 since max index is reached: 0
+ info: dependency alternative: libbar
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (0): index 1 collect alt-postponed boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent boo/1.0.0 since max index is reached: 1
+ info: dependency alternative: libfoo
+ {
+ require
+ {
+ config.libfoo.extras = true
+ }
+ }
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (0): index 2 collect alt-postponed boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent boo/1.0.0
+ trace: postponed_configurations::add: create {boo | libfoo->{boo/1,2}}
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (1): begin {boo | libfoo->{boo/1,2}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {boo | libfoo->{boo/1,2}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ trace: collect_build_prerequisites: end boo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {boo | libfoo->{boo/1,2}}!
+ trace: collect_build_postponed (1): end {boo | libfoo->{boo/1,2}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ !boo configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop fux boo
+ }
+
+ : with-premature-complex
+ :
+ {
+ $clone_cfg;
+
+ $* fux bex fix biz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add bex/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build: add biz/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin bex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent bex/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end bex/1.0.0
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: collect_build_prerequisites: begin biz/1.0.0
+ %.*
+ trace: collect_build: add boo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency boo/1.0.0 of dependent biz/1.0.0
+ trace: postponed_configurations::add: create {biz | boo->{biz/1,1}}
+ trace: collect_build_prerequisites: postpone biz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add fux/1.0.0
+ trace: collect_build: add bex/1.0.0
+ trace: collect_build: add fix/1.0.0
+ trace: collect_build: add biz/1.0.0
+ trace: collect_build_prerequisites: begin fux/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent fux/1.0.0
+ trace: collect_build_prerequisites: end fux/1.0.0
+ trace: collect_build_prerequisites: begin bex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent bex/1.0.0
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: end bex/1.0.0
+ trace: collect_build_prerequisites: begin fix/1.0.0
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent fix/1.0.0
+ trace: postponed_configurations::add: create {fix | foo->{fix/1,1}}
+ trace: collect_build_prerequisites: postpone fix/1.0.0
+ trace: collect_build_prerequisites: begin biz/1.0.0
+ %.*
+ trace: collect_build: add boo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency boo/1.0.0 of dependent biz/1.0.0
+ trace: postponed_configurations::add: create {biz | boo->{biz/1,1}}
+ trace: collect_build_prerequisites: postpone biz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {fix | foo->{fix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent fix/1.0.0
+ trace: collect_build_prerequisites: resume fix/1.0.0
+ trace: collect_build_prerequisites: end fix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {fix | foo->{fix/1,1}}!
+ trace: collect_build_postponed (2): begin {biz | boo->{biz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {biz | boo->{biz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent boo/1.0.0 since max index is reached: 0
+ info: dependency alternative: libbar
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent biz/1.0.0
+ trace: collect_build_prerequisites: resume biz/1.0.0
+ trace: collect_build_prerequisites: end biz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {biz | boo->{biz/1,1}}!
+ trace: collect_build_postponed (3): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (3): index 1 collect alt-postponed boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent boo/1.0.0
+ trace: collect_build_prerequisites: end boo/1.0.0
+ trace: collect_build_postponed (3): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (2): end {biz | boo->{biz/1,1}}
+ trace: collect_build_postponed (1): end {fix | foo->{fix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !fux configured 1.0.0
+ libfoo configured 1.0.0
+ !fix configured 1.0.0
+ foo configured 1.0.0
+ libfoo configured 1.0.0
+ !bex configured 1.0.0
+ libbar configured 1.0.0
+ !biz configured 1.0.0
+ boo configured 1.0.0
+ libbar configured 1.0.0
+ EOO
+
+ $pkg_drop fux bex fix biz
+ }
+
+ : up-negotiate
+ :
+ {
+ $clone_cfg;
+
+ $* foo boo 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add boo/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent boo/1.0.0 since max index is reached: 0
+ info: dependency alternative: libbar
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (1): index 1 collect alt-postponed boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent boo/1.0.0 since max index is reached: 1
+ info: dependency alternative: libfoo
+ {
+ require
+ {
+ config.libfoo.extras = true
+ }
+ }
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (1): index 2 collect alt-postponed boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent boo/1.0.0
+ trace: postponed_configurations::add: add {boo 1,2: libfoo} to {foo | libfoo->{foo/1,1}}!
+ %.*
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent boo/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent boo/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end boo/1.0.0
+ trace: collect_build_postponed (1): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !boo configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop foo boo
+ }
+
+ : after-negotiation
+ :
+ {
+ $clone_cfg;
+
+ $* foo biz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add biz/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: create {foo | libfoo->{foo/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin biz/1.0.0
+ %.*
+ trace: collect_build: add boo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency boo/1.0.0 of dependent biz/1.0.0
+ trace: postponed_configurations::add: create {biz | boo->{biz/1,1}}
+ trace: collect_build_prerequisites: postpone biz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {foo | libfoo->{foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_postponed (2): begin {biz | boo->{biz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {biz | boo->{biz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent boo/1.0.0 since max index is reached: 0
+ info: dependency alternative: libbar
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent biz/1.0.0
+ trace: collect_build_prerequisites: resume biz/1.0.0
+ trace: collect_build_prerequisites: end biz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {biz | boo->{biz/1,1}}!
+ trace: collect_build_postponed (2): index 1 collect alt-postponed boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: alt-postpone dependent boo/1.0.0 since max index is reached: 1
+ info: dependency alternative: libfoo
+ {
+ require
+ {
+ config.libfoo.extras = true
+ }
+ }
+ trace: collect_build_prerequisites: postpone boo/1.0.0
+ trace: collect_build_postponed (2): index 2 collect alt-postponed boo/1.0.0
+ trace: collect_build_prerequisites: resume boo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent boo/1.0.0
+ trace: postponed_configurations::add: add {boo 1,2: libfoo} to {foo | libfoo->{foo/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent boo/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent boo/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end boo/1.0.0
+ trace: collect_build_postponed (2): end {biz | boo->{biz/1,1}}
+ trace: collect_build_postponed (1): end {foo | libfoo->{foo/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !biz configured 1.0.0
+ boo configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop foo biz
+ }
+ }
+
+ : bogus-postponment
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tax: depends: libbar(c)
+ # depends: libfoo
+ #
+ # toz/0.1.0:
+ #
+ # toz/1.0.0: depends: libbaz(c)
+ # depends: libfoo(c)
+ # depends: libbar(c)
+ #
+ # tez: depends: libbox(c)
+ # depends: toz == 0.1.0 (c)
+ # depends: libbar(c)
+ #
+ $* tax toz tez 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: add toz/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: collect_build_prerequisites: begin toz/1.0.0
+ %.*
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent toz/1.0.0
+ trace: postponed_configurations::add: create {toz | libbaz->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tax | libbar->{tax/1,1}}!
+ trace: collect_build_postponed (2): begin {toz | libbaz->{toz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {toz | libbaz->{toz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent toz/1.0.0
+ trace: collect_build_prerequisites: resume toz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent toz/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: add toz/1.0.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: collect_build_prerequisites: begin toz/1.0.0
+ %.*
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent toz/1.0.0
+ trace: postponed_configurations::add: create {toz | libbaz->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/1.0.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tax | libbar->{tax/1,1}}!
+ trace: collect_build_postponed (2): begin {toz | libbaz->{toz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {toz | libbaz->{toz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent toz/1.0.0
+ trace: collect_build_prerequisites: resume toz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/1.0.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/2,1}}
+ trace: collect_build_prerequisites: postpone toz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {toz | libbaz->{toz/1,1}}!
+ trace: collect_build_postponed (3): begin {tez | libbox->{tez/1,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ %.*
+ trace: collect_build: pick toz/0.1.0 over toz/1.0.0
+ trace: collect_build: toz/1.0.0 package version needs to be replaced with toz/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: apply version replacement for toz/1.0.0
+ trace: collect_build: replacement: toz/0.1.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tax | libbar->{tax/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (toz), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: apply version replacement for toz/1.0.0
+ trace: collect_build: replacement: toz/0.1.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: pkg_build: dep-postpone user-specified toz
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tax | libbar->{tax/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {tez | toz->{tez/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {tez | toz->{tez/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {tax | libbar->{tax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ trace: collect_build_postponed (3): erase bogus postponement libfoo
+ trace: collect_build_postponed (3): bogus postponements erased, throwing
+ trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: apply version replacement for toz/1.0.0
+ trace: collect_build: replacement: toz/0.1.0
+ trace: collect_build: add toz/0.1.0
+ trace: collect_build: add tez/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: pkg_build: dep-postpone user-specified toz
+ trace: collect_build_prerequisites: begin tez/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | libbox->{tez/1,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tax | libbar->{tax/1,1}}!
+ trace: collect_build_postponed (2): begin {tez | libbox->{tez/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tez | libbox->{tez/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency toz/0.1.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: create {tez | toz->{tez/2,1}}
+ trace: collect_build_prerequisites: postpone tez/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tez | libbox->{tez/1,1}}!
+ trace: collect_build_postponed (3): begin {tez | toz->{tez/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {tez | toz->{tez/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin toz/0.1.0
+ trace: collect_build_prerequisites: end toz/0.1.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tez/1.0.0
+ trace: collect_build_prerequisites: resume tez/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tez/1.0.0
+ trace: postponed_configurations::add: add {tez 3,1: libbar} to {tax | libbar->{tax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tez/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tez/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end tez/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tez | toz->{tez/2,1}}!
+ trace: collect_build_postponed (3): end {tez | toz->{tez/2,1}}
+ trace: collect_build_postponed (2): end {tez | libbox->{tez/1,1}}
+ trace: collect_build_postponed (1): end {tax | libbar->{tax/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tax configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tez configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ EOO
+
+ $pkg_drop tax toz tez
+ }
+ }
+
+ : cycle
+ :
+ {
+ +$clone_cfg
+
+ : direct
+ :
+ {
+ +$clone_cfg
+
+ : args-tex-tix
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tix: depends: libbar(c)
+ # depends: tex(c)
+ #
+ $* tex tix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: add {tix 1,1: libbar} to {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex tix | libbar->{tex/1,1 tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex tix | libbar->{tex/1,1 tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build: add tix/1.0.0
+ trace: pkg_build: dep-postpone user-specified tex
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tix | libbar->{tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): end {tix | libbar->{tix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tix configured 1.0.0
+ libbar configured 1.0.0
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tex tix
+ }
+
+ : args-tix
+ :
+ : As above but with the different command-line arguments which results
+ : in the different cluster list at the moment of the cycle detection.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tix: depends: libbar(c)
+ # depends: tex(c)
+ #
+ $* tix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tix | libbar->{tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): end {tix | libbar->{tix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tix configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tix
+ }
+
+ : args-tex-tix-tux
+ :
+ : Here tux requires tix/0.1.0 which has no dependencies.
+ :
+ {
+ $clone_cfg;
+
+ $* tex tix tux 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build: add tux/1.0.0
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: add {tix 1,1: libbar} to {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_prerequisites: begin tux/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tux/1.0.0
+ trace: postponed_configurations::add: create {tux | libbox->{tux/1,1}}
+ trace: collect_build_prerequisites: postpone tux/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex tix | libbar->{tex/1,1 tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex tix | libbar->{tex/1,1 tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build: add tux/1.0.0
+ trace: pkg_build: dep-postpone user-specified tex
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_prerequisites: begin tux/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tux/1.0.0
+ trace: postponed_configurations::add: create {tux | libbox->{tux/1,1}}
+ trace: collect_build_prerequisites: postpone tux/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tux | libbox->{tux/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tux | libbox->{tux/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tux/1.0.0
+ trace: collect_build_prerequisites: resume tux/1.0.0
+ %.*
+ trace: collect_build: pick tix/0.1.0 over tix/1.0.0
+ trace: collect_build: tix/1.0.0 package version needs to be replaced with tix/0.1.0
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build: apply version replacement for tix/1.0.0
+ trace: collect_build: replacement: tix/0.1.0
+ trace: collect_build: add tix/0.1.0
+ trace: collect_build: add tux/1.0.0
+ trace: pkg_build: dep-postpone user-specified tex
+ trace: collect_build_prerequisites: begin tix/0.1.0
+ trace: collect_build_prerequisites: end tix/0.1.0
+ trace: collect_build_prerequisites: begin tux/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tux/1.0.0
+ trace: postponed_configurations::add: create {tux | libbox->{tux/1,1}}
+ trace: collect_build_prerequisites: postpone tux/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tux | libbox->{tux/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tux | libbox->{tux/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tux/1.0.0
+ trace: collect_build_prerequisites: resume tux/1.0.0
+ %.*
+ trace: collect_build_prerequisites: no cfg-clause for dependency tix/0.1.0 of dependent tux/1.0.0
+ trace: collect_build_prerequisites: end tux/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tux | libbox->{tux/1,1}}!
+ trace: collect_build_postponed (1): erase bogus postponement tex
+ trace: collect_build_postponed (1): bogus postponements erased, throwing
+ trace: pkg_build: collection failed due to bogus dependency collection postponement cancellation, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build: apply version replacement for tix/1.0.0
+ trace: collect_build: replacement: tix/0.1.0
+ trace: collect_build: add tix/0.1.0
+ trace: collect_build: add tux/1.0.0
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_prerequisites: begin tix/0.1.0
+ trace: collect_build_prerequisites: end tix/0.1.0
+ trace: collect_build_prerequisites: begin tux/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent tux/1.0.0
+ trace: postponed_configurations::add: create {tux | libbox->{tux/1,1}}
+ trace: collect_build_prerequisites: postpone tux/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex | libbar->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex | libbar->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tex | libbar->{tex/1,1}}!
+ trace: collect_build_postponed (2): begin {tux | libbox->{tux/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tux | libbox->{tux/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tux/1.0.0
+ trace: collect_build_prerequisites: resume tux/1.0.0
+ %.*
+ trace: collect_build_prerequisites: no cfg-clause for dependency tix/0.1.0 of dependent tux/1.0.0
+ trace: collect_build_prerequisites: end tux/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tux | libbox->{tux/1,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tux | libbox->{tux/1,1}}
+ trace: collect_build_postponed (1): end {tex | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !tux configured 1.0.0
+ libbox configured 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop tex tix tux
+ }
+
+ : args-tex-tiz
+ :
+ : Note that tiz is a correct version of tix, which fixes the
+ : configuration cycle.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tiz: depends: tex(c)
+ # depends: libbar(c)
+ #
+ $* tex tiz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_prerequisites: begin tiz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency tex/1.0.0 of dependent tiz/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build: add tiz/1.0.0
+ trace: pkg_build: dep-postpone user-specified tex
+ trace: collect_build_prerequisites: begin tiz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: postpone tiz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tiz | tex->{tiz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tiz | tex->{tiz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tiz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tiz | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (2): begin {tex tiz | libbar->{tex/1,1 tiz/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex tiz | libbar->{tex/1,1 tiz/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tex tiz | libbar->{tex/1,1 tiz/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tex tiz | libbar->{tex/1,1 tiz/2,1}}
+ trace: collect_build_postponed (1): end {tiz | tex->{tiz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tex tiz
+ }
+
+ : args-tiz
+ :
+ : Note that tiz is a correct version of tix, which fixes the
+ : configuration cycle.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tiz: depends: tex(c)
+ # depends: libbar(c)
+ #
+ $* tiz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tiz/1.0.0
+ trace: collect_build_prerequisites: begin tiz/1.0.0
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: create {tiz | tex->{tiz/1,1}}
+ trace: collect_build_prerequisites: postpone tiz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tiz | tex->{tiz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tiz | tex->{tiz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tiz/1.0.0
+ trace: postponed_configurations::add: add {tiz 2,1: libbar} to {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tiz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tiz | tex->{tiz/1,1}}!
+ trace: collect_build_postponed (2): begin {tex tiz | libbar->{tex/1,1 tiz/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex tiz | libbar->{tex/1,1 tiz/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tiz/1.0.0
+ trace: collect_build_prerequisites: resume tiz/1.0.0
+ trace: collect_build_prerequisites: end tiz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tex tiz | libbar->{tex/1,1 tiz/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tex tiz | libbar->{tex/1,1 tiz/2,1}}
+ trace: collect_build_postponed (1): end {tiz | tex->{tiz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tiz configured 1.0.0
+ libbar configured 1.0.0
+ tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tiz
+ }
+
+ : depends-depends-conflict
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # toz: depends: libfoo(c)
+ # depends: libbar(c)
+ #
+ $* tex toz/0.2.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build: add toz/0.2.0
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_prerequisites: begin toz/0.2.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: create {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone toz/0.2.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tex | libbar->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex | libbar->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 2,1: libfoo} to {toz | libfoo->{toz/1,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tex | libbar->{tex/1,1}}!
+ trace: collect_build_postponed (2): begin {tex toz | libfoo->{tex/2,1 toz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex toz | libfoo->{tex/2,1 toz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent toz/0.2.0
+ trace: collect_build_prerequisites: resume toz/0.2.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent toz/0.2.0
+ trace: postponed_configurations::add: add {toz 2,1: libbar} to {tex | libbar->{tex/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent toz/0.2.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent toz/0.2.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end toz/0.2.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tex toz | libfoo->{tex/2,1 toz/1,1}}!
+ trace: collect_build_postponed (2): end {tex toz | libfoo->{tex/2,1 toz/1,1}}
+ trace: collect_build_postponed (1): end {tex | libbar->{tex/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !toz configured !0.2.0 available 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop tex toz
+ }
+
+ : package-depends-conflict
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # baz: depends: {libbar libfoo} (c)
+ #
+ # bac: depends: libbar(c)
+ # depends: libbaz(c)
+ # depends: libfoo(c)
+ #
+ # bat: depends: libbaz(c)
+ #
+ $* baz bac bat 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build: add bac/1.0.0
+ trace: collect_build: add bat/1.0.0
+ trace: collect_build_prerequisites: begin baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent baz/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent baz/1.0.0
+ trace: postponed_configurations::add: create {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone baz/1.0.0
+ trace: collect_build_prerequisites: begin bac/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bac/1.0.0
+ trace: postponed_configurations::add: add {bac 1,1: libbar} to {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone bac/1.0.0
+ trace: collect_build_prerequisites: begin bat/1.0.0
+ %.*
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bat/1.0.0
+ trace: postponed_configurations::add: create {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: postpone bat/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bac baz | libbar->{bac/1,1 baz/1,1} libfoo->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {bac baz | libbar->{bac/1,1 baz/1,1} libfoo->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bac/1.0.0
+ trace: collect_build_prerequisites: resume bac/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bac/1.0.0
+ trace: postponed_configurations::add: add {bac 2,1: libbaz} to {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: postpone bac/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent baz/1.0.0
+ trace: collect_build_prerequisites: resume baz/1.0.0
+ trace: collect_build_prerequisites: end baz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bac baz | libbar->{bac/1,1 baz/1,1} libfoo->{baz/1,1}}!
+ trace: collect_build_postponed (2): begin {bac bat | libbaz->{bac/2,1 bat/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {bac bat | libbaz->{bac/2,1 bat/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bac/1.0.0
+ trace: collect_build_prerequisites: resume bac/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent bac/1.0.0
+ trace: postponed_configurations::add: add {bac 3,1: libfoo} to {bac baz | libbar->{bac/1,1 baz/1,1} libfoo->{baz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bac/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent bac/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bac/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bat/1.0.0
+ trace: collect_build_prerequisites: resume bat/1.0.0
+ trace: collect_build_prerequisites: end bat/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bac bat | libbaz->{bac/2,1 bat/1,1}}!
+ trace: collect_build_postponed (2): end {bac bat | libbaz->{bac/2,1 bat/1,1}}
+ trace: collect_build_postponed (1): end {bac baz | libbar->{bac/1,1 baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !bac configured 1.0.0
+ libbar configured 1.0.0
+ libbaz configured 1.0.0
+ libfoo configured 1.0.0
+ !bat configured 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop baz bac bat
+ }
+
+ : existing
+ :
+ {
+ +$clone_cfg
+
+ : dependency-new-downgrade
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tix: depends: libbar(c)
+ # depends: tex(c)
+ #
+ $* tex 2>!;
+
+ # Build new dependency of an existing dependent.
+ #
+ $* tix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: reeval tex/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {tex^ 1,1: libbar} to {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tex/1.0.0 results in {tex^ tix | libbar->{tex/1,1 tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tex^ tix | libbar->{tex/1,1 tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (tex), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: begin tix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent tex of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build: add tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/1.0.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tix | libbar->{tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/1.0.0 is already (being) recursively collected, skipping
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/1.0.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tix | tex->{tix/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/1.0.0
+ trace: collect_build_prerequisites: resume tex/1.0.0
+ trace: collect_build_prerequisites: end tex/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tix | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): end {tix | libbar->{tix/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !tix configured 1.0.0
+ libbar configured 1.0.0
+ !tex configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ # Downgrade the existing dependency of an existing dependent.
+ #
+ $* tex/0.3.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/0.3.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/0.3.0 of existing dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: reeval tix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ %.*
+ trace: collect_build: pick tex/0.3.0 over tex/1.0.0
+ trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: re-evaluated tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/0.3.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/0.3.0
+ trace: postponed_configurations::add: create {tex | libbar->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/0.3.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
+ trace: collect_build_postponed (2): begin {tex | libbar->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libbar
+ trace: collect_build_postponed (2): re-evaluate existing dependents for {tex | libbar->{tex/1,1}}
+ trace: collect_build_postponed (2): cannot re-evaluate dependent tix to dependency index 1 due to greater dependency index 2 in {tix^ | tex->{tix/2,1}}!, throwing postpone_position
+ trace: pkg_build: collection failed due to earlier dependency position, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tex/0.3.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/0.3.0 of existing dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): pos-postpone existing dependent tix re-evaluation to dependency index 2 due to recorded index 1, skipping {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): postpone cfg-negotiation of {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): non-negotiated clusters left and non-replace postponed positions are present, overriding first encountered non-replace position to replace
+ trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): pos-postpone existing dependent tix re-evaluation to dependency index 2 due to recorded index 1, skipping {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): replace dependency at index 2 of existing dependent tix/1.0.0 with dependency libbar/1.0.0 at index 1
+ trace: collect_build: add libbar/1.0.0
+ trace: postponed_configurations::add: create {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_postponed (0): postpone cfg-negotiation of {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): begin {tix^ | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): skip being built existing dependent tex of dependency libbar
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | libbar->{tix/1,1}}
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: reeval tix/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {tix^ 1,1: libbar} to {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_prerequisites: re-evaluated tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | libbar->{tix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ %.*
+ trace: collect_build: pick tex/0.3.0 over tex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/0.3.0 of dependent tix/1.0.0
+ trace: postponed_configurations::add: add {tix 2,1: tex} to {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: postpone tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix^ | libbar->{tix/1,1}}!
+ trace: collect_build_postponed (2): begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tix of dependency tex
+ trace: collect_build_postponed (2): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/0.3.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tex/0.3.0
+ trace: postponed_configurations::add: add {tex 1,1: libbar} to {tix^ | libbar->{tix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent tex/0.3.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent tex/0.3.0 is already (being) recursively collected, skipping
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.3.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/0.3.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
+ trace: collect_build_postponed (3): begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (3): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent tex/0.3.0
+ trace: collect_build_prerequisites: resume tex/0.3.0
+ trace: collect_build_prerequisites: end tex/0.3.0
+ trace: collect_build_postponed (3): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (3): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (2): end {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (1): end {tix^ | libbar->{tix/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_drop tex tix
+ }
+
+ : dependency-downgrade
+ :
+ : Note that here we also specify the existing dependent tix on the
+ : command line to make sure that its noop recursive collection
+ : doesn't prevent it from being properly re-evaluated afterwords.
+ :
+ : Also note that tex/0.1.0 doesn't depend on libbar.
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tix: depends: libbar(c)
+ # depends: tex(c)
+ #
+ $* tex tix 2>!;
+
+ $* tix tex/0.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build: add tex/0.1.0
+ trace: collect_build_prerequisites: skip configured tix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of existing dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: reeval tix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ %.*
+ trace: collect_build: pick tex/0.1.0 over tex/1.0.0
+ trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: re-evaluated tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/0.1.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.1.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
+ trace: collect_build_postponed (2): begin {tex | libfoo->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/0.1.0
+ trace: collect_build_prerequisites: resume tex/0.1.0
+ trace: collect_build_prerequisites: end tex/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/1,1}}!
+ trace: collect_build_postponed (2): end {tex | libfoo->{tex/1,1}}
+ trace: collect_build_postponed (1): end {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_drop tex tix
+ }
+
+ : dependency-downgrade-unhold
+ :
+ : As above but the dependency is also unheld.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tix: depends: libbar(c)
+ # depends: tex(c)
+ #
+ $* tex tix 2>!;
+
+ $* tix ?tex/0.1.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: skip configured tix/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: tex/1.0.0: update to tex/0.1.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/0.1.0 of existing dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: reeval tix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ %.*
+ trace: collect_build: pick tex/0.1.0 over tex/1.0.0
+ trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: re-evaluated tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/0.1.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.1.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/1,1}}
+ trace: collect_build_prerequisites: postpone tex/0.1.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
+ trace: collect_build_postponed (2): begin {tex | libfoo->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/0.1.0
+ trace: collect_build_prerequisites: resume tex/0.1.0
+ trace: collect_build_prerequisites: end tex/0.1.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/1,1}}!
+ trace: collect_build_postponed (2): end {tex | libfoo->{tex/1,1}}
+ trace: collect_build_postponed (1): end {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_drop tix
+ }
+
+ : dependency-downgrade-unhold-premature
+ :
+ : As above but the dependency (tex) depends on libbar without
+ : configuration clause.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tex: depends: libbar(c)
+ # depends: libfoo(c)
+ #
+ # tix: depends: libbar(c)
+ # depends: tex(c)
+ #
+ $* tex tix 2>!;
+
+ $* tix ?tex/0.2.0 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tix/1.0.0
+ trace: collect_build_prerequisites: skip configured tix/1.0.0
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: tex/1.0.0: update to tex/0.2.0
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency tex/0.2.0 of existing dependent tix/1.0.0
+ trace: postponed_configurations::add: create {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: reeval tix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ %.*
+ trace: collect_build: pick tex/0.2.0 over tex/1.0.0
+ trace: postponed_configurations::add: add {tix^ 2,1: tex} to {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent tix/1.0.0 results in {tix^ | tex->{tix/2,1}}
+ trace: collect_build_prerequisites: re-evaluated tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {tix^ | tex->{tix/2,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin tex/0.2.0
+ %.*
+ trace: collect_build_prerequisites: no cfg-clause for dependency libbar/1.0.0 of dependent tex/0.2.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent tex/0.2.0
+ trace: postponed_configurations::add: create {tex | libfoo->{tex/2,1}}
+ trace: collect_build_prerequisites: postpone tex/0.2.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tix/1.0.0
+ trace: collect_build_prerequisites: resume tix/1.0.0
+ trace: collect_build_prerequisites: end tix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tix^ | tex->{tix/2,1}}!
+ trace: collect_build_postponed (2): begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): skip being built existing dependent tex of dependency libfoo
+ trace: collect_build_postponed (2): cfg-negotiate begin {tex | libfoo->{tex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent tex/0.2.0
+ trace: collect_build_prerequisites: resume tex/0.2.0
+ trace: collect_build_prerequisites: end tex/0.2.0
+ trace: collect_build_postponed (2): cfg-negotiate end {tex | libfoo->{tex/2,1}}!
+ trace: collect_build_postponed (2): end {tex | libfoo->{tex/2,1}}
+ trace: collect_build_postponed (1): end {tix^ | tex->{tix/2,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_drop tix
+ }
+ }
+ }
+
+ : indirect
+ :
+ {
+ +$clone_cfg
+
+ : args-tax-dex-dix
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tax: depends: libbar(c)
+ # depends: libfoo
+ #
+ # bar: depends: libbar(c)
+ #
+ # dex: depends: bar(c)
+ # depends: libfoo(c)
+ #
+ # dox: dex(c)
+ #
+ # dix: depends: libbar(c)
+ # depends: libbox(c) # causes postponment and initial cluster finished negotiating
+ # depends: dox(c)
+ #
+ $* tax dex dix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add dix/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_prerequisites: begin dix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: add {dix 1,1: libbar} to {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {dix tax | libbar->{dix/1,1 tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {dix tax | libbar->{dix/1,1 tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | libbox->{dix/2,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {dix tax | libbar->{dix/1,1 tax/1,1}}!
+ trace: collect_build_postponed (2): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {dix tax | libbar->{dix/1,1 tax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add dix/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_prerequisites: begin dix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: add {dix 1,1: libbar} to {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {dix tax | libbar->{dix/1,1 tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {dix tax | libbar->{dix/1,1 tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | libbox->{dix/2,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {dix tax | libbar->{dix/1,1 tax/1,1}}!
+ trace: collect_build_postponed (2): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {dix tax | libbar->{dix/1,1 tax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (3): begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | dox->{dix/3,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dix | libbox->{dix/2,1}}!
+ trace: collect_build_postponed (4): begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {dex | libfoo->{dex/2,1}}!
+ trace: collect_build_postponed (5): begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (5): cfg-negotiate begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (dex), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add dix/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: pkg_build: dep-postpone user-specified dex
+ trace: collect_build_prerequisites: begin dix/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: add {dix 1,1: libbar} to {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {dix tax | libbar->{dix/1,1 tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {dix tax | libbar->{dix/1,1 tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | libbox->{dix/2,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {dix tax | libbar->{dix/1,1 tax/1,1}}!
+ trace: collect_build_postponed (2): begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | dox->{dix/3,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {dix | libbox->{dix/2,1}}!
+ trace: collect_build_postponed (3): begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ trace: collect_build_prerequisites: end dix/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dix | dox->{dix/3,1}}!
+ trace: collect_build_postponed (4): begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (5): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (5): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {dix tax | libbar->{dix/1,1 tax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (6): begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (6): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (6): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (6): cfg-negotiate end {dex | libfoo->{dex/2,1}}!
+ trace: collect_build_postponed (6): end {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (5): end {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (4): end {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): end {dix | dox->{dix/3,1}}
+ trace: collect_build_postponed (2): end {dix | libbox->{dix/2,1}}
+ trace: collect_build_postponed (1): end {dix tax | libbar->{dix/1,1 tax/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tax configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !dix configured 1.0.0
+ dox configured 1.0.0
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ $pkg_drop tax dex dix --drop-dependent
+ }
+
+ : args-dix
+ :
+ : As above but with the different command-line arguments which results
+ : in the different cluster list at the moment of the cycle detection.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bar: depends: libbar(c)
+ #
+ # dex: depends: bar(c)
+ # depends: libfoo(c)
+ #
+ # dox: dex(c)
+ #
+ # dix: depends: libbar(c)
+ # depends: libbox(c) # causes postponment and initial cluster finished negotiating
+ # depends: dox(c)
+ #
+ $* dix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add dix/1.0.0
+ trace: collect_build_prerequisites: begin dix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | libbar->{dix/1,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {dix | libbar->{dix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {dix | libbar->{dix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | libbox->{dix/2,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {dix | libbar->{dix/1,1}}!
+ trace: collect_build_postponed (2): begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | dox->{dix/3,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {dix | libbox->{dix/2,1}}!
+ trace: collect_build_postponed (3): begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ %.*
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ trace: collect_build_prerequisites: end dix/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dix | dox->{dix/3,1}}!
+ trace: collect_build_postponed (4): begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (5): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (5): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {dix | libbar->{dix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (6): begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (6): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (6): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (6): cfg-negotiate end {dex | libfoo->{dex/2,1}}!
+ trace: collect_build_postponed (6): end {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (5): end {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (4): end {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): end {dix | dox->{dix/3,1}}
+ trace: collect_build_postponed (2): end {dix | libbox->{dix/2,1}}
+ trace: collect_build_postponed (1): end {dix | libbar->{dix/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !dix configured 1.0.0
+ dox configured 1.0.0
+ dex configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ $pkg_drop dix
+ }
+
+ : args-tax-dex-diz
+ :
+ : Note that diz is a correct version of dix, which fixes the
+ : configuration cycle.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # tax: depends: libbar(c)
+ # depends: libfoo
+ #
+ # bar: depends: libbar(c)
+ #
+ # dex: depends: bar(c)
+ # depends: libfoo(c)
+ #
+ # dox: dex(c)
+ #
+ # diz: depends: dox(c)
+ # depends: libbox(c)
+ # depends: libbar(c)
+ #
+ $* tax dex diz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_prerequisites: begin diz/1.0.0
+ %.*
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: no cfg-clause for dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tax | libbar->{tax/1,1}}!
+ trace: collect_build_postponed (2): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {tax | libbar->{tax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (libfoo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_prerequisites: begin diz/1.0.0
+ %.*
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tax | libbar->{tax/1,1}}!
+ trace: collect_build_postponed (2): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {tax | libbar->{tax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (3): begin {diz | dox->{diz/1,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {diz | dox->{diz/1,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (dex), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add tax/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: begin tax/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent tax/1.0.0
+ trace: postponed_configurations::add: create {tax | libbar->{tax/1,1}}
+ trace: collect_build_prerequisites: postpone tax/1.0.0
+ trace: pkg_build: dep-postpone user-specified dex
+ trace: collect_build_prerequisites: begin diz/1.0.0
+ %.*
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {tax | libbar->{tax/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent tax/1.0.0
+ trace: collect_build_prerequisites: resume tax/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: dep-postpone dependency libfoo/1.0.0 of dependent tax/1.0.0
+ trace: collect_build_prerequisites: end tax/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {tax | libbar->{tax/1,1}}!
+ trace: collect_build_postponed (2): begin {diz | dox->{diz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {diz | dox->{diz/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {diz | dox->{diz/1,1}}!
+ trace: collect_build_postponed (3): begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (4): begin {diz | libbox->{diz/2,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {diz | libbox->{diz/2,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: add {diz 3,1: libbar} to {tax | libbar->{tax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent diz/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent diz/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end diz/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {diz | libbox->{diz/2,1}}!
+ trace: collect_build_postponed (5): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (5): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {diz tax | libbar->{diz/3,1 tax/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (6): begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (6): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (6): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (6): cfg-negotiate end {dex | libfoo->{dex/2,1}}!
+ trace: collect_build_postponed (6): end {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (5): end {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (4): end {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (3): end {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (2): end {diz | dox->{diz/1,1}}
+ trace: collect_build_postponed (1): end {tax | libbar->{tax/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !tax configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !diz configured 1.0.0
+ dox configured 1.0.0
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ $pkg_drop tax dex diz --drop-dependent
+ }
+
+ : args-diz
+ :
+ : Note that diz is a correct version of dix, which fixes the
+ : configuration cycle.
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bar: depends: libbar(c)
+ #
+ # dex: depends: bar(c)
+ # depends: libfoo(c)
+ #
+ # dox: dex(c)
+ #
+ # diz: depends: dox(c)
+ # depends: libbox(c)
+ # depends: libbar(c)
+ #
+ $* diz 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add diz/1.0.0
+ trace: collect_build_prerequisites: begin diz/1.0.0
+ %.*
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | dox->{diz/1,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {diz | dox->{diz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {diz | dox->{diz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ %.*
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbox->{diz/2,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {diz | dox->{diz/1,1}}!
+ trace: collect_build_postponed (2): begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (3): begin {diz | libbox->{diz/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {diz | libbox->{diz/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent diz/1.0.0
+ trace: postponed_configurations::add: create {diz | libbar->{diz/3,1}}
+ trace: collect_build_prerequisites: postpone diz/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {diz | libbox->{diz/2,1}}!
+ trace: collect_build_postponed (4): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {diz | libbar->{diz/3,1}}
+ trace: collect_build_prerequisites: postpone bar/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (5): begin {bar diz | libbar->{bar/1,1 diz/3,1}}
+ %.*
+ trace: collect_build_postponed (5): cfg-negotiate begin {bar diz | libbar->{bar/1,1 diz/3,1}}
+ %.*
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent diz/1.0.0
+ trace: collect_build_prerequisites: resume diz/1.0.0
+ trace: collect_build_prerequisites: end diz/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {bar diz | libbar->{bar/1,1 diz/3,1}}!
+ trace: collect_build_postponed (6): begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (6): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (6): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (6): cfg-negotiate end {dex | libfoo->{dex/2,1}}!
+ trace: collect_build_postponed (6): end {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (5): end {bar diz | libbar->{bar/1,1 diz/3,1}}
+ trace: collect_build_postponed (4): end {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (3): end {diz | libbox->{diz/2,1}}
+ trace: collect_build_postponed (2): end {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (1): end {diz | dox->{diz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !diz configured 1.0.0
+ dox configured 1.0.0
+ dex configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ $pkg_drop diz
+ }
+
+ : depends-depends-conflict
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bar: depends: libbar(c)
+ #
+ # dex: depends: bar(c)
+ # depends: libfoo(c)
+ #
+ # bux: depends: libbar(c)
+ #
+ # buc: depends: libfoo(c)
+ # depends: bux(c)
+ #
+ $* bar dex buc bux 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add buc/1.0.0
+ trace: collect_build: add bux/1.0.0
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: postpone bar/1.0.0
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (bar), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add buc/1.0.0
+ trace: collect_build: add bux/1.0.0
+ trace: pkg_build: dep-postpone user-specified bar
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_prerequisites: begin buc/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent buc/1.0.0
+ trace: postponed_configurations::add: create {buc | libfoo->{buc/1,1}}
+ trace: collect_build_prerequisites: postpone buc/1.0.0
+ trace: collect_build_prerequisites: begin bux/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bux/1.0.0
+ trace: postponed_configurations::add: create {bux | libbar->{bux/1,1}}
+ trace: collect_build_prerequisites: postpone bux/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {bux | libbar->{bux/1,1}}
+ trace: collect_build_prerequisites: postpone bar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: add {dex 2,1: libfoo} to {buc | libfoo->{buc/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (2): begin {buc dex | libfoo->{buc/1,1 dex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {buc dex | libfoo->{buc/1,1 dex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent buc/1.0.0
+ trace: collect_build_prerequisites: resume buc/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency bux/1.0.0 of dependent buc/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (bux), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add buc/1.0.0
+ trace: collect_build: add bux/1.0.0
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: postpone bar/1.0.0
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (bar), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build: add buc/1.0.0
+ trace: collect_build: add bux/1.0.0
+ trace: pkg_build: dep-postpone user-specified bar
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_prerequisites: begin buc/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent buc/1.0.0
+ trace: postponed_configurations::add: create {buc | libfoo->{buc/1,1}}
+ trace: collect_build_prerequisites: postpone buc/1.0.0
+ trace: pkg_build: dep-postpone user-specified bux
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: create {bar | libbar->{bar/1,1}}
+ trace: collect_build_prerequisites: postpone bar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: add {dex 2,1: libfoo} to {buc | libfoo->{buc/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (2): begin {buc dex | libfoo->{buc/1,1 dex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {buc dex | libfoo->{buc/1,1 dex/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent buc/1.0.0
+ trace: collect_build_prerequisites: resume buc/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency bux/1.0.0 of dependent buc/1.0.0
+ trace: postponed_configurations::add: create {buc | bux->{buc/2,1}}
+ trace: collect_build_prerequisites: postpone buc/1.0.0
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {buc dex | libfoo->{buc/1,1 dex/2,1}}!
+ trace: collect_build_postponed (3): begin {bar | libbar->{bar/1,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {bar | libbar->{bar/1,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bar | libbar->{bar/1,1}}!
+ trace: collect_build_postponed (4): begin {buc | bux->{buc/2,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {buc | bux->{buc/2,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bux/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bux/1.0.0
+ trace: postponed_configurations::add: add {bux 1,1: libbar} to {bar | libbar->{bar/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bux/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bux/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bux/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent buc/1.0.0
+ trace: collect_build_prerequisites: resume buc/1.0.0
+ trace: collect_build_prerequisites: end buc/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {buc | bux->{buc/2,1}}!
+ trace: collect_build_postponed (4): end {buc | bux->{buc/2,1}}
+ trace: collect_build_postponed (3): end {bar | libbar->{bar/1,1}}
+ trace: collect_build_postponed (2): end {buc dex | libfoo->{buc/1,1 dex/2,1}}
+ trace: collect_build_postponed (1): end {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ EOO
+
+ $pkg_drop bar dex buc bux
+ }
+
+ : package-depends-conflict
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # baz: depends: {libbar libfoo} (c)
+ #
+ # bas: depends: libbar(c)
+ # depends: bus (c)
+ #
+ # bus: depends: libbaz(c)
+ # depends: foo (c)
+ #
+ # foo: depends: libfoo(c)
+ #
+ # bat: depends: libbaz(c)
+ #
+ $* baz bas bus foo bat 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build: add bas/1.0.0
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add bat/1.0.0
+ trace: collect_build_prerequisites: begin baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent baz/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent baz/1.0.0
+ trace: postponed_configurations::add: create {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone baz/1.0.0
+ trace: collect_build_prerequisites: begin bas/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: add {bas 1,1: libbar} to {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_prerequisites: begin bus/1.0.0
+ %.*
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: create {bus | libbaz->{bus/1,1}}
+ trace: collect_build_prerequisites: postpone bus/1.0.0
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: add {foo 1,1: libfoo} to {bas baz | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin bat/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bat/1.0.0
+ trace: postponed_configurations::add: add {bat 1,1: libbaz} to {bus | libbaz->{bus/1,1}}
+ trace: collect_build_prerequisites: postpone bat/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bas baz foo | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1 foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {bas baz foo | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1 foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (bus), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build: add bas/1.0.0
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add bat/1.0.0
+ trace: collect_build_prerequisites: begin baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent baz/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent baz/1.0.0
+ trace: postponed_configurations::add: create {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone baz/1.0.0
+ trace: collect_build_prerequisites: begin bas/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: add {bas 1,1: libbar} to {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: pkg_build: dep-postpone user-specified bus
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: add {foo 1,1: libfoo} to {bas baz | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone foo/1.0.0
+ trace: collect_build_prerequisites: begin bat/1.0.0
+ %.*
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bat/1.0.0
+ trace: postponed_configurations::add: create {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: postpone bat/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bas baz foo | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1 foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {bas baz foo | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1 foo/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent baz/1.0.0
+ trace: collect_build_prerequisites: resume baz/1.0.0
+ trace: collect_build_prerequisites: end baz/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent foo/1.0.0
+ trace: collect_build_prerequisites: resume foo/1.0.0
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bas baz foo | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1 foo/1,1}}!
+ trace: collect_build_postponed (2): begin {bat | libbaz->{bat/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {bat | libbaz->{bat/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bat/1.0.0
+ trace: collect_build_prerequisites: resume bat/1.0.0
+ trace: collect_build_prerequisites: end bat/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bat | libbaz->{bat/1,1}}!
+ trace: collect_build_postponed (3): begin {bas | bus->{bas/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {bas | bus->{bas/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bus/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: add {bus 1,1: libbaz} to {bat | libbaz->{bat/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bus/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbaz/1.0.0 of dependent bus/1.0.0 is already (being) recursively collected, skipping
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency foo/1.0.0 of dependent bus/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (foo), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add baz/1.0.0
+ trace: collect_build: add bas/1.0.0
+ trace: collect_build: add bus/1.0.0
+ trace: collect_build: add foo/1.0.0
+ trace: collect_build: add bat/1.0.0
+ trace: collect_build_prerequisites: begin baz/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent baz/1.0.0
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent baz/1.0.0
+ trace: postponed_configurations::add: create {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone baz/1.0.0
+ trace: collect_build_prerequisites: begin bas/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: add {bas 1,1: libbar} to {baz | libbar->{baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: pkg_build: dep-postpone user-specified bus
+ trace: pkg_build: dep-postpone user-specified foo
+ trace: collect_build_prerequisites: begin bat/1.0.0
+ %.*
+ trace: collect_build: add libbaz/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bat/1.0.0
+ trace: postponed_configurations::add: create {bat | libbaz->{bat/1,1}}
+ trace: collect_build_prerequisites: postpone bat/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {bas baz | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): cfg-negotiate begin {bas baz | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbar/1.0.0
+ trace: collect_build_prerequisites: end libbar/1.0.0
+ trace: collect_build_prerequisites: begin libfoo/1.0.0
+ trace: collect_build_prerequisites: end libfoo/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency bus/1.0.0 of dependent bas/1.0.0
+ trace: postponed_configurations::add: create {bas | bus->{bas/2,1}}
+ trace: collect_build_prerequisites: postpone bas/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent baz/1.0.0
+ trace: collect_build_prerequisites: resume baz/1.0.0
+ trace: collect_build_prerequisites: end baz/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bas baz | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1}}!
+ trace: collect_build_postponed (2): begin {bat | libbaz->{bat/1,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {bat | libbaz->{bat/1,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbaz/1.0.0
+ trace: collect_build_prerequisites: end libbaz/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent bat/1.0.0
+ trace: collect_build_prerequisites: resume bat/1.0.0
+ trace: collect_build_prerequisites: end bat/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {bat | libbaz->{bat/1,1}}!
+ trace: collect_build_postponed (3): begin {bas | bus->{bas/2,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {bas | bus->{bas/2,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bus/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbaz/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: add {bus 1,1: libbaz} to {bat | libbaz->{bat/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bus/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbaz/1.0.0 of dependent bus/1.0.0 is already (being) recursively collected, skipping
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency foo/1.0.0 of dependent bus/1.0.0
+ trace: postponed_configurations::add: create {bus | foo->{bus/2,1}}
+ trace: collect_build_prerequisites: postpone bus/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent bas/1.0.0
+ trace: collect_build_prerequisites: resume bas/1.0.0
+ trace: collect_build_prerequisites: end bas/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {bas | bus->{bas/2,1}}!
+ trace: collect_build_postponed (4): begin {bus | foo->{bus/2,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {bus | foo->{bus/2,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent foo/1.0.0
+ trace: postponed_configurations::add: add {foo 1,1: libfoo} to {bas baz | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent foo/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libfoo/1.0.0 of dependent foo/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end foo/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent bus/1.0.0
+ trace: collect_build_prerequisites: resume bus/1.0.0
+ trace: collect_build_prerequisites: end bus/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {bus | foo->{bus/2,1}}!
+ trace: collect_build_postponed (4): end {bus | foo->{bus/2,1}}
+ trace: collect_build_postponed (3): end {bas | bus->{bas/2,1}}
+ trace: collect_build_postponed (2): end {bat | libbaz->{bat/1,1}}
+ trace: collect_build_postponed (1): end {bas baz | libbar->{bas/1,1 baz/1,1} libfoo->{baz/1,1}}
+ trace: collect_build_postponed (0): end
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ libfoo configured 1.0.0
+ libbaz configured 1.0.0
+ libbar configured 1.0.0
+ !bat configured 1.0.0
+ libbaz configured 1.0.0
+ EOO
+
+ $pkg_drop baz bas bus foo bat
+ }
+
+ : existing
+ :
+ {
+ +$clone_cfg
+
+ : negotiate
+ :
+ {
+ $clone_cfg;
+
+ # Dependencies:
+ #
+ # bar: depends: libbar(c)
+ #
+ # dex: depends: bar(c)
+ # depends: libfoo(c)
+ #
+ # dox: dex(c)
+ #
+ # dix: depends: libbar(c)
+ # depends: libbox(c) # causes postponment and initial cluster finished negotiating
+ # depends: dox(c)
+ #
+ $* dex 2>!;
+
+ $* dix 2>>~%EOE%;
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add dix/1.0.0
+ trace: collect_build_prerequisites: begin dix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | libbar->{dix/1,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {dix | libbar->{dix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): re-evaluate existing dependents for {dix | libbar->{dix/1,1}}
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: reeval bar/1.0.0
+ %.*
+ trace: postponed_configurations::add: add {bar^ 1,1: libbar} to {dix | libbar->{dix/1,1}}
+ trace: collect_build_prerequisites: re-evaluating dependent bar/1.0.0 results in {bar^ dix | libbar->{bar/1,1 dix/1,1}}
+ trace: collect_build_prerequisites: re-evaluated bar/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate begin {bar^ dix | libbar->{bar/1,1 dix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent bar/1.0.0
+ trace: collect_build_prerequisites: resume bar/1.0.0
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | libbox->{dix/2,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {bar^ dix | libbar->{bar/1,1 dix/1,1}}!
+ trace: collect_build_postponed (2): begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | dox->{dix/3,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {dix | libbox->{dix/2,1}}!
+ trace: collect_build_postponed (3): begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ %.*
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ trace: collect_build_prerequisites: end dix/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dix | dox->{dix/3,1}}!
+ trace: collect_build_postponed (4): begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cannot cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0 (collected prematurely), throwing postpone_dependency
+ trace: pkg_build: collection failed due to prematurely collected dependency (bar), retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ trace: collect_build: add dix/1.0.0
+ trace: collect_build_prerequisites: begin dix/1.0.0
+ %.*
+ trace: collect_build: add libbar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | libbar->{dix/1,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (0): begin
+ trace: collect_build_postponed (1): begin {dix | libbar->{dix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): skip dep-postponed existing dependent bar of dependency libbar
+ trace: collect_build_postponed (1): cfg-negotiate begin {dix | libbar->{dix/1,1}}
+ %.*
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libbar/1.0.0
+ trace: collect_build_postponed (1): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (1): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add libbox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libbox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | libbox->{dix/2,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (1): cfg-negotiate end {dix | libbar->{dix/1,1}}!
+ trace: collect_build_postponed (2): begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): cfg-negotiate begin {dix | libbox->{dix/2,1}}
+ %.*
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin libbox/1.0.0
+ trace: collect_build_prerequisites: end libbox/1.0.0
+ trace: collect_build_postponed (2): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (2): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ %.*
+ trace: collect_build: add dox/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dox/1.0.0 of dependent dix/1.0.0
+ trace: postponed_configurations::add: create {dix | dox->{dix/3,1}}
+ trace: collect_build_prerequisites: postpone dix/1.0.0
+ trace: collect_build_postponed (2): cfg-negotiate end {dix | libbox->{dix/2,1}}!
+ trace: collect_build_postponed (3): begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (3): cfg-negotiate begin {dix | dox->{dix/3,1}}
+ %.*
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dox/1.0.0
+ %.*
+ trace: collect_build: add dex/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency dex/1.0.0 of dependent dox/1.0.0
+ trace: postponed_configurations::add: create {dox | dex->{dox/1,1}}
+ trace: collect_build_prerequisites: postpone dox/1.0.0
+ trace: collect_build_postponed (3): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (3): select cfg-negotiated dependency alternative for dependent dix/1.0.0
+ trace: collect_build_prerequisites: resume dix/1.0.0
+ trace: collect_build_prerequisites: end dix/1.0.0
+ trace: collect_build_postponed (3): cfg-negotiate end {dix | dox->{dix/3,1}}!
+ trace: collect_build_postponed (4): begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (4): cfg-negotiate begin {dox | dex->{dox/1,1}}
+ %.*
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin dex/1.0.0
+ %.*
+ trace: collect_build: add bar/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency bar/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | bar->{dex/1,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (4): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (4): select cfg-negotiated dependency alternative for dependent dox/1.0.0
+ trace: collect_build_prerequisites: resume dox/1.0.0
+ trace: collect_build_prerequisites: end dox/1.0.0
+ trace: collect_build_postponed (4): cfg-negotiate end {dox | dex->{dox/1,1}}!
+ trace: collect_build_postponed (5): begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (5): skip being built existing dependent dex of dependency bar
+ trace: collect_build_postponed (5): cfg-negotiate begin {dex | bar->{dex/1,1}}
+ %.*
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: begin bar/1.0.0
+ %.*
+ trace: collect_build_prerequisites: cfg-postpone dependency libbar/1.0.0 of dependent bar/1.0.0
+ trace: postponed_configurations::add: add {bar 1,1: libbar} to {dix | libbar->{dix/1,1}}!
+ trace: collect_build_prerequisites: configuration for cfg-postponed dependencies of dependent bar/1.0.0 is negotiated
+ trace: collect_build_prerequisites: dependency libbar/1.0.0 of dependent bar/1.0.0 is already (being) recursively collected, skipping
+ trace: collect_build_prerequisites: end bar/1.0.0
+ trace: collect_build_postponed (5): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (5): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ %.*
+ trace: collect_build: add libfoo/1.0.0
+ trace: collect_build_prerequisites: cfg-postpone dependency libfoo/1.0.0 of dependent dex/1.0.0
+ trace: postponed_configurations::add: create {dex | libfoo->{dex/2,1}}
+ trace: collect_build_prerequisites: postpone dex/1.0.0
+ trace: collect_build_postponed (5): cfg-negotiate end {dex | bar->{dex/1,1}}!
+ trace: collect_build_postponed (6): begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (6): skip being built existing dependent dex of dependency libfoo
+ trace: collect_build_postponed (6): cfg-negotiate begin {dex | libfoo->{dex/2,1}}
+ %.*
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependencies
+ trace: collect_build_prerequisites: skip configured libfoo/1.0.0
+ trace: collect_build_postponed (6): recursively collect cfg-negotiated dependents
+ trace: collect_build_postponed (6): select cfg-negotiated dependency alternative for dependent dex/1.0.0
+ trace: collect_build_prerequisites: resume dex/1.0.0
+ trace: collect_build_prerequisites: end dex/1.0.0
+ trace: collect_build_postponed (6): cfg-negotiate end {dex | libfoo->{dex/2,1}}!
+ trace: collect_build_postponed (6): end {dex | libfoo->{dex/2,1}}
+ trace: collect_build_postponed (5): end {dex | bar->{dex/1,1}}
+ trace: collect_build_postponed (4): end {dox | dex->{dox/1,1}}
+ trace: collect_build_postponed (3): end {dix | dox->{dix/3,1}}
+ trace: collect_build_postponed (2): end {dix | libbox->{dix/2,1}}
+ trace: collect_build_postponed (1): end {dix | libbar->{dix/1,1}}
+ trace: collect_build_postponed (0): end
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ EOE
+
+ $pkg_status -r >>EOO;
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ !dix configured 1.0.0
+ dox configured 1.0.0
+ !dex configured 1.0.0
+ bar configured 1.0.0
+ libbar configured 1.0.0
+ libfoo configured 1.0.0
+ libbar configured 1.0.0
+ libbox configured 1.0.0
+ EOO
+
+ # @@ Note that if --drop-dependent is unspecified, the following
+ # command fails with:
+ #
+ # following dependent packages will have to be dropped as well:
+ # dox (requires dex)
+ # error: refusing to drop dependent packages with just --yes
+ # info: specify --drop-dependent to confirm
+ #
+ # Feels wrong.
+ #
+ $pkg_drop --drop-dependent dex dix
+ }
+ }
+ }
+ }
+
+ : all-repo-packages
+ :
+ : Don't match the tracing but just make sure that pkg-build doesn't crash
+ : or hang and ends up with an expected packages setup.
+ :
+ {
+ $clone_cfg;
+
+ $* libfoo libbar ?libbaz/0.1.0 ?libbox/0.1.0 \
+ foo fox fux fix fex bar baz bac bat bas bus \
+ box bax bux bix bex boo biz buz buc tax tex \
+ tix tiz toz tez tux dex dix diz dox 2>!;
+
+ $pkg_status -r >>EOO;
+ !libfoo configured 1.0.0
+ !libbar configured 1.0.0
+ !bat configured 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !tux configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !tix configured 0.1.0 available 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !bex configured 1.0.0
+ !libbar configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !biz configured 1.0.0
+ !boo configured 1.0.0
+ !libbar configured 1.0.0
+ !buz configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !tez configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !toz configured 0.1.0 available 1.0.0 0.2.0
+ !bix configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !libbar configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ !fox configured 1.0.0
+ !libfoo configured 1.0.0
+ !fux configured 1.0.0
+ !libfoo configured 1.0.0
+ !baz configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !bac configured 1.0.0
+ !libbar configured 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !libfoo configured 1.0.0
+ !fix configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ !fex configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ !libfoo configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !bas configured 1.0.0
+ !bus configured 1.0.0
+ !foo configured 1.0.0
+ !libfoo configured 1.0.0
+ libbaz configured !0.1.0 available 1.0.0
+ !libbar configured 1.0.0
+ !box configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !bax configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !libfoo configured 1.0.0
+ !buc configured 1.0.0
+ !bux configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !tax configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !tex configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !tiz configured 1.0.0
+ !libbar configured 1.0.0
+ !tex configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !dix configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ !diz configured 1.0.0
+ !dox configured 1.0.0
+ !dex configured 1.0.0
+ !bar configured 1.0.0
+ !libbar configured 1.0.0
+ !libfoo configured 1.0.0
+ !libbar configured 1.0.0
+ libbox configured !0.1.0 available 1.0.0
+ EOO
+
+ $pkg_drop libfoo libbar foo fox fux fix fex bar \
+ baz bac bat bas bus box bax bux bix bex \
+ boo biz buz buc tax tex tix tiz toz tez \
+ tux dex dix diz dox
+ }
+ }
+
+ : configuration-negotiation
+ :
+ {
+ test.arguments += --yes --plan 'build plan:'
+
+ : proj-better-choice
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13a && $rep_fetch
+
+ : bar
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ config.liba.backend=cli (set by bar)
+ new bar/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.backend = cli
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : baz
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by baz)
+ config.liba.backend=gui (set by baz)
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.backend = gui
+ EOO
+
+ $pkg_drop baz
+ }
+
+ : bar-baz
+ :
+ {
+ $clone_cfg;
+
+ $* bar baz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar, baz)
+ config.liba.backend=cli (set by bar)
+ new bar/1.0.0
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ configured baz/1.0.0
+ %info: .+bar.+ is up to date%
+ %info: .+baz.+ is up to date%
+ updated bar/1.0.0
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.backend = cli
+ EOO
+
+ $pkg_drop bar baz
+ }
+
+ : baz-bar
+ :
+ {
+ $clone_cfg;
+
+ $* baz bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar, baz)
+ config.liba.backend=cli (set by bar)
+ new baz/1.0.0
+ new bar/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured baz/1.0.0
+ configured bar/1.0.0
+ %info: .+baz.+ is up to date%
+ %info: .+bar.+ is up to date%
+ updated baz/1.0.0
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ # Would have been cool to end up with gui but looks like we have a map
+ # in configuration cluster.
+ #
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.backend = cli
+ EOO
+
+ $pkg_drop baz bar
+ }
+
+ : bar-baz-biz
+ :
+ {
+ $clone_cfg;
+
+ $* bar baz biz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar, baz, biz)
+ config.liba.backend=gui (set by biz)
+ new bar/1.0.0
+ new baz/1.0.0
+ new biz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ fetched biz/1.0.0
+ unpacked biz/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ configured baz/1.0.0
+ configured biz/1.0.0
+ %info: .+bar.+ is up to date%
+ %info: .+baz.+ is up to date%
+ %info: .+biz.+ is up to date%
+ updated bar/1.0.0
+ updated baz/1.0.0
+ updated biz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ !biz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.backend = gui
+ EOO
+
+ $pkg_drop bar baz biz
+ }
+ }
+
+ : proj-better-value
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13b && $rep_fetch
+
+ : liba
+ :
+ {
+ $clone_cfg;
+
+ $* liba 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ configured liba/1.0.0
+ %info: .+liba.+ is up to date%
+ updated liba/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = false
+ config.liba.buffer = 1024
+ EOO
+
+ $pkg_drop liba
+ }
+
+ : bar
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ config.liba.buffer=2048 (set by bar)
+ new bar/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = false
+ config.liba.buffer = 2048
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : bar-liba
+ :
+ {
+ $clone_cfg;
+
+ $* bar ?liba +{ config.liba.x=true } 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0
+ config.liba.x=true (user configuration)
+ config.liba.buffer=10240 (set by bar)
+ new bar/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+liba.+ is up to date%
+ %info: .+bar.+ is up to date%
+ updated liba/1.0.0
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ config.liba.buffer = 10240
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : baz
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by baz)
+ config.liba.buffer=4096 (set by baz)
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = false
+ config.liba.buffer = 4096
+ EOO
+
+ $pkg_drop baz
+ }
+
+ : baz-liba
+ :
+ {
+ $clone_cfg;
+
+ $* baz ?liba +{ config.liba.x=true } 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0
+ config.liba.x=true (user configuration)
+ config.liba.buffer=10240 (set by baz)
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured baz/1.0.0
+ %info: .+liba.+ is up to date%
+ %info: .+baz.+ is up to date%
+ updated liba/1.0.0
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ config.liba.buffer = 10240
+ EOO
+
+ $pkg_drop baz
+ }
+
+ : baz-biz
+ :
+ {
+ $clone_cfg;
+
+ $* baz biz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by baz, biz)
+ %(
+ config.liba.buffer=10240 (set by baz)
+ config.liba.x=true (set by biz)
+ %|
+ config.liba.x=true (set by biz)
+ config.liba.buffer=10240 (set by baz)
+ %)
+ new baz/1.0.0
+ new biz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ fetched biz/1.0.0
+ unpacked biz/1.0.0
+ configured liba/1.0.0
+ configured baz/1.0.0
+ configured biz/1.0.0
+ %info: .+baz.+ is up to date%
+ %info: .+biz.+ is up to date%
+ updated baz/1.0.0
+ updated biz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ !biz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ config.liba.buffer = 10240
+ EOO
+
+ $pkg_drop baz biz
+ }
+ }
+
+ : proj-disable-unused
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13c && $rep_fetch
+
+ : liba
+ :
+ {
+ $clone_cfg;
+
+ $* liba 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ configured liba/1.0.0
+ %info: .+liba.+ is up to date%
+ updated liba/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ EOO
+
+ $pkg_drop liba
+ }
+
+ : bar
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>~%EOE%;
+ <depends-reflect-clause>:1:5: info: false
+ info: reflect clause:
+ info $config.liba.x
+ info: in depends manifest value of package bar
+ build plan:
+ new liba/1.0.0 (required by bar)
+ config.liba.x=false (set by bar)
+ new bar/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = false
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : bar-baz
+ :
+ {
+ $clone_cfg;
+
+ $* bar baz 2>>~%EOE%;
+ <depends-reflect-clause>:1:5: info: true
+ info: reflect clause:
+ info $config.liba.x
+ info: in depends manifest value of package bar
+ build plan:
+ new liba/1.0.0 (required by bar, baz)
+ config.liba.x=true (set by baz)
+ new bar/1.0.0
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ configured baz/1.0.0
+ %info: .+bar.+ is up to date%
+ %info: .+baz.+ is up to date%
+ updated bar/1.0.0
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ EOO
+
+ $pkg_drop bar baz
+ }
+
+ : bar-liba
+ :
+ {
+ $clone_cfg;
+
+ $* bar ?liba +{ config.liba.x=true } 2>>~%EOE%;
+ <depends-reflect-clause>:1:5: info: true
+ info: reflect clause:
+ info $config.liba.x
+ info: in depends manifest value of package bar
+ build plan:
+ new liba/1.0.0
+ config.liba.x=true (user configuration)
+ new bar/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+liba.+ is up to date%
+ %info: .+bar.+ is up to date%
+ updated liba/1.0.0
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ EOO
+
+ $pkg_drop bar
+ }
+ }
+
+ : proj-use-if-available
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13d && $rep_fetch
+
+ : baz
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar, baz)
+ config.liba.x=true (set by baz)
+ new bar/1.0.0 (required by baz)
+ config.bar.liba_x=true (set by bar)
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ bar configured 1.0.0
+ liba configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ EOO
+
+ $pkg_drop baz
+ }
+
+ : bar
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ new libb/1.0.0 (required by bar)
+ new bar/1.0.0
+ config.bar.liba_x=false (set by bar)
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched libb/1.0.0
+ unpacked libb/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured libb/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ libb configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = false
+ EOO
+
+ $pkg_drop bar
+ }
+ }
+
+ : proj-bogus-config
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13e && $rep_fetch
+
+ : baz
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by baz, biz)
+ config.liba.x=true (set by biz)
+ new biz/1.0.0 (required by baz)
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched biz/1.0.0
+ unpacked biz/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured biz/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ biz configured 1.0.0
+ liba configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ config.liba.buffer = 1024
+ EOO
+
+ $pkg_drop baz
+ }
+ }
+
+ : proj-bogus-config-cycle
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13f && $rep_fetch
+
+ : baz
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>~%EOE% != 0;
+ error: unable to remove bogus configuration values without causing configuration refinement cycle
+ info: consider manually specifying one or more of the following variables as user configuration
+ %(
+ config.liba.buffer=2048
+ config.liba.x=true
+ %|
+ config.liba.x=true
+ config.liba.buffer=2048
+ %)
+ EOE
+
+ $* baz ?liba +{ config.liba.x=true } 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0
+ config.liba.x=true (user configuration)
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured baz/1.0.0
+ %info: .+liba.+ is up to date%
+ %info: .+baz.+ is up to date%
+ updated liba/1.0.0
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ config.liba.buffer = 1024
+ EOO
+
+ $pkg_drop baz
+ }
+ }
+
+ : proj-detect-unset
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13g && $rep_fetch
+
+ : bar
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>EOE != 0
+ <depends-accept-clause>:1:3: error: undefined dependency configuration variable config.liba.x
+ info: was config.liba.x set in earlier prefer or require clause?
+ info: accept condition: ($config.liba.x)
+ info: in depends manifest value of package bar
+ EOE
+ }
+
+ : baz
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>EOE != 0
+ <depends-enable-clause>:1:3: error: undefined dependency configuration variable config.liba.x
+ info: was config.liba.x set in earlier prefer or require clause?
+ info: enable condition: ($config.liba.x)
+ info: in depends manifest value of package baz
+ info: while satisfying baz/1.0.0
+ EOE
+ }
+
+ : biz
+ :
+ {
+ $clone_cfg;
+
+ $* biz 2>>EOE != 0
+ <depends-prefer-clause>:1:12: error: undefined dependency configuration variable config.liba.x
+ info: was config.liba.x set in earlier prefer or require clause?
+ info: prefer clause:
+ x = (!$config.liba.x) # Error.
+ info: in depends manifest value of package biz
+ EOE
+ }
+
+ : box
+ :
+ {
+ $clone_cfg;
+
+ $* box 2>>EOE != 0
+ <depends-reflect-clause>:1:12: error: undefined dependency configuration variable config.liba.x
+ info: was config.liba.x set in earlier prefer or require clause?
+ info: reflect clause:
+ x = (!$config.liba.x) # Error.
+ info: in depends manifest value of package box
+ EOE
+ }
+ }
+
+ : proj-cycle
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13h && $rep_fetch
+
+ : bar baz
+ :
+ {
+ $clone_cfg;
+
+ $* bar baz 2>>EOE != 0
+ error: unable to negotiate acceptable configuration between dependents baz, bar for dependencies liba
+ info: configuration before negotiation:
+ config.liba.buffer=4096 (set by bar)
+ info: configuration after negotiation:
+ config.liba.buffer=8192 (set by baz)
+ EOE
+ }
+ }
+
+ : proj-dependency-reflect
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13i && $rep_fetch
+
+ : bar
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>~%EOE%;
+ <depends-reflect-clause>:1:5: info: yes
+ info: reflect clause:
+ info ($config.liba.x ? yes : no)
+ info: in depends manifest value of package bar
+ build plan:
+ new liba/1.0.0 (required by bar)
+ config.liba.x=true (set by bar)
+ new bar/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ config.liba.buffer = 1024
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : baz
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>~%EOE%;
+ <depends-reflect-clause>:1:5: info: 4096
+ info: reflect clause:
+ info $config.liba.buffer
+ info: in depends manifest value of package baz
+ build plan:
+ new liba/1.0.0 (required by baz)
+ config.liba.buffer=4096 (set by baz)
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = false
+ config.liba.buffer = 4096
+ EOO
+
+ $pkg_drop baz
+ }
+ }
+
+ : proj-non-sensible
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13j && $rep_fetch
+
+ : bar-baz
+ :
+ {
+ $clone_cfg;
+
+ $* bar baz 2>>/~%EOE% != 0
+ error: unable to negotiate sensible configuration for dependency liba
+ % .+/root.build:5:1: error: buffer must be at least 4096 if feature x is enabled%
+ info: negotiated configuration:
+ %(
+ config.liba.buffer=2048 (set by bar)
+ config.liba.x=true (set by baz)
+ %|
+ config.liba.x=true (set by baz)
+ config.liba.buffer=2048 (set by bar)
+ %)
+ EOE
+ }
+
+ : biz-baz
+ :
+ {
+ $clone_cfg;
+
+ $* biz baz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by baz, biz)
+ %(
+ config.liba.buffer=4096 (set by biz)
+ config.liba.x=true (set by baz)
+ %|
+ config.liba.x=true (set by baz)
+ config.liba.buffer=4096 (set by biz)
+ %)
+ new biz/1.0.0
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched biz/1.0.0
+ unpacked biz/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured biz/1.0.0
+ configured baz/1.0.0
+ %info: .+biz.+ is up to date%
+ %info: .+baz.+ is up to date%
+ updated biz/1.0.0
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !biz configured 1.0.0
+ liba configured 1.0.0
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ config.liba.buffer = 4096
+ EOO
+
+ $pkg_drop biz baz
+ }
+ }
+
+ : proj-unaccept
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13k && $rep_fetch
+
+ : bar-baz
+ :
+ {
+ $clone_cfg;
+
+ $* bar baz 2>>EOE != 0
+ error: unable to negotiate acceptable configuration with dependent bar for dependencies liba
+ info: configuration before negotiation:
+ config.liba.buffer=8192 (set by baz)
+ EOE
+ }
+ }
+
+ : proj-require-system
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13l && $rep_fetch
+
+ : bar
+ :
+ {
+ +$clone_cfg
+
+ : basic
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ config.liba.x=true (set by bar)
+ new libb/1.0.0 (required by bar)
+ new bar/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched libb/1.0.0
+ unpacked libb/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured libb/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ libb configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : sys-liba-1
+ :
+ {
+ $clone_cfg;
+
+ $* bar '?sys:liba' 2>>~%EOE%;
+ build plan:
+ configure sys:liba/*
+ config.liba.x=true (expected by bar)
+ new libb/1.0.0 (required by bar)
+ new bar/1.0.0
+ fetched libb/1.0.0
+ unpacked libb/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured sys:liba/*
+ configured libb/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured,system !* available 1.0.0
+ libb configured 1.0.0
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : sys-liba-2
+ :
+ {
+ $clone_cfg;
+
+ $* bar '?sys:liba' +{ config.liba.x=false } 2>>EOE != 0
+ error: unable to negotiate acceptable configuration with dependent bar for dependencies liba
+ info: configuration before negotiation:
+ config.liba.x=false (user configuration)
+ EOE
+ }
+
+ : bar-sys-liba-3
+ :
+ {
+ $clone_cfg;
+
+ $* bar '?sys:liba' +{ config.liba.x=[null] } 2>>EOE != 0
+ error: unable to negotiate acceptable configuration with dependent bar for dependencies liba
+ info: configuration before negotiation:
+ config.liba.x=[null] (user configuration)
+ EOE
+ }
+
+ : sys-liba-4
+ :
+ {
+ $clone_cfg;
+
+ $* bar '?sys:liba' +{ config.liba.x=true } 2>>~%EOE%;
+ build plan:
+ configure sys:liba/*
+ config.liba.x=true (expected user configuration)
+ new libb/1.0.0 (required by bar)
+ new bar/1.0.0
+ fetched libb/1.0.0
+ unpacked libb/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured sys:liba/*
+ configured libb/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured,system !* available 1.0.0
+ libb configured 1.0.0
+ EOO
+
+ $pkg_drop bar
+ }
+ }
+
+ : baz
+ :
+ {
+ +$clone_cfg
+
+ : basic
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by baz)
+ config.liba.x=true (set by baz)
+ new libb/1.0.0 (required by baz)
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched libb/1.0.0
+ unpacked libb/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured libb/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured 1.0.0
+ libb configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ EOO
+
+ $pkg_drop baz
+ }
+
+ : sys-liba-1
+ :
+ {
+ $clone_cfg;
+
+ $* baz '?sys:liba' +{ config.liba.x=false } 2>>EOE != 0
+ error: unable to negotiate configuration for system dependency liba without configuration information
+ info: consider specifying system dependency version that has corresponding available package
+ info: dependent baz has prefer/accept clauses that cannot be evaluated without configuration information
+ EOE
+ }
+
+ : sys-liba-2
+ :
+ {
+ $clone_cfg;
+
+ $* baz '?sys:liba/1.0.0' 2>>~%EOE%;
+ build plan:
+ configure sys:liba/1.0.0
+ config.liba.x=true (expected by baz)
+ new libb/1.0.0 (required by baz)
+ new baz/1.0.0
+ fetched libb/1.0.0
+ unpacked libb/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured sys:liba/1.0.0
+ configured libb/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured,system !1.0.0
+ libb configured 1.0.0
+ EOO
+
+ $pkg_drop baz
+ }
+
+ : sys-liba-3
+ :
+ {
+ $clone_cfg;
+
+ $* baz '?sys:liba/1.0.0' +{ config.liba.x=false } 2>>EOE != 0
+ error: unable to negotiate acceptable configuration with dependent baz for dependencies liba
+ info: configuration before negotiation:
+ config.liba.x=false (user configuration)
+ EOE
+ }
+
+ : bar-sys-liba-4
+ :
+ {
+ $clone_cfg;
+
+ $* baz '?sys:liba/1.0.0' +{ config.liba.x=[null] } 2>>EOE != 0
+ <depends-accept-clause>:1: error: invalid bool value: null
+ info: accept condition: ($config.liba.x)
+ info: in depends manifest value of package baz
+ EOE
+ }
+
+ : sys-liba-5
+ :
+ {
+ $clone_cfg;
+
+ $* baz '?sys:liba/1.0.0' +{ config.liba.x=true } 2>>~%EOE%;
+ build plan:
+ configure sys:liba/1.0.0
+ config.liba.x=true (expected user configuration)
+ new libb/1.0.0 (required by baz)
+ new baz/1.0.0
+ fetched libb/1.0.0
+ unpacked libb/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured sys:liba/1.0.0
+ configured libb/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ liba configured,system !1.0.0
+ libb configured 1.0.0
+ EOO
+
+ $pkg_drop baz
+ }
+ }
+ }
+
+ : proj-require-basics
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13m && $rep_fetch
+
+ : bar
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ config.liba.x=true (set by bar)
+ new bar/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ config.liba.y = false
+ config.liba.n = 1024
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : baz
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar, baz)
+ %(
+ config.liba.y=true (set by baz)
+ config.liba.x=true (set by bar)
+ %|
+ config.liba.x=true (set by bar)
+ config.liba.y=true (set by baz)
+ %)
+ new bar/1.0.0 (required by baz)
+ new baz/1.0.0
+ config.baz.bar=true (set by baz)
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ bar configured 1.0.0
+ liba configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/liba-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.liba.x = true
+ config.liba.y = true
+ config.liba.n = 1024
+ EOO
+
+ cat cfg/baz-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.baz.bar = true
+ EOO
+
+ $pkg_drop baz
+ }
+
+ : biz
+ :
+ {
+ $clone_cfg;
+
+ $* biz 2>>EOE != 0
+ error: configuration variable config.liba.x is not set to true
+ info: config.liba.x set in require clause of dependent biz
+ info: require clause:
+ config.liba.x = false # Error: not true
+ info: in depends manifest value of package biz
+ EOE
+ }
+
+ : bix
+ :
+ {
+ $clone_cfg;
+
+ $* bix 2>>EOE != 0
+ error: configuration variable config.liba.n is not of bool type
+ info: config.liba.n set in require clause of dependent bix
+ info: require clause:
+ config.liba.n = 1 # Error: not bool
+ info: in depends manifest value of package bix
+ EOE
+ }
+
+ : box
+ :
+ {
+ $clone_cfg;
+
+ $* box 2>>EOE != 0
+ error: package liba has no configuration variable config.liba.z
+ info: config.liba.z set in require clause of dependent box
+ info: require clause:
+ config.liba.z = true # Error: no such variable
+ info: in depends manifest value of package box
+ EOE
+ }
+ }
+
+ : proj-reflect-append
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13n && $rep_fetch
+
+ : bar
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ new libb/1.0.0 (required by bar)
+ new bar/1.0.0
+ config.bar.libs=liba libb (set by bar)
+ config.bar.x=true (set by bar)
+ config.bar.y=true (set by bar)
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched libb/1.0.0
+ unpacked libb/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured libb/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ libb configured 1.0.0
+ EOO
+
+ cat cfg/bar-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.bar.x = true
+ config.bar.y = true
+ config.bar.libs = liba libb
+ EOO
+
+ $pkg_drop bar
+ }
+ }
+
+ : proj-reflect-override
+ :
+ {
+ +$clone_root_cfg && $rep_add $rep/t13o && $rep_fetch
+
+ : bar
+ :
+ {
+ $clone_cfg;
+
+ $* bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ new bar/1.0.0
+ config.bar.x=true (set by bar)
+ config.bar.y=true (set by bar)
+ config.bar.z=true (set by bar)
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/bar-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.bar.x = true
+ config.bar.y = true
+ config.bar.z = true
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : bar-config-1
+ :
+ {
+ $clone_cfg;
+
+ $* config.bar.y=true -- bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ new bar/1.0.0
+ config.bar.y=true (user configuration)
+ config.bar.x=true (set by bar)
+ config.bar.z=true (set by bar)
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/bar-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.bar.x = true
+ config.bar.y = true
+ config.bar.z = true
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : bar-config-2
+ :
+ {
+ $clone_cfg;
+
+ $* config.bar.y=false -- bar 2>>EOE != 0
+ error: reflect variable config.bar.y overriden by user configuration
+ info: reflect value: config.bar.y=true
+ info: user value: config.bar.y=false
+ info: reflect clause:
+ config.bar.x = true
+ config.bar.y = true
+ if ($config.origin(config.bar.z) != 'override')
+ config.bar.z = true
+ info: in depends manifest value of package bar
+ info: while satisfying bar/1.0.0
+ EOE
+ }
+
+ : bar-config-3
+ :
+ {
+ $clone_cfg;
+
+ $* config.bar.z=false -- bar 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ new bar/1.0.0
+ config.bar.z=false (user configuration)
+ config.bar.x=true (set by bar)
+ config.bar.y=true (set by bar)
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ %info: .+bar.+ is up to date%
+ updated bar/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/bar-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.bar.x = true
+ config.bar.y = true
+ config.bar.z = false
+ EOO
+
+ $pkg_drop bar
+ }
+
+ : baz
+ :
+ {
+ $clone_cfg;
+
+ $* baz 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ new bar/1.0.0 (required by baz)
+ config.bar.y=true (set by baz)
+ config.bar.x=true (set by bar)
+ config.bar.z=true (set by bar)
+ new baz/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ fetched baz/1.0.0
+ unpacked baz/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ configured baz/1.0.0
+ %info: .+baz.+ is up to date%
+ updated baz/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !baz configured 1.0.0
+ bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/bar-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.bar.x = true
+ config.bar.y = true
+ config.bar.z = true
+ EOO
+
+ $pkg_drop baz
+ }
+
+ : biz
+ :
+ {
+ $clone_cfg;
+
+ $* biz 2>>EOE != 0
+ error: reflect variable config.bar.y overriden by dependent biz
+ info: reflect value: config.bar.y=true
+ info: dependent value: config.bar.y=false
+ info: reflect clause:
+ config.bar.x = true
+ config.bar.y = true
+ if ($config.origin(config.bar.z) != 'override')
+ config.bar.z = true
+ info: in depends manifest value of package bar
+ info: while satisfying bar/1.0.0
+ EOE
+ }
+
+ : biz-bar
+ :
+ {
+ $clone_cfg;
+
+ $* biz ?bar +{ config.bar.y=false } 2>>EOE != 0
+ error: reflect variable config.bar.y overriden by user configuration
+ info: reflect value: config.bar.y=true
+ info: user value: config.bar.y=false
+ info: reflect clause:
+ config.bar.x = true
+ config.bar.y = true
+ if ($config.origin(config.bar.z) != 'override')
+ config.bar.z = true
+ info: in depends manifest value of package bar
+ info: while satisfying bar/1.0.0
+ EOE
+ }
+
+ : bix
+ :
+ {
+ $clone_cfg;
+
+ $* bix 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ new bar/1.0.0 (required by bix)
+ config.bar.z=false (set by bix)
+ config.bar.x=true (set by bar)
+ config.bar.y=true (set by bar)
+ new bix/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ fetched bix/1.0.0
+ unpacked bix/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ configured bix/1.0.0
+ %info: .+bix.+ is up to date%
+ updated bix/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bix configured 1.0.0
+ bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/bar-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.bar.x = true
+ config.bar.y = true
+ config.bar.z = false
+ EOO
+
+ $pkg_drop bix
+ }
+
+ : bix-bar
+ :
+ {
+ $clone_cfg;
+
+ $* bix ?bar +{ config.bar.z=false } 2>>~%EOE%;
+ build plan:
+ new liba/1.0.0 (required by bar)
+ new bar/1.0.0
+ config.bar.z=false (user configuration)
+ config.bar.x=true (set by bar)
+ config.bar.y=true (set by bar)
+ new bix/1.0.0
+ fetched liba/1.0.0
+ unpacked liba/1.0.0
+ fetched bar/1.0.0
+ unpacked bar/1.0.0
+ fetched bix/1.0.0
+ unpacked bix/1.0.0
+ configured liba/1.0.0
+ configured bar/1.0.0
+ configured bix/1.0.0
+ %info: .+bar.+ is up to date%
+ %info: .+bix.+ is up to date%
+ updated bar/1.0.0
+ updated bix/1.0.0
+ EOE
+
+ $pkg_status -r >>EOO;
+ !bix configured 1.0.0
+ bar configured 1.0.0
+ liba configured 1.0.0
+ EOO
+
+ cat cfg/bar-1.0.0/build/config.build >>~%EOO%;
+ %.*
+ config.bar.x = true
+ config.bar.y = true
+ config.bar.z = false
+ EOO
+
+ $pkg_drop bix
+ }
+ }
+ }
}
: test-dependency
@@ -5335,7 +13995,8 @@ test.options += --no-progress
+cp -r $src/libhello-1.0.0 ./libhello
+cat <<EOI >+libhello/build/root.build
config [bool] config.libhello.develop ?= false
- text "develop=$config.libhello.develop"
+ if ($build.mode != 'skeleton')
+ text "develop=$config.libhello.develop"
EOI
+$rep_add libhello --type dir
+$rep_fetch
@@ -6838,24 +15499,76 @@ else
$rep_add -d t2 $rep/t7a && $rep_fetch -d t2;
- $* ?foo libbaz +{ --config-name t2 } <<EOI 2>>~%EOE%;
+ $* ?foo libbaz +{ --config-name t2 } --verbose 5 <<EOI 2>>~%EOE%;
y
EOI
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ %trace: collect_build: add libbaz/1.0.0 \[t2.\]%
+ %trace: collect_build_prerequisites: begin libbaz/1.0.0 \[t2.\]%
+ %trace: collect_build_prerequisites: end libbaz/1.0.0 \[t2.\]%
+ %.*
+ trace: collect_build_prerequisites: begin foo/1.0.0
+ %.*
+ %trace: collect_build_prerequisites: no cfg-clause for dependency libbaz/1.0.0 \[t2.\] of dependent foo/1.0.0%
+ trace: collect_build_prerequisites: end foo/1.0.0
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ trace: evaluate_dependency: libbaz/1.0.0: unused
+ %.*
+ trace: evaluate_dependency: foo/1.0.0: unused
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ %.*
+ trace: collect_drop: foo/1.0.0 package version needs to be replaced with drop
+ trace: pkg_build: collection failed due to package version replacement, retry from scratch
+ %.*
+ trace: pkg_build: refine package collection/plan execution from scratch
+ %.*
+ %trace: collect_build: add libbaz/1.0.0 \[t2.\]%
+ %trace: collect_build_prerequisites: begin libbaz/1.0.0 \[t2.\]%
+ %trace: collect_build_prerequisites: end libbaz/1.0.0 \[t2.\]%
+ trace: collect_build: apply version replacement for foo/1.0.0
+ trace: collect_build: replacement: drop
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
+ %trace: evaluate_dependency: libbuild2-bar/1.0.0 \[t1..bpkg.build2.\]: unused%
+ %.*
+ trace: pkg_build: refine package collection/plan execution
+ %.*
+ trace: execute_plan: simulate: yes
+ %.*
% new libbaz/1.0.0 \[t2.\]%
% drop libbuild2-bar/1.0.0 \[t1..bpkg.build2.\] \(unused\)%
drop libbaz/1.0.0 (unused)
drop foo/1.0.0 (unused)
- continue? [Y/n] disfigured foo/1.0.0
+ continue? [Y/n] trace: execute_plan: simulate: no
+ %.*
+ disfigured foo/1.0.0
+ %.*
disfigured libbaz/1.0.0
+ %.*
%disfigured libbuild2-bar/1.0.0 \[t1..bpkg.build2.\]%
+ %.*
%fetched libbaz/1.0.0 \[t2.\]%
+ %.*
%unpacked libbaz/1.0.0 \[t2.\]%
+ %.*
%purged libbuild2-bar/1.0.0 \[t1..bpkg.build2.\]%
+ %.*
purged libbaz/1.0.0
+ %.*
purged foo/1.0.0
+ %.*
%configured libbaz/1.0.0 \[t2.\]%
- %info: t2.+libbaz-1.0.0.+ is up to date%
+ %.*
+ %info: .+t2.+libbaz-1.0.0.+ is up to date%
+ %.*
%updated libbaz/1.0.0 \[t2.\]%
+ %.*
EOE
$pkg_status -d t1 --link -r >>/EOO
diff --git a/tests/pkg-build/t11a b/tests/pkg-build/t11a
new file mode 120000
index 0000000..4f78412
--- /dev/null
+++ b/tests/pkg-build/t11a
@@ -0,0 +1 @@
+../common/dependency-alternatives/t11a \ No newline at end of file
diff --git a/tests/pkg-build/t12a b/tests/pkg-build/t12a
new file mode 120000
index 0000000..d421f92
--- /dev/null
+++ b/tests/pkg-build/t12a
@@ -0,0 +1 @@
+../common/satisfy/t12a/ \ No newline at end of file
diff --git a/tests/pkg-build/t12b b/tests/pkg-build/t12b
new file mode 120000
index 0000000..0fbba8a
--- /dev/null
+++ b/tests/pkg-build/t12b
@@ -0,0 +1 @@
+../common/satisfy/t12b/ \ No newline at end of file
diff --git a/tests/pkg-build/t13a b/tests/pkg-build/t13a
new file mode 120000
index 0000000..9d8fb23
--- /dev/null
+++ b/tests/pkg-build/t13a
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13a/ \ No newline at end of file
diff --git a/tests/pkg-build/t13b b/tests/pkg-build/t13b
new file mode 120000
index 0000000..d17701b
--- /dev/null
+++ b/tests/pkg-build/t13b
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13b/ \ No newline at end of file
diff --git a/tests/pkg-build/t13c b/tests/pkg-build/t13c
new file mode 120000
index 0000000..1c534d0
--- /dev/null
+++ b/tests/pkg-build/t13c
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13c/ \ No newline at end of file
diff --git a/tests/pkg-build/t13d b/tests/pkg-build/t13d
new file mode 120000
index 0000000..6933497
--- /dev/null
+++ b/tests/pkg-build/t13d
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13d/ \ No newline at end of file
diff --git a/tests/pkg-build/t13e b/tests/pkg-build/t13e
new file mode 120000
index 0000000..d8d84cc
--- /dev/null
+++ b/tests/pkg-build/t13e
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13e/ \ No newline at end of file
diff --git a/tests/pkg-build/t13f b/tests/pkg-build/t13f
new file mode 120000
index 0000000..bf556bc
--- /dev/null
+++ b/tests/pkg-build/t13f
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13f/ \ No newline at end of file
diff --git a/tests/pkg-build/t13g b/tests/pkg-build/t13g
new file mode 120000
index 0000000..4dc8eb4
--- /dev/null
+++ b/tests/pkg-build/t13g
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13g/ \ No newline at end of file
diff --git a/tests/pkg-build/t13h b/tests/pkg-build/t13h
new file mode 120000
index 0000000..f99413a
--- /dev/null
+++ b/tests/pkg-build/t13h
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13h/ \ No newline at end of file
diff --git a/tests/pkg-build/t13i b/tests/pkg-build/t13i
new file mode 120000
index 0000000..bba4fd3
--- /dev/null
+++ b/tests/pkg-build/t13i
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13i/ \ No newline at end of file
diff --git a/tests/pkg-build/t13j b/tests/pkg-build/t13j
new file mode 120000
index 0000000..da120da
--- /dev/null
+++ b/tests/pkg-build/t13j
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13j/ \ No newline at end of file
diff --git a/tests/pkg-build/t13k b/tests/pkg-build/t13k
new file mode 120000
index 0000000..b1e5a14
--- /dev/null
+++ b/tests/pkg-build/t13k
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13k/ \ No newline at end of file
diff --git a/tests/pkg-build/t13l b/tests/pkg-build/t13l
new file mode 120000
index 0000000..40d9561
--- /dev/null
+++ b/tests/pkg-build/t13l
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13l/ \ No newline at end of file
diff --git a/tests/pkg-build/t13m b/tests/pkg-build/t13m
new file mode 120000
index 0000000..0154455
--- /dev/null
+++ b/tests/pkg-build/t13m
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13m/ \ No newline at end of file
diff --git a/tests/pkg-build/t13n b/tests/pkg-build/t13n
new file mode 120000
index 0000000..1ed57ca
--- /dev/null
+++ b/tests/pkg-build/t13n
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13n/ \ No newline at end of file
diff --git a/tests/pkg-build/t13o b/tests/pkg-build/t13o
new file mode 120000
index 0000000..9516f8f
--- /dev/null
+++ b/tests/pkg-build/t13o
@@ -0,0 +1 @@
+../common/dependency-alternatives/t13o/ \ No newline at end of file