aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2022-06-20 20:59:53 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2022-06-23 12:35:42 +0300
commitc0ca17391c41048cd1db19f0aa08e060624f4bd1 (patch)
tree4037ed4be1abf8f4b85e7e5420c3cac2d2f10503
parent2ee693000ff6ea44cfd4fc51c7b058258056610a (diff)
Add support for additional *-build package manifest values and alternative buildfile naming
-rw-r--r--bpkg/manifest-utility.cxx224
-rw-r--r--bpkg/manifest-utility.hxx23
-rw-r--r--bpkg/package-skeleton.cxx22
-rw-r--r--bpkg/package.cxx1
-rw-r--r--bpkg/package.hxx40
-rw-r--r--bpkg/package.xml44
-rw-r--r--bpkg/pkg-checkout.cxx5
-rw-r--r--bpkg/pkg-unpack.cxx10
-rw-r--r--bpkg/pkg-verify.cxx153
-rw-r--r--bpkg/pkg-verify.hxx5
-rw-r--r--bpkg/rep-fetch.cxx72
-rw-r--r--bpkg/rep-fetch.hxx6
-rw-r--r--bpkg/utility.cxx10
-rw-r--r--bpkg/utility.hxx4
-rw-r--r--doc/manual.cli49
-rw-r--r--tests/common/dependency-alternatives/t11a/libbar-1.0.0.tar.gzbin406 -> 465 bytes
-rw-r--r--tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gzbin409 -> 480 bytes
-rw-r--r--tests/pkg-build.testscript10
18 files changed, 523 insertions, 155 deletions
diff --git a/bpkg/manifest-utility.cxx b/bpkg/manifest-utility.cxx
index d205c2d..56da715 100644
--- a/bpkg/manifest-utility.cxx
+++ b/bpkg/manifest-utility.cxx
@@ -3,9 +3,11 @@
#include <bpkg/manifest-utility.hxx>
+#include <sstream>
#include <cstring> // strcspn()
#include <libbutl/b.hxx>
+#include <libbutl/filesystem.hxx> // dir_iterator
#include <bpkg/package.hxx> // wildcard_version
#include <bpkg/diagnostics.hxx>
@@ -357,19 +359,73 @@ namespace bpkg
}
}
+ // Return the sorted list of *.build files (first) which are present in the
+ // package's build/config/ subdirectory (or their alternatives) together
+ // with the *-build manifest value names they correspond to (second). Skip
+ // files which are already present in the specified list. Note: throws
+ // system_error on filesystem errors.
+ //
+ static vector<pair<path, path>>
+ find_buildfiles (const dir_path& config,
+ const string& ext,
+ const vector<buildfile>& bs)
+ {
+ vector<pair<path, path>> r;
+
+ for (const dir_entry& de:
+ dir_iterator (config, false /* ignore_dangling */))
+ {
+ if (de.type () == entry_type::regular)
+ {
+ const path& p (de.path ());
+ const char* e (p.extension_cstring ());
+
+ if (e != nullptr && ext == e)
+ {
+ path f (config.leaf () / p.base ()); // Relative to build/.
+
+ if (find_if (bs.begin (), bs.end (),
+ [&f] (const auto& v) {return v.path == f;}) ==
+ bs.end ())
+ {
+ r.emplace_back (config / p, move (f));
+ }
+ }
+ }
+ }
+
+ sort (r.begin (), r.end (),
+ [] (const auto& x, const auto& y) {return x.second < y.second;});
+
+ return r;
+ }
+
string
package_buildfiles_checksum (const optional<string>& bb,
const optional<string>& rb,
- const dir_path& d)
+ const vector<buildfile>& bs,
+ const dir_path& d,
+ optional<bool> an)
{
- if (bb && rb)
+ if (d.empty ())
{
+ assert (bb);
+
sha256 cs (*bb);
- cs.append (*rb);
+
+ if (rb)
+ cs.append (*rb);
+
+ for (const buildfile& b: bs)
+ cs.append (b.content);
+
return cs.string ();
}
- auto checksum = [&bb, &rb] (const path& b, const path& r)
+ auto checksum = [&bb, &rb, &bs] (const path& b,
+ const path& r,
+ const dir_path& c,
+ const string& e)
{
sha256 cs;
@@ -396,24 +452,176 @@ namespace bpkg
else
append_file (b);
+ bool root (true);
+
if (rb)
cs.append (*rb);
else if (exists (r))
append_file (r);
+ else
+ root = false;
+
+ for (const buildfile& b: bs)
+ cs.append (b.content);
+
+ if (root && exists (c))
+ try
+ {
+ for (auto& f: find_buildfiles (c, e, bs))
+ append_file (f.first);
+ }
+ catch (const system_error& e)
+ {
+ fail << "unable to scan directory " << c << ": " << e;
+ }
return string (cs.string ());
};
- // Check the alternative bootstrap file first since it is more
- // specific.
+ // Verify that the deduced naming scheme matches the specified one and
+ // fail if that's not the case.
+ //
+ auto verify = [an, &d] (bool alt_naming)
+ {
+ assert (an);
+
+ if (*an != alt_naming)
+ fail << "buildfile naming scheme mismatch between manifest and "
+ << "package directory " << d;
+ };
+
+ // Check the alternative bootstrap file first since it is more specific.
//
path bf;
if (exists (bf = d / alt_bootstrap_file))
- return checksum (bf, d / alt_root_file);
+ {
+ if (an)
+ verify (true /* alt_naming */);
+
+ return checksum (bf,
+ d / alt_root_file,
+ d / alt_config_dir,
+ alt_build_ext);
+ }
else if (exists (bf = d / std_bootstrap_file))
- return checksum (bf, d / std_root_file);
+ {
+ if (an)
+ verify (false /* alt_naming */);
+
+ return checksum (bf,
+ d / std_root_file,
+ d / std_config_dir,
+ std_build_ext);
+ }
else
fail << "unable to find bootstrap.build file in package directory "
<< d << endf;
}
+
+ void
+ load_package_buildfiles (package_manifest& m, const dir_path& d, bool erp)
+ {
+ auto load_buildfiles = [&m, &d, erp] (const path& b,
+ const path& r,
+ const dir_path& c,
+ const string& ext)
+ {
+ auto diag_path = [&d, erp] (const path& p)
+ {
+ return !erp ? p : p.leaf (d);
+ };
+
+ auto load = [&diag_path] (const path& f)
+ {
+ try
+ {
+ ifdstream ifs (f);
+ string r (ifs.read_text ());
+ ifs.close ();
+ return r;
+ }
+ catch (const io_error& e)
+ {
+ // Sanitize the exception description.
+ //
+ ostringstream os;
+ os << "unable to read from " << diag_path (f) << ": " << e;
+ throw runtime_error (os.str ());
+ }
+ };
+
+ if (!m.bootstrap_build)
+ m.bootstrap_build = load (b);
+
+ if (!m.root_build && exists (r))
+ m.root_build = load (r);
+
+ if (m.root_build && exists (c))
+ try
+ {
+ for (auto& f: find_buildfiles (c, ext, m.buildfiles))
+ m.buildfiles.emplace_back (move (f.second), load (f.first));
+ }
+ catch (const system_error& e)
+ {
+ // Sanitize the exception description.
+ //
+ ostringstream os;
+ os << "unable to scan directory " << diag_path (c) << ": " << e;
+ throw runtime_error (os.str ());
+ }
+ };
+
+ // Set the manifest's alt_naming flag to the deduced value if absent and
+ // verify that it matches otherwise.
+ //
+ auto alt_naming = [&m, &d, erp] (bool v)
+ {
+ if (!m.alt_naming)
+ {
+ m.alt_naming = v;
+ }
+ else if (*m.alt_naming != v)
+ {
+ string e ("buildfile naming scheme mismatch between manifest and "
+ "package directory");
+
+ if (!erp)
+ e += " " + d.string ();
+
+ throw runtime_error (e);
+ }
+ };
+
+ // Check the alternative bootstrap file first since it is more specific.
+ //
+ path bf;
+ if (exists (bf = d / alt_bootstrap_file))
+ {
+ alt_naming (true);
+
+ load_buildfiles (bf,
+ d / alt_root_file,
+ d / alt_config_dir,
+ alt_build_ext);
+ }
+ else if (exists (bf = d / std_bootstrap_file))
+ {
+ alt_naming (false);
+
+ load_buildfiles (bf,
+ d / std_root_file,
+ d / std_config_dir,
+ std_build_ext);
+ }
+ else
+ {
+ string e ("unable to find bootstrap.build file in package directory");
+
+ if (!erp)
+ e += " " + d.string ();
+
+ throw runtime_error (e);
+ }
+ }
}
diff --git a/bpkg/manifest-utility.hxx b/bpkg/manifest-utility.hxx
index 8701b65..abb85ab 100644
--- a/bpkg/manifest-utility.hxx
+++ b/bpkg/manifest-utility.hxx
@@ -154,14 +154,29 @@ namespace bpkg
const dir_path& src_dir,
const package_info*);
- // Caclulate the checksum of the buildfiles using the *-build manifest
- // values, unless unspecified in which case use the files in the package
- // source directory.
+ // Calculate the checksum of the buildfiles using the *-build manifest
+ // values. If the package source directory is specified (not empty), then
+ // use the files it contains for unspecified values. If the alt_naming flag
+ // is also specified for the latter case, then verify the package's
+ // buildfile naming scheme against its value and fail on mismatch.
//
string
package_buildfiles_checksum (const optional<string>& bootstrap_build,
const optional<string>& root_build,
- const dir_path& src_dir);
+ const vector<buildfile>& buildfiles,
+ const dir_path& src_dir = {},
+ optional<bool> alt_naming = nullopt);
+
+ // Load the package's buildfiles for unspecified manifest values. Throw
+ // std::runtime_error for underlying errors (unable to find bootstrap.build,
+ // unable to read from file, etc). Optionally convert paths used in the
+ // potential error description to be relative to the package source
+ // directory.
+ //
+ void
+ load_package_buildfiles (package_manifest&,
+ const dir_path& src_dir,
+ bool err_path_relative = false);
}
#endif // BPKG_MANIFEST_UTILITY_HXX
diff --git a/bpkg/package-skeleton.cxx b/bpkg/package-skeleton.cxx
index d58c846..a3e0b5a 100644
--- a/bpkg/package-skeleton.cxx
+++ b/bpkg/package-skeleton.cxx
@@ -2501,7 +2501,10 @@ namespace bpkg
// additional files.
//
{
- path bf (skl.src_root_ / std_bootstrap_file);
+ bool an (*ap.alt_naming);
+
+ path bf (skl.src_root_ /
+ (an ? alt_bootstrap_file : std_bootstrap_file));
mk_p (bf.directory ());
@@ -2524,7 +2527,22 @@ namespace bpkg
save (*ap.bootstrap_build, bf);
if (ap.root_build)
- save (*ap.root_build, skl.src_root_ / std_root_file);
+ save (*ap.root_build,
+ skl.src_root_ / (an ? alt_root_file : std_root_file));
+
+ for (const buildfile& f: ap.buildfiles)
+ {
+ path p (skl.src_root_ /
+ (an ? alt_build_dir : std_build_dir) /
+ f.path);
+
+ p += ".";
+ p += (an ? alt_build_ext : std_build_ext);
+
+ mk_p (p.directory ());
+
+ save (f.content, p);
+ }
}
// Create the manifest file containing the bare minimum of values
diff --git a/bpkg/package.cxx b/bpkg/package.cxx
index c02bdf4..a7282c5 100644
--- a/bpkg/package.cxx
+++ b/bpkg/package.cxx
@@ -676,6 +676,7 @@ namespace bpkg
changed = package_buildfiles_checksum (
nullopt /* bootstrap_build */,
nullopt /* root_build */,
+ {} /* buildfiles */,
d) != *p->buildfiles_checksum;
}
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index dc5031c..694d068 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, 19, closed)
+#pragma db model version(DB_SCHEMA_VERSION_BASE, 20, closed)
namespace bpkg
{
@@ -653,6 +653,10 @@ namespace bpkg
available_package_id (package_name, const bpkg::version&);
};
+ // buildfile
+ //
+ #pragma db value(buildfile) definition
+
#pragma db object pointer(shared_ptr) session
class available_package
{
@@ -690,12 +694,14 @@ namespace bpkg
small_vector<test_dependency, 1> tests;
// Note that while the bootstrap buildfile is always present for stub
- // packages, we don't save bootstrap/root buildfiles for stubs of any kind
- // (can come from repository, be based on system selected package, etc),
- // leaving *_build as nullopt.
+ // packages, we don't save buildfiles for stubs of any kind (can come from
+ // repository, be based on system selected package, etc), leaving *_build
+ // as nullopt and buildfiles empty.
//
- optional<string> bootstrap_build;
- optional<string> root_build;
+ optional<bool> alt_naming;
+ optional<string> bootstrap_build;
+ optional<string> root_build;
+ vector<buildfile> buildfiles;
// Present for non-transient objects only (and only for certain repository
// types).
@@ -719,10 +725,12 @@ namespace bpkg
{
if (!stub ())
{
- assert (m.bootstrap_build.has_value ());
+ assert (m.bootstrap_build.has_value () && m.alt_naming.has_value ());
+ alt_naming = m.alt_naming;
bootstrap_build = move (m.bootstrap_build);
root_build = move (m.root_build);
+ buildfiles = move (m.buildfiles);
}
}
@@ -813,6 +821,20 @@ namespace bpkg
//
#pragma db member(tests) id_column("") value_column("test_")
+ // alt_naming
+ //
+ // @@ TMP Drop when database migration to the schema version 20 is no
+ // longer supported.
+ //
+ // Note that since no real packages with alternative buildfile naming
+ // use conditional dependencies yet, we can just set alt_naming to
+ // false during migration to the database schema version 20. Also we
+ // never rely on alt_naming to be nullopt for the stub packages, so
+ // let's not complicate things and set alt_naming to false for them
+ // either.
+ //
+ #pragma db member(alt_naming) default(false)
+
// *_build
//
// @@ TMP Drop when database migration to the schema version 15 is no
@@ -827,6 +849,10 @@ namespace bpkg
//
#pragma db member(bootstrap_build) default("")
+ // buildfiles
+ //
+ #pragma db member(buildfiles) id_column("") value_column("")
+
private:
friend class odb::access;
available_package () = default;
diff --git a/bpkg/package.xml b/bpkg/package.xml
index 8959529..3fa1bc0 100644
--- a/bpkg/package.xml
+++ b/bpkg/package.xml
@@ -1,4 +1,48 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="sqlite" version="1">
+ <changeset version="20">
+ <alter-table name="main.available_package">
+ <add-column name="alt_naming" type="INTEGER" null="true" default="0"/>
+ </alter-table>
+ <add-table name="main.available_package_buildfiles" kind="container">
+ <column name="name" type="TEXT" null="true" options="COLLATE NOCASE"/>
+ <column name="version_epoch" type="INTEGER" null="true"/>
+ <column name="version_canonical_upstream" type="TEXT" null="true"/>
+ <column name="version_canonical_release" type="TEXT" null="true" options="COLLATE BINARY"/>
+ <column name="version_revision" type="INTEGER" null="true"/>
+ <column name="version_iteration" type="INTEGER" null="true"/>
+ <column name="index" type="INTEGER" null="true"/>
+ <column name="path" type="TEXT" null="true"/>
+ <column name="content" type="TEXT" null="true"/>
+ <foreign-key name="object_id_fk" on-delete="CASCADE">
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <column name="version_iteration"/>
+ <references table="main.available_package">
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <column name="version_iteration"/>
+ </references>
+ </foreign-key>
+ <index name="available_package_buildfiles_object_id_i">
+ <column name="name"/>
+ <column name="version_epoch"/>
+ <column name="version_canonical_upstream"/>
+ <column name="version_canonical_release"/>
+ <column name="version_revision"/>
+ <column name="version_iteration"/>
+ </index>
+ <index name="available_package_buildfiles_index_i">
+ <column name="index"/>
+ </index>
+ </add-table>
+ </changeset>
+
<changeset version="19">
<alter-table name="main.selected_package_prerequisites">
<add-column name="config_dependency_index" type="INTEGER" null="true" default="0"/>
diff --git a/bpkg/pkg-checkout.cxx b/bpkg/pkg-checkout.cxx
index 6c6dcf8..2a3f508 100644
--- a/bpkg/pkg-checkout.cxx
+++ b/bpkg/pkg-checkout.cxx
@@ -319,12 +319,15 @@ namespace bpkg
// Calculate the buildfiles checksum if the package has any buildfile
// clauses in the dependencies.
//
+ // Note that the available package already has all the buildfiles
+ // loaded.
+ //
if ((p != nullptr && p->manifest_checksum == mc)
? p->buildfiles_checksum.has_value ()
: has_buildfile_clause (ap->dependencies))
bc = package_buildfiles_checksum (ap->bootstrap_build,
ap->root_build,
- d);
+ ap->buildfiles);
}
if (p != nullptr)
diff --git a/bpkg/pkg-unpack.cxx b/bpkg/pkg-unpack.cxx
index b38a750..2e21c70 100644
--- a/bpkg/pkg-unpack.cxx
+++ b/bpkg/pkg-unpack.cxx
@@ -175,6 +175,7 @@ namespace bpkg
: has_buildfile_clause (deps))
bc = package_buildfiles_checksum (nullopt /* bootstrap_build */,
nullopt /* root_build */,
+ {} /* buildfiles */,
d);
}
@@ -414,10 +415,13 @@ namespace bpkg
if (ap != nullptr)
{
+ // Note that the available package already has all the buildfiles
+ // loaded.
+ //
if (has_buildfile_clause (ap->dependencies))
bc = package_buildfiles_checksum (ap->bootstrap_build,
ap->root_build,
- d);
+ ap->buildfiles);
}
else
{
@@ -435,7 +439,9 @@ namespace bpkg
if (has_buildfile_clause (m.dependencies))
bc = package_buildfiles_checksum (m.bootstrap_build,
m.root_build,
- d);
+ m.buildfiles,
+ d,
+ m.alt_naming);
}
}
diff --git a/bpkg/pkg-verify.cxx b/bpkg/pkg-verify.cxx
index b0dbf65..229b73d 100644
--- a/bpkg/pkg-verify.cxx
+++ b/bpkg/pkg-verify.cxx
@@ -226,12 +226,13 @@ namespace bpkg
iu);
}
- // Extract the bootstrap/root buildfiles into the respective *-build
- // values, if requested and are not already specified in the manifest.
+ // Extract the bootstrap, root, and config/*.build buildfiles into the
+ // respective *-build values, if requested and are not already
+ // specified in the manifest.
//
// Note that we don't verify that the files are not empty.
//
- if (lb && (!m.bootstrap_build || !m.root_build))
+ if (lb)
{
paths ps (archive_contents (co, af, diag_level != 0));
@@ -240,14 +241,80 @@ namespace bpkg
return find (ps.begin (), ps.end (), p) != ps.end ();
};
- auto extract_buildfiles = [&m, &co, &af, diag_level, &contains]
- (const path& b, const path& r)
+ auto extract_buildfiles = [&m, &co, &af, &ps, diag_level, &contains]
+ (const path& b,
+ const path& r,
+ const dir_path& c,
+ const string& ext)
{
if (!m.bootstrap_build)
m.bootstrap_build = extract (co, af, b, diag_level != 0);
if (!m.root_build && contains (r))
m.root_build = extract (co, af, r, diag_level != 0);
+
+ // Extract build/config/*.build files.
+ //
+ if (m.root_build)
+ {
+ vector<buildfile>& bs (m.buildfiles);
+ size_t n (bs.size ());
+
+ for (const path& ap: ps)
+ {
+ if (!ap.to_directory () && ap.sub (c))
+ {
+ path p (ap.leaf (c));
+ const char* e (p.extension_cstring ());
+
+ // Only consider immediate sub-entries of the config/
+ // subdirectory.
+ //
+ if (e != nullptr && ext == e && p.simple ())
+ {
+ path f (c.leaf () / p.base ()); // Relative to build/.
+
+ if (find_if (bs.begin (), bs.end (),
+ [&f] (const auto& v) {return v.path == f;}) ==
+ bs.end ())
+ {
+ bs.emplace_back (move (f),
+ extract (co, af, ap, diag_level != 0));
+ }
+ }
+ }
+ }
+
+ // To produce a stable result sort the appended *-build values.
+ //
+ if (bs.size () != n)
+ {
+ sort (bs.begin () + n, bs.end (),
+ [] (const auto& x, const auto& y)
+ {
+ return x.path < y.path;
+ });
+ }
+ }
+ };
+
+ // Set the manifest's alt_naming flag to the deduced value if absent
+ // and verify that it matches otherwise.
+ //
+ auto alt_naming = [&m, diag_level, &af] (bool v)
+ {
+ if (!m.alt_naming)
+ {
+ m.alt_naming = v;
+ }
+ else if (*m.alt_naming != v)
+ {
+ if (diag_level != 0)
+ error << "buildfile naming scheme mismatch between manifest "
+ << "and package archive " << af;
+
+ throw failed ();
+ }
};
// Check the alternative bootstrap file first since it is more
@@ -256,11 +323,21 @@ namespace bpkg
path bf;
if (contains (bf = pd / alt_bootstrap_file))
{
- extract_buildfiles (bf, pd / alt_root_file);
+ alt_naming (true);
+
+ extract_buildfiles (bf,
+ pd / alt_root_file,
+ pd / alt_config_dir,
+ alt_build_ext);
}
else if (contains (bf = pd / std_bootstrap_file))
{
- extract_buildfiles (bf, pd / std_root_file);
+ alt_naming (false);
+
+ extract_buildfiles (bf,
+ pd / std_root_file,
+ pd / std_config_dir,
+ std_build_ext);
}
else
{
@@ -354,61 +431,23 @@ namespace bpkg
tf,
iu);
- // Load the bootstrap/root buildfiles into the respective *-build
- // values, if requested and if they are not already specified in the
- // manifest.
+ // Load the bootstrap, root, and config/*.build buildfiles into the
+ // respective *-build values, if requested and if they are not already
+ // specified in the manifest.
//
// Note that we don't verify that the files are not empty.
//
- if (lb && (!m.bootstrap_build || !m.root_build))
+ if (lb)
+ try
{
- auto load_buildfiles = [&m, diag_level] (const path& b, const path& r)
- {
- auto load = [diag_level] (const path& f)
- {
- try
- {
- ifdstream ifs (f);
- string r (ifs.read_text ());
- ifs.close ();
- return r;
- }
- catch (const io_error& e)
- {
- if (diag_level != 0)
- error << "unable to read from " << f << ": " << e;
-
- throw failed ();
- }
- };
-
- if (!m.bootstrap_build)
- m.bootstrap_build = load (b);
-
- if (!m.root_build && exists (r))
- m.root_build = load (r);
- };
-
- // Check the alternative bootstrap file first since it is more
- // specific.
- //
- path bf;
- if (exists (bf = d / alt_bootstrap_file))
- {
- load_buildfiles (bf, d / alt_root_file);
- }
- else if (exists (bf = d / std_bootstrap_file))
- {
- load_buildfiles (bf, d / std_root_file);
- }
- else
- {
- if (diag_level != 0)
- error << "unable to find bootstrap.build file in package "
- << "directory " << d;
+ load_package_buildfiles (m, d);
+ }
+ catch (const runtime_error& e)
+ {
+ if (diag_level != 0)
+ error << e;
- throw failed ();
- }
+ throw failed ();
}
// We used to verify package directory is <name>-<version> but it is
diff --git a/bpkg/pkg-verify.hxx b/bpkg/pkg-verify.hxx
index 8c0b555..b4b536b 100644
--- a/bpkg/pkg-verify.hxx
+++ b/bpkg/pkg-verify.hxx
@@ -22,8 +22,9 @@ namespace bpkg
// expand the file-referencing manifest values (description, changes, etc),
// setting them to the contents of files they refer to, set the potentially
// absent description-type value to the effective description type (see
- // libbpkg/manifest.hxx), load the bootstrap and root buildfiles into the
- // respective *-build values, and complete the dependency constraints.
+ // libbpkg/manifest.hxx), load the bootstrap, root, and config/*.build
+ // buildfiles into the respective *-build values, and complete the
+ // dependency constraints.
//
// Throw not_package (derived from failed) if this doesn't look like a
// package. Throw plain failed if this does looks like a package but
diff --git a/bpkg/rep-fetch.cxx b/bpkg/rep-fetch.cxx
index e9cacd0..038d54e 100644
--- a/bpkg/rep-fetch.cxx
+++ b/bpkg/rep-fetch.cxx
@@ -323,67 +323,21 @@ namespace bpkg
//
m.location = move (*pm.location);
- // Load the bootstrap/root buildfiles into the respective *-build
- // values, if requested and if they are not already specified in the
- // manifest.
+ // Load the bootstrap, root, and config/*.build buildfiles into the
+ // respective *-build values, if requested and if they are not already
+ // specified in the manifest.
//
- if (lb && (!m.bootstrap_build || !m.root_build))
+ if (lb)
+ try
{
- const dir_path& d (pds[i]);
-
- // Note that the paths relative to the package directory (last two
- // arguments) are used for diagnostics only.
- //
- auto load_buildfiles = [&m, &add_package_info] (const path& bf,
- const path& rf,
- const path& bfr,
- const path& rfr)
- {
- auto load = [&m, &add_package_info] (const path& f, const path& fr)
- {
- try
- {
- ifdstream ifs (f);
- string r (ifs.read_text ());
- ifs.close ();
- return r;
- }
- catch (const io_error& e)
- {
- diag_record dr (fail);
- dr << "unable to read from " << fr << ": " << e;
- add_package_info (m, dr);
- dr << endf;
- }
- };
-
- if (!m.bootstrap_build)
- m.bootstrap_build = load (bf, bfr);
-
- if (!m.root_build && exists (rf))
- m.root_build = load (rf, rfr);
- };
-
- // Check the alternative bootstrap file first since it is more
- // specific.
- //
- path bf;
- if (exists (bf = d / alt_bootstrap_file))
- {
- load_buildfiles (bf, d / alt_root_file,
- alt_bootstrap_file, alt_root_file);
- }
- else if (exists (bf = d / std_bootstrap_file))
- {
- load_buildfiles (bf, d / std_root_file,
- std_bootstrap_file, std_root_file);
- }
- else
- {
- diag_record dr (fail);
- dr << "unable to find bootstrap.build file";
- add_package_info (m, dr);
- }
+ load_package_buildfiles (m, pds[i], true /* err_path_relative */);
+ }
+ catch (const runtime_error& e)
+ {
+ diag_record dr (fail);
+ dr << e << info;
+ add_package_info (m, dr);
+ dr << endf;
}
pm = move (m);
diff --git a/bpkg/rep-fetch.hxx b/bpkg/rep-fetch.hxx
index b9d458f..7e03999 100644
--- a/bpkg/rep-fetch.hxx
+++ b/bpkg/rep-fetch.hxx
@@ -54,9 +54,9 @@ namespace bpkg
// (description, changes, etc), setting them to the contents of files they
// refer to and set the potentially absent description-type value to the
// effective description type (see libbpkg/manifest.hxx) and load the
- // bootstrap and root buildfiles into the respective *-build values. Note
- // that for pkg repositories such values are expanded/loaded at the
- // repository creation time.
+ // bootstrap, root, and config/*.build buildfiles into the respective *-build
+ // values. Note that for pkg repositories such values are expanded/loaded at
+ // the repository creation time.
//
rep_fetch_data
rep_fetch (const common_options&,
diff --git a/bpkg/utility.cxx b/bpkg/utility.cxx
index d229205..68d79ad 100644
--- a/bpkg/utility.cxx
+++ b/bpkg/utility.cxx
@@ -26,13 +26,23 @@ namespace bpkg
const dir_path certs_dir (dir_path (bpkg_dir) /= "certs");
const dir_path repos_dir (dir_path (bpkg_dir) /= "repos");
+ // Standard and alternative build file/directory naming schemes.
+ //
+ // build:
+ //
const dir_path std_build_dir ("build");
+ const dir_path std_config_dir (dir_path (std_build_dir) /= "config");
const path std_bootstrap_file (dir_path (std_build_dir) /= "bootstrap.build");
const path std_root_file (dir_path (std_build_dir) /= "root.build");
+ const string std_build_ext ("build");
+ // build2:
+ //
const dir_path alt_build_dir ("build2");
+ const dir_path alt_config_dir (dir_path (alt_build_dir) /= "config");
const path alt_bootstrap_file (dir_path (alt_build_dir) /= "bootstrap.build2");
const path alt_root_file (dir_path (alt_build_dir) /= "root.build2");
+ const string alt_build_ext ("build2");
const dir_path current_dir (".");
diff --git a/bpkg/utility.hxx b/bpkg/utility.hxx
index 597800c..342d608 100644
--- a/bpkg/utility.hxx
+++ b/bpkg/utility.hxx
@@ -86,12 +86,16 @@ namespace bpkg
extern const dir_path repos_dir; // .bpkg/repos/
extern const dir_path std_build_dir; // build/
+ extern const dir_path std_config_dir; // build/config/
extern const path std_bootstrap_file; // build/bootstrap.build
extern const path std_root_file; // build/root.build
+ extern const string std_build_ext; // build
extern const dir_path alt_build_dir; // build2/
+ extern const dir_path alt_config_dir; // build2/config/
extern const path alt_bootstrap_file; // build2/bootstrap.build2
extern const path alt_root_file; // build2/root.build2
+ extern const string alt_build_ext; // build2
extern const dir_path current_dir; // ./
diff --git a/doc/manual.cli b/doc/manual.cli
index b00430a..ec0a535 100644
--- a/doc/manual.cli
+++ b/doc/manual.cli
@@ -623,6 +623,11 @@ license: <licenses> [; <comment>]
[bootstrap-build]: <text>
[root-build]: <text>
+[*-build]: <text>
+
+[bootstrap-build2]: <text>
+[root-build2]: <text>
+[*-build2]: <text>
\
\h2#manifest-package-name|\c{name}|
@@ -1437,17 +1442,51 @@ Note that the comment of the matching exclusion is used by the web interface
(\c{brep}) to display the reason for the build configuration exclusion.
-\h2#manifest-package-bootstrap-root-build|\c{{bootstrap,root\}-build}|
+\h2#manifest-package-x-build|\c{{bootstrap,root,*\}-build[2]}|
\
[bootstrap-build]: <text>
[root-build]: <text>
+[*-build]: <text>
+
+[bootstrap-build2]: <text>
+[root-build2]: <text>
+[*-build2]: <text>
+\
+
+The contents of the mandatory \c{bootstrap.build} file, optional
+\c{root.build} file, and additional files included by \c{root.build}, or their
+alternative naming scheme variants (\c{bootstrap.build2}, etc). Packages with
+the alternative naming scheme should use the \c{*-build2} values instead of
+\c{*-build}.
+
+These files must reside in the package's \c{build/} subdirectory and have the
+\c{.build} extension (or their alternative names). The respective manifest
+value name prefix must be the file path relative to this subdirectory with the
+extension stripped.
+
+As an example, the following value corresponds to the
+\c{build/config/common.build} file:
+
+\
+config/common-build:\
+config [bool] config.libhello.fancy ?= false
+\\
+\
+
+And the following value corresponds to the \c{build2/config/common.build2}
+file in a package with the alternative naming scheme:
+
+\
+config/common-build2:\
+config [bool] config.libhello.fancy ?= false
+\\
\
-The contents of the mandatory \c{bootstrap.build} and optional \c{root.build}
-files in the package's \c{build/} (or their alternative names) subdirectory.
-If unspecified, then they will be automatically added, for example, when the
-\l{#manifest-package-list-pkg package list manifest} is created.
+If unspecified, then the package's \c{bootstrap.build}, \c{root.build}, and
+\c{build/config/*.build} files (or their alternative names) will be
+automatically added, for example, when the \l{#manifest-package-list-pkg
+package list manifest} is created.
\h#manifest-package-list-pkg|Package List Manifest for \cb{pkg} Repositories|
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
index 7c5a840..aacf8d7 100644
--- a/tests/common/dependency-alternatives/t11a/libbar-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t11a/libbar-1.0.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
index 52ba91b..da545c1 100644
--- a/tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gz
+++ b/tests/common/dependency-alternatives/t11a/libfoo-1.0.0.tar.gz
Binary files differ
diff --git a/tests/pkg-build.testscript b/tests/pkg-build.testscript
index 86a63f1..bf39949 100644
--- a/tests/pkg-build.testscript
+++ b/tests/pkg-build.testscript
@@ -4932,7 +4932,7 @@ test.options += --no-progress
}
}
- : configuration-negotiation-order
+ : config-negotiation-order
:
{
+$clone_root_cfg && $rep_add $rep/t11a && $rep_fetch
@@ -5520,7 +5520,7 @@ test.options += --no-progress
$pkg_drop foo libfoo
}
- : dependent-single-position
+ : dependent-single-pos
:
{
+$clone_cfg
@@ -5831,7 +5831,7 @@ test.options += --no-progress
}
}
- : dependent-multiple-positions
+ : dependent-mult-pos
:
{
+$clone_cfg
@@ -6151,7 +6151,7 @@ test.options += --no-progress
$pkg_drop tex baz
}
- : replace-re-evaluation
+ : replace-reeval
:
{
+$clone_cfg
@@ -11272,7 +11272,7 @@ test.options += --no-progress
}
}
- : configuration-negotiation
+ : config-negotiation
:
{
test.arguments += --yes --plan 'build plan:'