aboutsummaryrefslogtreecommitdiff
path: root/bbot
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2023-03-24 20:32:25 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2023-04-03 16:52:41 +0300
commit8c54405d78b87b8756106eceec0a53ef0225d05e (patch)
tree3e94822ac2234814190297e571e41ac90615a51a /bbot
parent2cdf8357b2eb3ddaf726c2cd51bff524e8faa3d6 (diff)
Add support for package build config worker steps and steps enabling/disabling
Diffstat (limited to 'bbot')
-rw-r--r--bbot/worker/worker.cxx2527
1 files changed, 1482 insertions, 1045 deletions
diff --git a/bbot/worker/worker.cxx b/bbot/worker/worker.cxx
index 6c96b5b..f1e5e8c 100644
--- a/bbot/worker/worker.cxx
+++ b/bbot/worker/worker.cxx
@@ -151,6 +151,9 @@ catch (const system_error& e)
// Step IDs.
//
+// NOTE: keep ids ordered according to the sequence of steps and remember to
+// update unreachable breakpoint checks if changing anything here.
+//
enum class step_id
{
// Common fallbacks for bpkg_*_create/b_test_installed_create and
@@ -302,6 +305,12 @@ static const strings step_id_str {
"end"};
+static inline const string&
+to_string (step_id s)
+{
+ return step_id_str[static_cast<size_t> (s)];
+}
+
using std::regex;
namespace regex_constants = std::regex_constants;
using regexes = vector<regex>;
@@ -390,7 +399,7 @@ run_cmd (step_id step,
auto prompt_step = [step, &t, &log, &bkp_step, &prompt] ()
{
- const string& sid (step_id_str[static_cast<size_t> (step)]);
+ const string& sid (to_string (step));
// Prompt the user if the breakpoint is reached.
//
@@ -789,7 +798,7 @@ upload_manifest (tracer& trace,
}
}
-static const string worker_checksum ("4"); // Logic version.
+static const string worker_checksum ("5"); // Logic version.
static int bbot::
build (size_t argc, const char* argv[])
@@ -915,53 +924,105 @@ build (size_t argc, const char* argv[])
}
// Split the argument into prefix (empty if not present) and unquoted
- // value. Return nullopt if the prefix is invalid.
+ // value (absent if not present) and determine the step status. If the
+ // prefix is present and is prepended with the '+'/'-' character, then the
+ // respective step needs to be enabled/disabled. Return nullopt if the
+ // prefix is invalid.
//
- auto parse_arg = [] (const string& a) -> optional<pair<string, string>>
+ // Note that arguments with absent values are normally used to
+ // enable/disable steps and are omitted from the command lines.
+ //
+ struct argument
+ {
+ string prefix;
+
+ // Absent if the argument value is an empty unquoted string.
+ //
+ optional<string> value;
+
+ // True - enable, false - disable, nullopt - neutral.
+ //
+ optional<bool> step_status;
+ };
+
+ auto parse_arg = [] (const string& a) -> optional<argument>
{
size_t p (a.find_first_of (":=\"'"));
+ auto value = [] (const string& v)
+ {
+ return !v.empty () ? unquote (v) : optional<string> ();
+ };
+
if (p == string::npos || a[p] != ':') // No prefix.
- return make_pair (string (), unquote (a));
+ return argument {string (), value (a), nullopt};
+
+ string prefix (a, 0, p);
+
+ optional<bool> enable;
+ if (prefix[0] == '+' || prefix[0] == '-')
+ {
+ enable = (prefix[0] == '+');
+
+ prefix.erase (0, 1);
+
+ if (prefix != "bpkg.update" &&
+ prefix != "bpkg.test" &&
+ prefix != "bpkg.test-separate.update" &&
+ prefix != "bpkg.test-separate.test" &&
+ prefix != "bpkg.install" &&
+ prefix != "b.test-installed.test" &&
+ prefix != "bpkg.test-separate-installed.update" &&
+ prefix != "bpkg.test-separate-installed.test")
+ {
+ return nullopt; // Prefix is invalid.
+ }
+ }
for (const string& id: step_id_str)
{
- if (a.compare (0, p, id, 0, p) == 0 &&
- (id.size () == p || (id.size () > p && id[p] == '.')))
- return make_pair (a.substr (0, p), unquote (a.substr (p + 1)));
+ size_t n (prefix.size ());
+ if (id.compare (0, n, prefix) == 0 &&
+ (id.size () == n || (id.size () > n && id[n] == '.')))
+ return argument {move (prefix), value (a.substr (p + 1)), enable};
}
return nullopt; // Prefix is invalid.
};
- // Parse configuration arguments. Report failures to the bbot controller.
+ // Keep track of explicitly enabled/disabled steps.
//
- std::multimap<string, string> tgt_args;
+ std::map<string, bool> step_statuses;
- for (const string& c: tm.target_config)
+ // Return true if the step is explicitly enabled via a +<prefix>:[<value>]
+ // environment/configuration argument.
+ //
+ // @@ TMP Use it for bpkg.bindist step.
+ //
+#if 0
+ auto step_enabled = [&step_statuses] (step_id step) -> bool
{
- optional<pair<string, string>> v (parse_arg (c));
-
- if (!v)
- {
- rm.status |= result_status::abort;
- l3 ([&]{trace << "invalid configuration argument prefix in "
- << "'" << c << "'";});
- break;
- }
-
- if (v->second[0] != '-' && v->second.find ('=') == string::npos)
- {
- rm.status |= result_status::abort;
- l3 ([&]{trace << "invalid configuration argument '" << c << "'";});
- break;
- }
+ auto i (step_statuses.find (to_string (step)));
+ return i != step_statuses.end () && i->second;
+ };
+#endif
- tgt_args.emplace (move (*v));
- }
+ // Return true if the step is explicitly disabled via a -<prefix>:[<value>]
+ // environment/configuration argument.
+ //
+ auto step_disabled = [&step_statuses] (step_id step) -> bool
+ {
+ auto i (step_statuses.find (to_string (step)));
+ return i != step_statuses.end () && !i->second;
+ };
- if (!rm.status)
- break;
+ // Parse the environment, target configuration, and build package
+ // configuration arguments.
+ //
+ // NOTE: keep this parsing order intact so that, for example, a build
+ // package configuration argument can override step status specified
+ // by a target configuration argument.
+ //
// Parse environment arguments.
//
@@ -971,147 +1032,73 @@ build (size_t argc, const char* argv[])
for (size_t i (1); i != argc; ++i)
{
const char* a (argv[i]);
- optional<pair<string, string>> v (parse_arg (a));
+ optional<argument> v (parse_arg (a));
if (!v)
fail << "invalid environment argument prefix in '" << a << "'";
- bool mod (v->second[0] != '-' && v->second.find ('=') == string::npos);
-
- if (mod && !v->first.empty () &&
- v->first != "b.create" &&
- v->first != "bpkg.create" &&
- v->first != "bpkg.target.create" &&
- v->first != "bpkg.host.create" &&
- v->first != "bpkg.module.create" &&
- v->first != "b.test-installed.create" &&
- v->first != "bpkg.test-separate-installed.create" &&
- v->first != "bpkg.test-separate-installed.create_for_target" &&
- v->first != "bpkg.test-separate-installed.create_for_host" &&
- v->first != "bpkg.test-separate-installed.create_for_module")
+ bool mod (v->value &&
+ (*v->value)[0] != '-' &&
+ v->value->find ('=') == string::npos);
+
+ if (mod &&
+ !v->prefix.empty () &&
+ v->prefix != "b.create" &&
+ v->prefix != "bpkg.create" &&
+ v->prefix != "bpkg.target.create" &&
+ v->prefix != "bpkg.host.create" &&
+ v->prefix != "bpkg.module.create" &&
+ v->prefix != "b.test-installed.create" &&
+ v->prefix != "bpkg.test-separate-installed.create" &&
+ v->prefix != "bpkg.test-separate-installed.create_for_target" &&
+ v->prefix != "bpkg.test-separate-installed.create_for_host" &&
+ v->prefix != "bpkg.test-separate-installed.create_for_module")
fail << "invalid module prefix in '" << a << "'";
- (mod ? modules : env_args).emplace (move (*v));
+ if (v->step_status)
+ step_statuses[v->prefix] = *v->step_status;
+
+ if (v->value)
+ (mod ? modules : env_args).emplace (make_pair (move (v->prefix),
+ move (*v->value)));
}
- // Return command arguments for the specified step id, complementing
- // *.create[_for_*] steps with un-prefixed arguments. If no arguments are
- // specified for the step then use the specified fallbacks, potentially
- // both. Arguments with more specific prefixes come last.
+ // Parse target configuration arguments. Report failures to the bbot
+ // controller.
//
- auto step_args = [] (const std::multimap<string, string>& args,
- step_id step,
- optional<step_id> fallback1 = nullopt,
- optional<step_id> fallback2 = nullopt) -> cstrings
- {
- cstrings r;
-
- // Add arguments for a specified, potentially empty, prefix.
- //
- auto add_args = [&args, &r] (const string& prefix)
- {
- auto range (args.equal_range (prefix));
+ std::multimap<string, string> tgt_args;
- for (auto i (range.first); i != range.second; ++i)
- r.emplace_back (i->second.c_str ());
- };
+ for (const string& c: tm.target_config)
+ {
+ optional<argument> v (parse_arg (c));
- // Add un-prefixed arguments if this is one of the *.create[_for_*]
- // steps.
- //
- switch (step)
+ if (!v)
{
- case step_id::b_create:
- case step_id::bpkg_create:
- case step_id::bpkg_target_create:
- case step_id::bpkg_host_create:
- case step_id::bpkg_module_create:
- case step_id::b_test_installed_create:
- case step_id::bpkg_test_separate_installed_create:
- case step_id::bpkg_test_separate_installed_create_for_target:
- case step_id::bpkg_test_separate_installed_create_for_host:
- case step_id::bpkg_test_separate_installed_create_for_module:
- {
- add_args ("");
- break;
- }
- default: break;
+ rm.status |= result_status::abort;
+ l3 ([&]{trace << "invalid target configuration argument prefix in "
+ << "'" << c << "'";});
+ break;
}
- auto add_step_args = [&add_args] (step_id step)
- {
- const string& s (step_id_str[static_cast<size_t> (step)]);
-
- for (size_t n (0);; ++n)
- {
- n = s.find ('.', n);
-
- add_args (n == string::npos ? s : string (s, 0, n));
-
- if (n == string::npos)
- break;
- }
- };
-
- // If no arguments found for the step id, then use the fallback step
- // ids, if specified.
- //
- if (args.find (step_id_str[static_cast<size_t> (step)]) != args.end ())
- {
- add_step_args (step);
- }
- else
+ if (v->value &&
+ (*v->value)[0] != '-' &&
+ v->value->find ('=') == string::npos)
{
- // Note that if we ever need to specify fallback pairs with common
- // ancestors, we may want to suppress duplicate ancestor step ids.
- //
- if (fallback1)
- add_step_args (*fallback1);
-
- if (fallback2)
- add_step_args (*fallback2);
+ rm.status |= result_status::abort;
+ l3 ([&]{trace << "invalid target configuration argument '" << c
+ << "'";});
+ break;
}
- return r;
- };
+ if (v->step_status)
+ step_statuses[v->prefix] = *v->step_status;
- // bpkg-rep-fetch trust options.
- //
- cstrings trust_ops;
- {
- const char* t ("--trust-no");
-
- for (const string& fp: tm.trust)
- {
- if (fp == "yes")
- t = "--trust-yes";
- else
- {
- trust_ops.push_back ("--trust");
- trust_ops.push_back (fp.c_str ());
- }
- }
-
- trust_ops.push_back (t);
+ if (v->value)
+ tgt_args.emplace (make_pair (move (v->prefix), move (*v->value)));
}
- const string& pkg (tm.name.string ());
- const version& ver (tm.version);
- const string repo (tm.repository.string ());
- const dir_path pkg_dir (pkg + '-' + ver.string ());
- const string pkg_var (tm.name.variable ());
-
- // Specify the revision explicitly for the bpkg-build command not to end
- // up with a race condition building the latest revision rather than the
- // zero revision.
- //
- const string pkg_rev (pkg +
- '/' +
- version (ver.epoch,
- ver.upstream,
- ver.release,
- ver.effective_revision (),
- ver.iteration).string ());
+ if (!rm.status)
+ break;
// Parse the build package configuration represented as a whitespace
// separated list of the following potentially quoted bpkg-pkg-build
@@ -1120,12 +1107,21 @@ build (size_t argc, const char* argv[])
// <option>... <config-var>... ({ <config-var>... }+ (?[sys:]|sys:)<pkg-name>[<version-spec>])...
//
// If the package configuration is specified, then parse it into the
- // options list, the main package-specific configuration variables list,
- // and the dependency packages list, potentially with their own
- // configuration variables (but not options).
+ // prefixed global options and configuration variables map, unprefixed
+ // global options list, the main package-specific configuration variables
+ // list, and the dependency packages list, potentially with their own
+ // configuration variables (but not options). The prefixed arguments are
+ // added to the command lines at the corresponding steps after potential
+ // environment and target configuration arguments. Unprefixed arguments
+ // are added to the bpkg-pkg-build command line at the
+ // bpkg.configure.build step. Specifically, the unprefixed global options
+ // are specified after all the prefixed global options and the unprefixed
+ // variables are specified for the main package only, wherever it is
+ // configured.
//
- strings pkg_config_opts;
- strings pkg_config_vars;
+ std::multimap<string, string> pkg_args;
+ strings pkg_config_opts;
+ strings pkg_config_vars;
vector<pair<string, strings>> pkg_config_deps;
if (!tm.package_config.empty ())
@@ -1148,13 +1144,47 @@ build (size_t argc, const char* argv[])
try
{
strings argsv (string_parser::parse_quoted (tm.package_config,
- true /* unquote */));
+ false /* unquote */));
cli::vector_scanner scanv (argsv);
cli::group_scanner args (scanv);
while (args.more ())
{
+ string a (args.next ());
+
+ // Unless the argument is an unquoted dependency (starts with `?` or
+ // `sys:`), first try to interpret it as a prefixed option/variable
+ // and/or step id status (enabled/disabled).
+ //
+ if (!(a[0] == '?' || a.compare (0, 4, "sys:") == 0))
+ {
+ optional<argument> v (parse_arg (a));
+
+ if (v && !v->prefix.empty ())
+ {
+ if (v->value &&
+ (*v->value)[0] != '-' &&
+ v->value->find ('=') == string::npos)
+ fail ("invalid prefixed argument '" + a + '\'');
+
+ if (args.group ().more ())
+ fail ("unexpected options group for prefixed argument '" + a +
+ '\'');
+
+ if (v->step_status)
+ step_statuses[v->prefix] = *v->step_status;
+
+ if (v->value)
+ pkg_args.emplace (make_pair (move (v->prefix),
+ move (*v->value)));
+
+ continue;
+ }
+ }
+
+ a = unquote (a);
+
// Return true if the argument is an option.
//
// Note that options with values can only be specified using
@@ -1180,7 +1210,6 @@ build (size_t argc, const char* argv[])
a.find ('=') != string::npos;
};
- string a (args.next ());
bool o (opt (a));
bool v (var (a));
@@ -1214,7 +1243,7 @@ build (size_t argc, const char* argv[])
strings vars;
while (ag.more ())
{
- string da (ag.next ());
+ string da (unquote (ag.next ()));
if (!var (da))
fail ("argument is not a configuration variable for "
"dependency " + a + ": '" + da + '\'');
@@ -1241,6 +1270,125 @@ build (size_t argc, const char* argv[])
}
}
+ // Return command arguments for the specified step id, complementing
+ // *.create[_for_*] steps with un-prefixed arguments. If no arguments are
+ // specified for the step then use the specified fallbacks, potentially
+ // both. Arguments with more specific prefixes come last.
+ //
+ auto step_args = [] (const std::multimap<string, string>& args,
+ step_id step,
+ optional<step_id> fallback1 = nullopt,
+ optional<step_id> fallback2 = nullopt) -> cstrings
+ {
+ cstrings r;
+
+ // Add arguments for a specified, potentially empty, prefix.
+ //
+ auto add_args = [&args, &r] (const string& prefix)
+ {
+ auto range (args.equal_range (prefix));
+
+ for (auto i (range.first); i != range.second; ++i)
+ r.emplace_back (i->second.c_str ());
+ };
+
+ // Add un-prefixed arguments if this is one of the *.create[_for_*]
+ // steps.
+ //
+ switch (step)
+ {
+ case step_id::b_create:
+ case step_id::bpkg_create:
+ case step_id::bpkg_target_create:
+ case step_id::bpkg_host_create:
+ case step_id::bpkg_module_create:
+ case step_id::b_test_installed_create:
+ case step_id::bpkg_test_separate_installed_create:
+ case step_id::bpkg_test_separate_installed_create_for_target:
+ case step_id::bpkg_test_separate_installed_create_for_host:
+ case step_id::bpkg_test_separate_installed_create_for_module:
+ {
+ add_args ("");
+ break;
+ }
+ default: break;
+ }
+
+ auto add_step_args = [&add_args] (step_id step)
+ {
+ const string& s (to_string (step));
+
+ for (size_t n (0);; ++n)
+ {
+ n = s.find ('.', n);
+
+ add_args (n == string::npos ? s : string (s, 0, n));
+
+ if (n == string::npos)
+ break;
+ }
+ };
+
+ // If no arguments found for the step id, then use the fallback step
+ // ids, if specified.
+ //
+ if (args.find (to_string (step)) != args.end ())
+ {
+ add_step_args (step);
+ }
+ else
+ {
+ // Note that if we ever need to specify fallback pairs with common
+ // ancestors, we may want to suppress duplicate ancestor step ids.
+ //
+ if (fallback1)
+ add_step_args (*fallback1);
+
+ if (fallback2)
+ add_step_args (*fallback2);
+ }
+
+ return r;
+ };
+
+ // bpkg-rep-fetch trust options.
+ //
+ cstrings trust_ops;
+ {
+ const char* t ("--trust-no");
+
+ for (const string& fp: tm.trust)
+ {
+ if (fp == "yes")
+ t = "--trust-yes";
+ else
+ {
+ trust_ops.push_back ("--trust");
+ trust_ops.push_back (fp.c_str ());
+ }
+ }
+
+ trust_ops.push_back (t);
+ }
+
+ const string& pkg (tm.name.string ());
+ const version& ver (tm.version);
+ const string repo (tm.repository.string ());
+ const dir_path pkg_dir (pkg + '-' + ver.string ());
+ const string pkg_var (tm.name.variable ());
+
+ // Specify the revision explicitly for the bpkg-build command not to end
+ // up with a race condition building the latest revision rather than the
+ // zero revision.
+ //
+ const string pkg_rev (pkg +
+ '/' +
+ version (ver.epoch,
+ ver.upstream,
+ ver.release,
+ ver.effective_revision (),
+ ver.iteration).string ());
+
// Query the project's build system information with `b info`.
//
auto prj_info = [&trace] (const dir_path& d,
@@ -1588,7 +1736,9 @@ build (size_t argc, const char* argv[])
//
// Create the target configuration.
//
- // bpkg create <env-modules> <env-config-args> <tgt-config-args>
+ // bpkg create <env-modules> <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
//
if (create_target)
{
@@ -1607,7 +1757,8 @@ build (size_t argc, const char* argv[])
!target_pkg ? cstrings ({"--uuid", target_uuid}) : cstrings (),
step_args (modules, s, f1, f2),
step_args (env_args, s, f1, f2),
- step_args (tgt_args, s, f1, f2));
+ step_args (tgt_args, s, f1, f2),
+ step_args (pkg_args, s, f1, f2));
if (!r.status)
break;
@@ -1628,7 +1779,9 @@ build (size_t argc, const char* argv[])
step_id f1 (step_id::b_create);
step_id f2 (step_id::bpkg_create);
- // bpkg create --type host <env-modules> <env-config-args> <tgt-config-args>
+ // bpkg create --type host <env-modules> <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
//
r.status |= run_bpkg (
b,
@@ -1641,7 +1794,8 @@ build (size_t argc, const char* argv[])
"--uuid", host_uuid,
step_args (modules, s, f1, f2),
step_args (env_args, s, f1, f2),
- step_args (tgt_args, s, f1, f2));
+ step_args (tgt_args, s, f1, f2),
+ step_args (pkg_args, s, f1, f2));
if (!r.status)
break;
@@ -1649,7 +1803,9 @@ build (size_t argc, const char* argv[])
// Create the install configuration.
//
- // bpkg create <env-modules> <env-config-args> <tgt-config-args>
+ // bpkg create <env-modules> <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
//
if (create_install)
{
@@ -1667,7 +1823,8 @@ build (size_t argc, const char* argv[])
"--uuid", install_uuid,
step_args (modules, s, f1, f2),
step_args (env_args, s, f1, f2),
- step_args (tgt_args, s, f1, f2));
+ step_args (tgt_args, s, f1, f2),
+ step_args (pkg_args, s, f1, f2));
if (!r.status)
break;
@@ -1718,7 +1875,9 @@ build (size_t argc, const char* argv[])
// Create the module configuration.
//
{
- // b create(<dir>) config.config.load=~build2 [<env-config-args> <tgt-config-args>]
+ // b create(<dir>) config.config.load=~build2 [<env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>]
//
// Note also that we suppress warnings about unused config.* values.
//
@@ -1731,6 +1890,7 @@ build (size_t argc, const char* argv[])
string mods;
cstrings eas;
cstrings cas;
+ cstrings pas;
if (module_pkg && selfhost)
{
@@ -1746,6 +1906,7 @@ build (size_t argc, const char* argv[])
eas = step_args (env_args, s);
cas = step_args (tgt_args, s);
+ pas = step_args (pkg_args, s);
}
else
mods = "cc";
@@ -1759,7 +1920,8 @@ build (size_t argc, const char* argv[])
"config.config.load=~build2",
"config.config.persist+='config.*'@unused=drop",
eas,
- cas);
+ cas,
+ pas);
if (!r.status)
break;
@@ -1796,7 +1958,9 @@ build (size_t argc, const char* argv[])
mods += m;
}
- // b create(<dir>) config.config.load=~build2 [<env-config-args> <tgt-config-args>]
+ // b create(<dir>) config.config.load=~build2 [<env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>]
//
r.status |= run_b (
b,
@@ -1807,7 +1971,8 @@ build (size_t argc, const char* argv[])
"config.config.load=~build2",
"config.config.persist+='config.*'@unused=drop",
step_args (env_args, s),
- step_args (tgt_args, s));
+ step_args (tgt_args, s),
+ step_args (pkg_args, s));
if (!r.status)
break;
@@ -1926,7 +2091,8 @@ build (size_t argc, const char* argv[])
// configuration for external build-time tests, if any, and the install
// configuration, if present.
//
- // bpkg add <env-config-args> <tgt-config-args> <repository-url>
+ // bpkg add <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <repository-url>
//
{
step_id b (step_id::bpkg_configure_add);
@@ -1941,13 +2107,15 @@ build (size_t argc, const char* argv[])
"-d", main_pkg_conf,
step_args (env_args, s),
step_args (tgt_args, s),
+ step_args (pkg_args, s),
repo);
if (!r.status)
break;
}
- // bpkg fetch <env-config-args> <tgt-config-args> <trust-options>
+ // bpkg fetch <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <trust-options>
//
{
step_id b (step_id::bpkg_configure_fetch);
@@ -1962,6 +2130,7 @@ build (size_t argc, const char* argv[])
"-d", main_pkg_conf,
step_args (env_args, s),
step_args (tgt_args, s),
+ step_args (pkg_args, s),
trust_ops);
if (!r.status)
@@ -1970,7 +2139,8 @@ build (size_t argc, const char* argv[])
if (create_install)
{
- // bpkg add <env-config-args> <tgt-config-args> <repository-url>
+ // bpkg add <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <repository-url>
//
{
step_id b (step_id::bpkg_configure_add);
@@ -1985,13 +2155,15 @@ build (size_t argc, const char* argv[])
"-d", install_conf,
step_args (env_args, s),
step_args (tgt_args, s),
+ step_args (pkg_args, s),
repo);
if (!r.status)
break;
}
- // bpkg fetch <env-config-args> <tgt-config-args> <trust-options>
+ // bpkg fetch <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <trust-options>
//
{
step_id b (step_id::bpkg_configure_fetch);
@@ -2006,6 +2178,7 @@ build (size_t argc, const char* argv[])
"-d", install_conf,
step_args (env_args, s),
step_args (tgt_args, s),
+ step_args (pkg_args, s),
trust_ops);
if (!r.status)
@@ -2015,7 +2188,8 @@ build (size_t argc, const char* argv[])
if (has_buildtime_tests)
{
- // bpkg add <env-config-args> <tgt-config-args> <repository-url>
+ // bpkg add <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <repository-url>
//
{
step_id b (step_id::bpkg_configure_add);
@@ -2030,13 +2204,15 @@ build (size_t argc, const char* argv[])
"-d", target_conf,
step_args (env_args, s),
step_args (tgt_args, s),
+ step_args (pkg_args, s),
repo);
if (!r.status)
break;
}
- // bpkg fetch <env-config-args> <tgt-config-args> <trust-options>
+ // bpkg fetch <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <trust-options>
//
{
step_id b (step_id::bpkg_configure_fetch);
@@ -2051,6 +2227,7 @@ build (size_t argc, const char* argv[])
"-d", target_conf,
step_args (env_args, s),
step_args (tgt_args, s),
+ step_args (pkg_args, s),
trust_ops);
if (!r.status)
@@ -2086,13 +2263,17 @@ build (size_t argc, const char* argv[])
// it simple for now.
//
strings common_args;
- strings pkg_args;
+ strings pkgs;
if (target_pkg) // The simple common case (see above)?
{
// The overall command looks like this (but some parts may be omitted):
//
- // bpkg build --configure-only <pkg-config-opts> <env-config-args> <tgt-config-args> --
+ // bpkg build --configure-only <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ // <pkg-config-opts>
+ // --
// { <pkg-config-vars>|config.<pkg-name>.develop=false }+ <pkg>
// { config.<runtime-test-name>.develop=false }+ <runtime-test>...
// { <dep-config-vars> }+ <dep>...
@@ -2104,16 +2285,18 @@ build (size_t argc, const char* argv[])
cstrings eas (step_args (env_args, s, f1, f2));
cstrings cas (step_args (tgt_args, s, f1, f2));
+ cstrings pas (step_args (pkg_args, s, f1, f2));
common_args.push_back ("--checkout-root");
common_args.push_back (dist_root.string ());
common_args.insert (common_args.end (), eas.begin (), eas.end ());
common_args.insert (common_args.end (), cas.begin (), cas.end ());
+ common_args.insert (common_args.end (), pas.begin (), pas.end ());
// Add the main package.
//
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
// @@ config.<pkg>.develop=false
//
@@ -2121,16 +2304,16 @@ build (size_t argc, const char* argv[])
// configuration variables specified.
//
if (!pkg_config_vars.empty ())
- pkg_args.insert (pkg_args.end (),
- pkg_config_vars.begin (), pkg_config_vars.end ());
+ pkgs.insert (pkgs.end (),
+ pkg_config_vars.begin (), pkg_config_vars.end ());
#if 1
else
- pkg_args.push_back ("config." + pkg_var + ".develop=false");
+ pkgs.push_back ("config." + pkg_var + ".develop=false");
#endif
- pkg_args.push_back ("}+");
+ pkgs.push_back ("}+");
- pkg_args.push_back (pkg_rev);
+ pkgs.push_back (pkg_rev);
// Add the runtime test packages.
//
@@ -2139,17 +2322,15 @@ build (size_t argc, const char* argv[])
// @@ config.<pkg>.develop=false
//
#if 1
- pkg_args.push_back ("{");
- pkg_args.push_back ("config." +
- t.name.variable () +
- ".develop=false");
- pkg_args.push_back ("}+");
+ pkgs.push_back ("{");
+ pkgs.push_back ("config." + t.name.variable () + ".develop=false");
+ pkgs.push_back ("}+");
#endif
// Add test dependency package constraints (for example
// 'bar > 1.0.0').
//
- pkg_args.push_back (t.string ());
+ pkgs.push_back (t.string ());
}
// Add the main package dependencies.
@@ -2158,25 +2339,45 @@ build (size_t argc, const char* argv[])
{
if (!d.second.empty ())
{
- pkg_args.push_back ("{");
- pkg_args.insert (pkg_args.end (), d.second.begin (), d.second.end ());
- pkg_args.push_back ("}+");
+ pkgs.push_back ("{");
+ pkgs.insert (pkgs.end (), d.second.begin (), d.second.end ());
+ pkgs.push_back ("}+");
}
- pkg_args.push_back (d.first);
+ pkgs.push_back (d.first);
}
}
else
{
// The overall command looks like this (but some parts may be omitted):
//
- // bpkg build --configure-only <pkg-config-opts> <env-config-args> <tgt-config-args> --
- // { <build-config> <env-config-args> <tgt-config-args> <pkg-config-vars>|config.<pkg-name>.develop=false }+ <pkg>
- // { <build-config> <env-config-args> <tgt-config-args> config.<runtime-test-name>.develop=false }+ <runtime-test>...
- // { <install-config> <env-config-args> <tgt-config-args> <pkg-config-vars> }+ <pkg>
- // { <target-config> <env-config-args> <tgt-config-args> config.<buildtime-test-name>.develop=false }+ <buildtime-test>...
- // { <build-config> <install-config> <dep-config-vars> }+ <dep>...
- // { <build-config> <install-config> }+ { <dep>... }
+ // bpkg build --configure-only <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ // <pkg-config-opts>
+ // --
+ // { <build-config> <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ // <pkg-config-vars>|config.<pkg-name>.develop=false }+ <pkg>
+ //
+ // { <build-config> <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ // config.<runtime-test-name>.develop=false }+ <runtime-test>...
+ //
+ // { <install-config> <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ // <pkg-config-vars> }+ <pkg>
+ //
+ // { <target-config> <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ // config.<buildtime-test-name>.develop=false }+ <buildtime-test>...
+ //
+ // { <build-config> <install-config> <dep-config-vars> }+ <dep>...
+ // { <build-config> <install-config> }+ { <dep>... }
//
// Main package configuration name.
@@ -2198,20 +2399,22 @@ build (size_t argc, const char* argv[])
cstrings eas (step_args (env_args, s, f1, f2));
cstrings cas (step_args (tgt_args, s, f1, f2));
+ cstrings pas (step_args (pkg_args, s, f1, f2));
// Add the main package.
//
{
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (conf_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (conf_uuid);
- pkg_args.push_back ("--checkout-root");
- pkg_args.push_back (dist_root.string ());
+ pkgs.push_back ("--checkout-root");
+ pkgs.push_back (dist_root.string ());
- pkg_args.insert (pkg_args.end (), eas.begin (), eas.end ());
- pkg_args.insert (pkg_args.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), eas.begin (), eas.end ());
+ pkgs.insert (pkgs.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), pas.begin (), pas.end ());
// @@ config.<pkg>.develop=false
//
@@ -2219,16 +2422,16 @@ build (size_t argc, const char* argv[])
// package configuration variables specified.
//
if (!pkg_config_vars.empty ())
- pkg_args.insert (pkg_args.end (),
- pkg_config_vars.begin (), pkg_config_vars.end ());
+ pkgs.insert (pkgs.end (),
+ pkg_config_vars.begin (), pkg_config_vars.end ());
#if 1
else
- pkg_args.push_back ("config." + pkg_var + ".develop=false");
+ pkgs.push_back ("config." + pkg_var + ".develop=false");
#endif
- pkg_args.push_back ("}+");
+ pkgs.push_back ("}+");
- pkg_args.push_back (pkg_rev);
+ pkgs.push_back (pkg_rev);
}
// Add the runtime test packages.
@@ -2238,58 +2441,58 @@ build (size_t argc, const char* argv[])
#if 1
for (const auto& t: runtime_tests)
{
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (conf_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (conf_uuid);
- pkg_args.push_back ("--checkout-root");
- pkg_args.push_back (dist_root.string ());
+ pkgs.push_back ("--checkout-root");
+ pkgs.push_back (dist_root.string ());
if (bootstrap_import)
- pkg_args.push_back (*bootstrap_import);
+ pkgs.push_back (*bootstrap_import);
- pkg_args.insert (pkg_args.end (), eas.begin (), eas.end ());
- pkg_args.insert (pkg_args.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), eas.begin (), eas.end ());
+ pkgs.insert (pkgs.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), pas.begin (), pas.end ());
- pkg_args.push_back ("config." +
- t.name.variable () +
- ".develop=false");
+ pkgs.push_back ("config." + t.name.variable () + ".develop=false");
- pkg_args.push_back ("}+");
+ pkgs.push_back ("}+");
- pkg_args.push_back (t.string ());
+ pkgs.push_back (t.string ());
}
#else
if (has_runtime_tests)
{
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (conf_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (conf_uuid);
- pkg_args.push_back ("--checkout-root");
- pkg_args.push_back (dist_root.string ());
+ pkgs.push_back ("--checkout-root");
+ pkgs.push_back (dist_root.string ());
if (bootstrap_import)
- pkg_args.push_back (*bootstrap_import);
+ pkgs.push_back (*bootstrap_import);
- pkg_args.insert (pkg_args.end (), eas.begin (), eas.end ());
- pkg_args.insert (pkg_args.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), eas.begin (), eas.end ());
+ pkgs.insert (pkgs.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), pas.begin (), pas.end ());
- pkg_args.push_back ("}+");
+ pkgs.push_back ("}+");
// Add test dependency package constraints and group them if there
// are multiple of them.
//
if (runtime_tests.size () != 1)
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
for (const auto& t: runtime_tests)
- pkg_args.push_back (t.string ());
+ pkgs.push_back (t.string ());
if (runtime_tests.size () != 1)
- pkg_args.push_back ("}");
+ pkgs.push_back ("}");
}
#endif
}
@@ -2304,6 +2507,7 @@ build (size_t argc, const char* argv[])
cstrings eas (step_args (env_args, s, f1, f2));
cstrings cas (step_args (tgt_args, s, f1, f2));
+ cstrings pas (step_args (pkg_args, s, f1, f2));
// Add the main package.
//
@@ -2312,27 +2516,28 @@ build (size_t argc, const char* argv[])
common_args.push_back ("-d");
common_args.push_back (install_conf.string ());
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (install_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (install_uuid);
// Note that we do another re-distribution (with a separate
// --checkout-root) in case the package is missing file that
// are only used during installation.
//
- pkg_args.push_back ("--checkout-root");
- pkg_args.push_back (dist_install_root.string ());
+ pkgs.push_back ("--checkout-root");
+ pkgs.push_back (dist_install_root.string ());
- pkg_args.insert (pkg_args.end (), eas.begin (), eas.end ());
- pkg_args.insert (pkg_args.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), eas.begin (), eas.end ());
+ pkgs.insert (pkgs.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), pas.begin (), pas.end ());
- pkg_args.insert (pkg_args.end (),
- pkg_config_vars.begin (), pkg_config_vars.end ());
+ pkgs.insert (pkgs.end (),
+ pkg_config_vars.begin (), pkg_config_vars.end ());
- pkg_args.push_back ("}+");
+ pkgs.push_back ("}+");
- pkg_args.push_back (pkg_rev);
+ pkgs.push_back (pkg_rev);
}
// Add the build-time test packages.
@@ -2342,62 +2547,62 @@ build (size_t argc, const char* argv[])
#if 1
for (const auto& t: buildtime_tests)
{
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (target_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (target_uuid);
- pkg_args.push_back ("--checkout-root");
- pkg_args.push_back (dist_root.string ());
+ pkgs.push_back ("--checkout-root");
+ pkgs.push_back (dist_root.string ());
if (bootstrap_import)
- pkg_args.push_back (*bootstrap_import);
+ pkgs.push_back (*bootstrap_import);
- pkg_args.insert (pkg_args.end (), eas.begin (), eas.end ());
- pkg_args.insert (pkg_args.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), eas.begin (), eas.end ());
+ pkgs.insert (pkgs.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), pas.begin (), pas.end ());
- pkg_args.push_back ("config." +
- t.name.variable () +
- ".develop=false");
+ pkgs.push_back ("config." + t.name.variable () + ".develop=false");
- pkg_args.push_back ("}+");
+ pkgs.push_back ("}+");
// Strip the build-time mark.
//
- pkg_args.push_back (t.dependency::string ());
+ pkgs.push_back (t.dependency::string ());
}
#else
if (has_buildtime_tests)
{
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (target_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (target_uuid);
- pkg_args.push_back ("--checkout-root");
- pkg_args.push_back (dist_root.string ());
+ pkgs.push_back ("--checkout-root");
+ pkgs.push_back (dist_root.string ());
if (bootstrap_import)
- pkg_args.push_back (*bootstrap_import);
+ pkgs.push_back (*bootstrap_import);
- pkg_args.insert (pkg_args.end (), eas.begin (), eas.end ());
- pkg_args.insert (pkg_args.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), eas.begin (), eas.end ());
+ pkgs.insert (pkgs.end (), cas.begin (), cas.end ());
+ pkgs.insert (pkgs.end (), pas.begin (), pas.end ());
- pkg_args.push_back ("}+");
+ pkgs.push_back ("}+");
// Add test dependency package constraints and group them if there
// are multiple of them.
//
if (buildtime_tests.size () != 1)
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
// Strip the build-time mark.
//
for (const auto& t: buildtime_tests)
- pkg_args.push_back (t.dependency::string ());
+ pkgs.push_back (t.dependency::string ());
if (buildtime_tests.size () != 1)
- pkg_args.push_back ("}");
+ pkgs.push_back ("}");
}
#endif
}
@@ -2414,21 +2619,22 @@ build (size_t argc, const char* argv[])
{
if (!d.second.empty ())
{
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (conf_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (conf_uuid);
if (create_install)
{
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (install_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (install_uuid);
}
- pkg_args.insert (pkg_args.end (), d.second.begin (), d.second.end ());
- pkg_args.push_back ("}+");
+ pkgs.insert (pkgs.end (), d.second.begin (), d.second.end ());
+
+ pkgs.push_back ("}+");
- pkg_args.push_back (d.first);
+ pkgs.push_back (d.first);
}
else
++no_vars;
@@ -2438,30 +2644,30 @@ build (size_t argc, const char* argv[])
//
if (no_vars != 0)
{
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (conf_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (conf_uuid);
if (create_install)
{
- pkg_args.push_back ("--config-uuid");
- pkg_args.push_back (install_uuid);
+ pkgs.push_back ("--config-uuid");
+ pkgs.push_back (install_uuid);
}
- pkg_args.push_back ("}+");
+ pkgs.push_back ("}+");
if (no_vars != 1)
- pkg_args.push_back ("{");
+ pkgs.push_back ("{");
for (const pair<string, strings>& d: pkg_config_deps)
{
if (d.second.empty ())
- pkg_args.push_back (d.first);
+ pkgs.push_back (d.first);
}
if (no_vars != 1)
- pkg_args.push_back ("}");
+ pkgs.push_back ("}");
}
}
}
@@ -2481,16 +2687,17 @@ build (size_t argc, const char* argv[])
"-v",
"build",
"--configure-only",
- pkg_config_opts,
"--rebuild-checksum",
tm.dependency_checksum ? *tm.dependency_checksum : "",
"--yes",
"-d", root_conf,
step_args (env_args, s),
step_args (tgt_args, s),
+ step_args (pkg_args, s),
common_args,
+ pkg_config_opts,
"--",
- pkg_args);
+ pkgs);
// The dependency checksum is tricky, here are the possibilities:
//
@@ -2585,952 +2792,1182 @@ build (size_t argc, const char* argv[])
Sleep (5000);
#endif
- // Update the main package.
- //
- {
- operation_result& r (add_result ("update"));
-
- change_wd (trace, &r.log, rwd / main_pkg_conf);
-
- // bpkg update <env-config-args> <tgt-config-args> <package-name>
- //
- step_id b (step_id::bpkg_update);
- step_id s (step_id::bpkg_update);
-
- r.status |= run_bpkg (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "update",
- step_args (env_args, s),
- step_args (tgt_args, s),
- pkg);
-
- if (!r.status)
- break;
-
- rm.status |= r.status;
- }
-
- // Re-distribute if comes from a version control-based repository, update,
- // and test external test packages in the bpkg configuration in the
- // current working directory. Optionally pass the config.import.* variable
- // override and/or set the environment variables for the bpkg processes.
- // Return true if all operations for all packages succeeded.
- //
- // Pass true as the installed argument to use the test separate installed
- // phase step ids (bpkg.test-separate-installed.*) and the test separate
- // phase step ids (bpkg.test-separate.*) otherwise. In both cases fall
- // back to the main phase step ids (bpkg.*) when no environment/
- // configuration arguments are specified for them.
- //
- auto test = [&trace, &wre,
- &bkp_step, &bkp_status, &last_cmd,
- &step_args, &tgt_args, &env_args,
- &bootstrap_import,
- &redist]
- (operation_result& r,
- const small_vector<test_dependency, 1>& tests,
- const dir_path& dist_root,
- bool installed,
- const small_vector<string, 1>& envvars = {})
+ auto fail_unreached_breakpoint = [&bkp_step, &fail_operation]
+ (operation_result& r)
{
- const optional<string>& import (!installed
- ? bootstrap_import
- : nullopt);
-
- for (const test_dependency& td: tests)
- {
- const string& pkg (td.name.string ());
-
- // Re-distribute.
- //
- if (exists (dist_root))
- {
- // Note that re-distributing the test package is a bit tricky since
- // we don't know its version and so cannot deduce its source
- // directory name easily. We could potentially run the bpkg-status
- // command after the package is configured and parse the output to
- // obtain the version. Let's, however, keep it simple and find the
- // source directory using the package directory name pattern.
- //
- try
- {
- dir_path pkg_dir;
-
- // Note: doesn't follow symlinks.
- //
- path_search (dir_path (pkg + "-*/"),
- [&pkg_dir] (path&& pe, const string&, bool interm)
- {
- if (!interm)
- pkg_dir = path_cast<dir_path> (move (pe));
-
- return interm;
- },
- dist_root,
- path_match_flags::none);
-
- if (!pkg_dir.empty ())
- {
- step_id b (
- installed
- ? step_id::bpkg_test_separate_installed_configure_build
- : step_id::bpkg_configure_build);
-
- if (!redist (b, r, dist_root, pkg_dir, import, envvars))
- return false;
- }
- }
- catch (const system_error& e)
- {
- fail << "unable to scan directory " << dist_root << ": " << e;
- }
- }
+ assert (bkp_step);
- // Update.
- //
- // bpkg update <env-config-args> <tgt-config-args> <package-name>
- //
- {
- step_id b (installed
- ? step_id::bpkg_test_separate_installed_update
- : step_id::bpkg_test_separate_update);
-
- step_id s (b);
-
- step_id f (step_id::bpkg_update);
-
- r.status |= run_bpkg (
- b,
- envvars,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "update",
- step_args (env_args, s, f),
- step_args (tgt_args, s, f),
- import,
- pkg);
-
- if (!r.status)
- return false;
- }
-
- // Test.
- //
- // Note that we assume that the package supports the test operation
- // since this is its main purpose.
- //
- // bpkg test <env-config-args> <tgt-config-args> <package-name>
- //
- {
- step_id b (installed
- ? step_id::bpkg_test_separate_installed_test
- : step_id::bpkg_test_separate_test);
-
- step_id s (b);
-
- step_id f (step_id::bpkg_test);
-
- r.status |= run_bpkg (
- b,
- envvars,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "test",
- "--package-cwd", // See above for details.
- step_args (env_args, s, f),
- step_args (tgt_args, s, f),
- import,
- pkg);
-
- if (!r.status)
- return false;
- }
- }
-
- return true;
+ fail_operation (r,
+ "interactive build breakpoint " +
+ to_string (*bkp_step) + " cannot be reached",
+ result_status::abort);
};
- // Test the main package.
- //
- b_project_info prj (
- prj_info (pkg_dir,
- b_info_flags::ext_mods | b_info_flags::subprojects,
- "project"));
-
- // Run the internal tests if the test operation is supported by the
- // project but only for the target package or if the configuration is
- // self-hosted.
+ // Note that if the bpkg.update step is disabled, we also skip all the
+ // test and install related steps.
//
- bool has_internal_tests ((target_pkg || selfhost) &&
- find (prj.operations.begin (),
- prj.operations.end (),
- "test") != prj.operations.end ());
-
- if (has_internal_tests || has_runtime_tests || has_buildtime_tests)
+ if (!step_disabled (step_id::bpkg_update))
{
- operation_result& r (add_result ("test"));
-
- // Run internal tests.
+ // Update the main package.
//
- if (has_internal_tests)
{
- // Use --package-cwd to help ported to build2 third-party packages a
- // bit (see bpkg-pkg-test(1) for details).
- //
- // Note that internal tests that load the module itself don't make
- // much sense, thus we don't pass the config.import.* variable on
- // the command line for modules that require bootstrap.
- //
- // bpkg test <env-config-args> <tgt-config-args> <package-name>
+ operation_result& r (add_result ("update"));
+
+ change_wd (trace, &r.log, rwd / main_pkg_conf);
+
+ // bpkg update <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <package-name>
//
- step_id b (step_id::bpkg_test);
- step_id s (step_id::bpkg_test);
+ step_id b (step_id::bpkg_update);
+ step_id s (step_id::bpkg_update);
r.status |= run_bpkg (
b,
trace, r.log, wre,
bkp_step, bkp_status, last_cmd,
"-v",
- "test",
- "--package-cwd",
+ "update",
step_args (env_args, s),
step_args (tgt_args, s),
+ step_args (pkg_args, s),
pkg);
if (!r.status)
break;
+
+ rm.status |= r.status;
}
- // External runtime tests.
+ // Re-distribute if comes from a version control-based repository,
+ // update, and test external test packages in the bpkg configuration in
+ // the current working directory. Optionally pass the config.import.*
+ // variable override and/or set the environment variables for the bpkg
+ // processes. Return true if all operations for all packages succeeded.
//
- // Note that we assume that these packages belong to the dependent
- // package's repository or its complement repositories, recursively.
- // Thus, we test them in the configuration used to build the dependent
- // package.
+ // Pass true as the installed argument to use the test separate installed
+ // phase step ids (bpkg.test-separate-installed.*) and the test separate
+ // phase step ids (bpkg.test-separate.*) otherwise. In both cases fall
+ // back to the main phase step ids (bpkg.*) when no environment/
+ // configuration arguments are specified for them.
//
- if (has_runtime_tests)
- {
- if (!test (r, runtime_tests, dist_root, false /* installed */))
- break;
- }
+ auto test = [&trace, &wre,
+ &bkp_step, &bkp_status, &last_cmd,
+ &step_args, &env_args, &tgt_args, &pkg_args,
+ &bootstrap_import,
+ &redist]
+ (operation_result& r,
+ const small_vector<test_dependency, 1>& tests,
+ const dir_path& dist_root,
+ bool installed,
+ bool update_only,
+ const small_vector<string, 1>& envvars = {})
+ {
+ const optional<string>& import (!installed
+ ? bootstrap_import
+ : nullopt);
- // External build-time tests.
- //
- if (has_buildtime_tests)
- {
- change_wd (trace, &r.log, rwd / target_conf);
+ for (const test_dependency& td: tests)
+ {
+ const string& pkg (td.name.string ());
- if (!test (r, buildtime_tests, dist_root, false /* installed */))
- break;
- }
+ // Re-distribute.
+ //
+ if (exists (dist_root))
+ {
+ // Note that re-distributing the test package is a bit tricky
+ // since we don't know its version and so cannot deduce its
+ // source directory name easily. We could potentially run the
+ // bpkg-status command after the package is configured and parse
+ // the output to obtain the version. Let's, however, keep it
+ // simple and find the source directory using the package
+ // directory name pattern.
+ //
+ try
+ {
+ dir_path pkg_dir;
- rm.status |= r.status;
- }
+ // Note: doesn't follow symlinks.
+ //
+ path_search (dir_path (pkg + "-*/"),
+ [&pkg_dir] (path&& pe, const string&, bool interm)
+ {
+ if (!interm)
+ pkg_dir = path_cast<dir_path> (move (pe));
+
+ return interm;
+ },
+ dist_root,
+ path_match_flags::none);
+
+ if (!pkg_dir.empty ())
+ {
+ step_id b (
+ installed
+ ? step_id::bpkg_test_separate_installed_configure_build
+ : step_id::bpkg_configure_build);
- // Install the package, optionally test the installation and uninstall
- // afterwards.
- //
- if (!install_root)
- break;
+ if (!redist (b, r, dist_root, pkg_dir, import, envvars))
+ return false;
+ }
+ }
+ catch (const system_error& e)
+ {
+ fail << "unable to scan directory " << dist_root << ": " << e;
+ }
+ }
- // Now the overall plan is as follows:
- //
- // 1. Install the package.
- //
- // 2. If the package has subprojects that support the test operation, then
- // configure, build, and test them out of the source tree against the
- // installed package using the build system directly.
- //
- // 3. If any of the test packages are specified, then configure, build,
- // and test them in a separate bpkg configuration(s) against the
- // installed package.
- //
- // 4. Uninstall the package.
+ // Update.
+ //
+ // bpkg update <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <package-name>
+ //
+ {
+ step_id b (installed
+ ? step_id::bpkg_test_separate_installed_update
+ : step_id::bpkg_test_separate_update);
- install_conf = rwd / (create_install ? install_conf : main_pkg_conf);
+ step_id s (b);
- // Install.
- //
- {
- operation_result& r (add_result ("install"));
+ step_id f (step_id::bpkg_update);
- change_wd (trace, &r.log, install_conf);
+ r.status |= run_bpkg (
+ b,
+ envvars,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "update",
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f),
+ import,
+ pkg);
- // Note that for a host or module package we don't need the target
- // configuration anymore, if present. So let's free up the space a
- // little bit.
- //
- if (!target_pkg && create_target)
- rm_r (trace, &r.log, rwd / target_conf);
+ if (!r.status)
+ return false;
+ }
- // bpkg install <env-config-args> <tgt-config-args> <package-name>
- //
- step_id b (step_id::bpkg_install);
- step_id s (step_id::bpkg_install);
+ // Test.
+ //
+ // Note that we assume that the package supports the test operation
+ // since this is its main purpose.
+ //
+ // bpkg test <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <package-name>
+ //
+ if (!update_only)
+ {
+ step_id b (installed
+ ? step_id::bpkg_test_separate_installed_test
+ : step_id::bpkg_test_separate_test);
- r.status |= run_bpkg (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "install",
- step_args (env_args, s),
- step_args (tgt_args, s),
- pkg);
+ step_id s (b);
- if (!r.status)
- break;
+ step_id f (step_id::bpkg_test);
- rm.status |= r.status;
- }
+ r.status |= run_bpkg (
+ b,
+ envvars,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "test",
+ "--package-cwd", // See above for details.
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f),
+ import,
+ pkg);
- // Run the internal tests if the project contains "testable" subprojects,
- // but not for a module.
- //
- has_internal_tests = false;
+ if (!r.status)
+ return false;
+ }
+ }
- dir_paths subprj_dirs; // "Testable" package subprojects.
+ return true;
+ };
- if (!module_pkg)
- {
- // Collect the "testable" subprojects.
+ // Test the main package.
//
- for (const b_project_info::subproject& sp: prj.subprojects)
- {
- // Retrieve the subproject information similar to how we've done it
- // for the package.
- //
- b_project_info si (prj_info (pkg_dir / sp.path,
- b_info_flags::ext_mods,
- "subproject"));
-
- const strings& ops (si.operations);
- if (find (ops.begin (), ops.end (), "test") != ops.end ())
- subprj_dirs.push_back (sp.path);
- }
-
- has_internal_tests = !subprj_dirs.empty ();
- }
-
- if (has_internal_tests || has_runtime_tests || has_buildtime_tests)
- {
- operation_result& r (add_result ("test-installed"));
-
- change_wd (trace, &r.log, rwd);
-
- // Make sure that the installed package executables are properly
- // imported when configuring and running tests, unless we are testing
- // the build system module (that supposedly doesn't install any
- // executables).
+ b_project_info prj (
+ prj_info (pkg_dir,
+ b_info_flags::ext_mods | b_info_flags::subprojects,
+ "project"));
+
+ // Run the internal tests if the test operation is supported by the
+ // project but only for the target package or if the configuration is
+ // self-hosted.
//
- small_vector<string, 1> envvars;
+ bool has_internal_tests ((target_pkg || selfhost) &&
+ find (prj.operations.begin (),
+ prj.operations.end (),
+ "test") != prj.operations.end ());
- if (!module_pkg)
+ if (has_internal_tests || has_runtime_tests || has_buildtime_tests)
{
- // Note that we add the $config.install.root/bin directory at the
- // beginning of the PATH environment variable value, so the installed
- // executables are found first.
- //
- string paths ("PATH=" + (*install_root / "bin").string ());
+ operation_result& r (add_result ("test"));
- if (optional<string> s = getenv ("PATH"))
- {
- paths += path::traits_type::path_separator;
- paths += *s;
- }
-
- envvars.push_back (move (paths));
- }
-
- // Run internal tests.
- //
- if (has_internal_tests)
- {
- // Create the configuration.
- //
- // b create(<dir>, <env-modules>) <env-config-args> <tgt-config-args>
+ // Run internal tests.
//
- // Amalgamation directory that will contain configuration subdirectory
- // for package tests out of source tree build.
- //
- dir_path out_dir ("build-installed");
-
+ if (has_internal_tests && !step_disabled (step_id::bpkg_test))
{
- step_id b (step_id::b_test_installed_create);
- step_id s (step_id::b_test_installed_create);
- step_id f (step_id::b_create);
-
- string mods; // build2 create meta-operation parameters.
-
- for (const char* m: step_args (modules, s, f))
- {
- mods += mods.empty () ? ", " : " ";
- mods += m;
- }
+ // Use --package-cwd to help ported to build2 third-party packages a
+ // bit (see bpkg-pkg-test(1) for details).
+ //
+ // Note that internal tests that load the module itself don't make
+ // much sense, thus we don't pass the config.import.* variable on
+ // the command line for modules that require bootstrap.
+ //
+ // bpkg test <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <package-name>
+ //
+ step_id b (step_id::bpkg_test);
+ step_id s (step_id::bpkg_test);
- r.status |= run_b (
+ r.status |= run_bpkg (
b,
trace, r.log, wre,
bkp_step, bkp_status, last_cmd,
- "-V",
- "create('" + out_dir.representation () + '\'' + mods + ')',
- step_args (env_args, s, f),
- step_args (tgt_args, s, f));
+ "-v",
+ "test",
+ "--package-cwd",
+ step_args (env_args, s),
+ step_args (tgt_args, s),
+ step_args (pkg_args, s),
+ pkg);
if (!r.status)
break;
}
-
- // Configure testable subprojects sequentially and test/build in
- // parallel afterwards.
//
- // It feels right to configure internal tests also passing the main
- // package configuration variables, since they may need to align with
- // the main package setup (enable some testscripts, etc).
+ // Fail if the breakpoint refers to the bpkg.test step but the package
+ // has no internal tests or this step is disabled.
//
- strings test_specs;
- for (const dir_path& d: subprj_dirs)
+ else if (bkp_step && *bkp_step == step_id::bpkg_test)
{
- // b configure(<subprj-src-dir>@<subprj-out-dir>) <env-config-args>
- // <tgt-config-args>
- // <pkg-vars>
- //
- step_id b (step_id::b_test_installed_configure);
- step_id s (step_id::b_test_installed_configure);
- step_id f (step_id::b_configure);
-
- dir_path subprj_src_dir (exists (dist_src)
- ? dist_src / d
- : main_pkg_conf / pkg_dir / d);
-
- dir_path subprj_out_dir (out_dir / d);
+ fail_unreached_breakpoint (r);
+ break;
+ }
- r.status |= run_b (
- b,
- envvars,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "configure('" +
- subprj_src_dir.representation () + "'@'" +
- subprj_out_dir.representation () + "')",
- step_args (env_args, s, f),
- step_args (tgt_args, s, f),
- pkg_config_vars);
+ // External tests.
+ //
+ // Note that if the bpkg.test-separate.update step is disabled, we
+ // also skip bpkg.test-separate.test.
+ //
+ if ((has_runtime_tests || has_buildtime_tests) &&
+ !step_disabled (step_id::bpkg_test_separate_update))
+ {
+ bool update_only (step_disabled (step_id::bpkg_test_separate_test));
- if (!r.status)
+ // Fail if the breakpoint refers to the bpkg.test-separate.test step
+ // but this step is disabled.
+ //
+ if (update_only &&
+ bkp_step &&
+ *bkp_step == step_id::bpkg_test_separate_test)
+ {
+ fail_unreached_breakpoint (r);
break;
+ }
- test_specs.push_back (
- "test('" + subprj_out_dir.representation () + "')");
- }
+ // External runtime tests.
+ //
+ // Note that we assume that these packages belong to the dependent
+ // package's repository or its complement repositories, recursively.
+ // Thus, we test them in the configuration used to build the
+ // dependent package.
+ //
+ if (has_runtime_tests)
+ {
+ if (!test (r,
+ runtime_tests,
+ dist_root,
+ false /* installed */,
+ update_only))
+ break;
+ }
- if (!r.status)
- break;
+ // External build-time tests.
+ //
+ if (has_buildtime_tests)
+ {
+ change_wd (trace, &r.log, rwd / target_conf);
- // Build/test subprojects.
+ if (!test (r,
+ buildtime_tests,
+ dist_root,
+ false /* installed */,
+ update_only))
+ break;
+ }
+ }
//
- // b test(<subprj-out-dir>)... <env-config-args> <tgt-config-args>
+ // Fail if the breakpoint refers to some of the bpkg.test-separate.*
+ // steps but the package either has no external tests or the
+ // bpkg.test-separate.update step is disabled.
//
+ else if (bkp_step &&
+ *bkp_step >= step_id::bpkg_test_separate_update &&
+ *bkp_step <= step_id::bpkg_test_separate_test)
{
- step_id b (step_id::b_test_installed_test);
- step_id s (step_id::b_test_installed_test);
-
- r.status |= run_b (
- b,
- envvars,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- test_specs,
- step_args (env_args, s),
- step_args (tgt_args, s));
-
- if (!r.status)
- break;
+ fail_unreached_breakpoint (r);
+ break;
}
- }
- // Run runtime and build-time tests.
+ rm.status |= r.status;
+ }
//
- // Note that we only build runtime tests for target packages and for
- // host packages in self-hosted configurations.
+ // Fail if the breakpoint refers to some of the test steps but the
+ // package has no tests.
//
- if (has_runtime_tests || has_buildtime_tests)
+ else if (bkp_step &&
+ *bkp_step >= step_id::bpkg_test &&
+ *bkp_step <= step_id::bpkg_test_separate_test)
{
- // Create the required build configurations.
- //
- dir_path target_conf ("build-installed-bpkg");
- dir_path host_conf ("build-installed-bpkg-host");
- dir_path module_conf ("build-installed-bpkg-module");
+ fail_unreached_breakpoint (add_result ("test"));
+ break;
+ }
- // Create the target configuration if this is a target package having
- // external runtime tests or a host/module package having external
- // build-time tests.
+ // Install the package, optionally test the installation and uninstall
+ // afterwards.
+ //
+ // Note that if the bpkg.install step is disabled, we also skip all the
+ // test installed related steps up to bpkg.uninstall.
+ //
+ if (install_root && !step_disabled (step_id::bpkg_install))
+ {
+ // Now the overall plan is as follows:
//
- bool create_target (target_pkg || has_buildtime_tests);
-
- // Note that even if there are no runtime tests for a host/module
- // package, we still need to create the host/build2 configuration to
- // configure the system package in.
+ // 1. Install the package.
//
- bool create_host (host_pkg || module_pkg);
- bool create_module (module_pkg || (host_pkg && has_buildtime_tests));
-
- // Note: a module package cannot have runtime tests and so the module
- // configuration is only created to serve build-time tests. Thus, the
- // host or target configuration is always created as well and the
- // module configuration is never a root configuration.
+ // 2. If the package has subprojects that support the test operation,
+ // then configure, build, and test them out of the source tree
+ // against the installed package using the build system directly.
//
- assert (create_target || create_host);
-
- // Root configuration through which we will be configuring the
- // cluster.
+ // 3. If any of the test packages are specified, then configure, build,
+ // and test them in a separate bpkg configuration(s) against the
+ // installed package.
//
- const dir_path& root_conf (create_target ? target_conf : host_conf);
+ // 4. Uninstall the package.
- // Runtime tests configuration. Should only be used if there are any.
- //
- const dir_path& runtime_tests_conf (target_pkg
- ? target_conf
- : host_conf);
+ install_conf = rwd / (create_install ? install_conf : main_pkg_conf);
- // Create the target configuration.
- //
- // bpkg create <env-modules> <env-config-args> <tgt-config-args>
+ // Install.
//
- if (create_target)
{
- step_id b (step_id::bpkg_test_separate_installed_create);
+ operation_result& r (add_result ("install"));
- // Note that here and below the _for_* step ids are determined by
- // the main package type (and, yes, that means we will use the same
- // step ids for target and host configuration -- that, however,
- // should be ok since host configuration will only be created in
- // the self-hosted case).
+ change_wd (trace, &r.log, install_conf);
+
+ // Note that for a host or module package we don't need the target
+ // configuration anymore, if present. So let's free up the space a
+ // little bit.
//
- step_id s (
- target_pkg
- ? step_id::bpkg_test_separate_installed_create_for_target
- : host_pkg
- ? step_id::bpkg_test_separate_installed_create_for_host
- : step_id::bpkg_test_separate_installed_create_for_module);
-
- // Note: no fallback for modules.
+ if (!target_pkg && create_target)
+ rm_r (trace, &r.log, rwd / target_conf);
+
+ // bpkg install <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <package-name>
//
- optional<step_id> f (!module_pkg
- ? step_id::bpkg_test_separate_installed_create
- : optional<step_id> ());
+ step_id b (step_id::bpkg_install);
+ step_id s (step_id::bpkg_install);
r.status |= run_bpkg (
b,
trace, r.log, wre,
bkp_step, bkp_status, last_cmd,
- "-V",
- "create",
- "-d", target_conf,
- step_args (modules, s, f),
- step_args (env_args, s, f),
- step_args (tgt_args, s, f));
+ "-v",
+ "install",
+ step_args (env_args, s),
+ step_args (tgt_args, s),
+ step_args (pkg_args, s),
+ pkg);
if (!r.status)
break;
+
+ rm.status |= r.status;
}
- // Create the host configuration.
+ // Run the internal tests if the project contains "testable"
+ // subprojects, but not for a module.
//
- if (create_host)
- {
- // bpkg create --type host <env-modules> <env-config-args> <tgt-config-args>
- //
- step_id b (step_id::bpkg_test_separate_installed_create);
+ has_internal_tests = false;
- step_id s (
- host_pkg
- ? step_id::bpkg_test_separate_installed_create_for_host
- : step_id::bpkg_test_separate_installed_create_for_module);
+ dir_paths subprj_dirs; // "Testable" package subprojects.
- // Note: no fallback for modules.
+ if (!module_pkg)
+ {
+ // Collect the "testable" subprojects.
//
- optional<step_id> f (!module_pkg
- ? step_id::bpkg_test_separate_installed_create
- : optional<step_id> ());
+ for (const b_project_info::subproject& sp: prj.subprojects)
+ {
+ // Retrieve the subproject information similar to how we've done it
+ // for the package.
+ //
+ b_project_info si (prj_info (pkg_dir / sp.path,
+ b_info_flags::ext_mods,
+ "subproject"));
- r.status |= run_bpkg (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-V",
- "create",
- "-d", host_conf,
- "--type", "host",
- "--name", "host",
- step_args (modules, s, f),
- step_args (env_args, s, f),
- step_args (tgt_args, s, f));
+ const strings& ops (si.operations);
+ if (find (ops.begin (), ops.end (), "test") != ops.end ())
+ subprj_dirs.push_back (sp.path);
+ }
- if (!r.status)
- break;
+ has_internal_tests = !subprj_dirs.empty ();
}
- // Create the module configuration.
- //
- // Note that we never build any tests in it but only configure the
- // system package. Note, however, that the host/module package
- // build-time tests can potentially build some other modules here.
- //
- if (create_module)
+ if (has_internal_tests || has_runtime_tests || has_buildtime_tests)
{
- // b create(<dir>) config.config.load=~build2
+ operation_result& r (add_result ("test-installed"));
+
+ change_wd (trace, &r.log, rwd);
+
+ // Make sure that the installed package executables are properly
+ // imported when configuring and running tests, unless we are testing
+ // the build system module (that supposedly doesn't install any
+ // executables).
//
- step_id b (step_id::bpkg_test_separate_installed_create);
+ small_vector<string, 1> envvars;
- r.status |= run_b (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-V",
- "create(" + module_conf.representation () + ",cc)",
- "config.config.load=~build2",
- "config.config.persist+='config.*'@unused=drop");
+ if (!module_pkg)
+ {
+ // Note that we add the $config.install.root/bin directory at the
+ // beginning of the PATH environment variable value, so the
+ // installed executables are found first.
+ //
+ string paths ("PATH=" + (*install_root / "bin").string ());
- if (!r.status)
- break;
+ if (optional<string> s = getenv ("PATH"))
+ {
+ paths += path::traits_type::path_separator;
+ paths += *s;
+ }
- // bpkg create --existing --type build2
+ envvars.push_back (move (paths));
+ }
+
+ // Run internal tests.
//
- r.status |= run_bpkg (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "create",
- "--existing",
- "-d", module_conf,
- "--type", "build2",
- "--name", "module");
+ if (has_internal_tests)
+ {
+ // Create the configuration.
+ //
+ // b create(<dir>, <env-modules>) <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ //
+ // Amalgamation directory that will contain configuration
+ // subdirectory for package tests out of source tree build.
+ //
+ dir_path out_dir ("build-installed");
- if (!r.status)
- break;
- }
+ {
+ step_id b (step_id::b_test_installed_create);
+ step_id s (step_id::b_test_installed_create);
+ step_id f (step_id::b_create);
- // Link the configurations.
- //
- // bpkg link -d <dir> <dir>
- //
- {
- step_id b (step_id::bpkg_test_separate_installed_link);
+ string mods; // build2 create meta-operation parameters.
- if (create_target)
- {
- if (create_host)
+ for (const char* m: step_args (modules, s, f))
+ {
+ mods += mods.empty () ? ", " : " ";
+ mods += m;
+ }
+
+ r.status |= run_b (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-V",
+ "create('" + out_dir.representation () + '\'' + mods + ')',
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f));
+
+ if (!r.status)
+ break;
+ }
+
+ // Configure testable subprojects sequentially and test/build in
+ // parallel afterwards.
+ //
+ // It feels right to configure internal tests also passing the
+ // main package configuration variables, since they may need to
+ // align with the main package setup (enable some testscripts,
+ // etc).
+ //
+ strings test_specs;
+ for (const dir_path& d: subprj_dirs)
{
- r.status |= run_bpkg (
+ // b configure(<subprj-src-dir>@<subprj-out-dir>) <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ // <pkg-vars>
+ //
+ step_id b (step_id::b_test_installed_configure);
+ step_id s (step_id::b_test_installed_configure);
+ step_id f (step_id::b_configure);
+
+ dir_path subprj_src_dir (exists (dist_src)
+ ? dist_src / d
+ : main_pkg_conf / pkg_dir / d);
+
+ dir_path subprj_out_dir (out_dir / d);
+
+ r.status |= run_b (
b,
+ envvars,
trace, r.log, wre,
bkp_step, bkp_status, last_cmd,
"-v",
- "link",
- "-d", target_conf,
- host_conf);
+ "configure('" +
+ subprj_src_dir.representation () + "'@'" +
+ subprj_out_dir.representation () + "')",
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f),
+ pkg_config_vars);
if (!r.status)
break;
+
+ test_specs.push_back (
+ "test('" + subprj_out_dir.representation () + "')");
}
- if (create_module)
+ if (!r.status)
+ break;
+
+ // Build/test subprojects.
+ //
+ // b test(<subprj-out-dir>)... <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ //
+ if (!step_disabled (step_id::b_test_installed_test))
{
- r.status |= run_bpkg (
+ step_id b (step_id::b_test_installed_test);
+ step_id s (step_id::b_test_installed_test);
+
+ r.status |= run_b (
b,
+ envvars,
trace, r.log, wre,
bkp_step, bkp_status, last_cmd,
"-v",
- "link",
- "-d", target_conf,
- module_conf);
+ test_specs,
+ step_args (env_args, s),
+ step_args (tgt_args, s),
+ step_args (pkg_args, s));
if (!r.status)
break;
}
+ //
+ // Fail if the breakpoint refers to the b.test-installed.test step
+ // but this step is disabled.
+ //
+ else if (bkp_step && *bkp_step == step_id::b_test_installed_test)
+ {
+ fail_unreached_breakpoint (r);
+ break;
+ }
+ }
+ //
+ // Fail if the breakpoint refers to some of the b.test-installed.*
+ // steps but the package doesn't have any internal tests.
+ //
+ else if (bkp_step &&
+ *bkp_step >= step_id::b_test_installed_create &&
+ *bkp_step <= step_id::b_test_installed_test)
+ {
+ fail_unreached_breakpoint (r);
+ break;
}
- if (create_host)
+ // Run runtime and build-time tests.
+ //
+ // Note that we only build runtime tests for target packages and for
+ // host packages in self-hosted configurations.
+ //
+ if (has_runtime_tests || has_buildtime_tests)
{
+ // Create the required build configurations.
+ //
+ dir_path target_conf ("build-installed-bpkg");
+ dir_path host_conf ("build-installed-bpkg-host");
+ dir_path module_conf ("build-installed-bpkg-module");
+
+ // Create the target configuration if this is a target package
+ // having external runtime tests or a host/module package having
+ // external build-time tests.
+ //
+ bool create_target (target_pkg || has_buildtime_tests);
+
+ // Note that even if there are no runtime tests for a host/module
+ // package, we still need to create the host/build2 configuration
+ // to configure the system package in.
+ //
+ bool create_host (host_pkg || module_pkg);
+
+ bool create_module (module_pkg ||
+ (host_pkg && has_buildtime_tests));
+
+ // Note: a module package cannot have runtime tests and so the
+ // module configuration is only created to serve build-time tests.
+ // Thus, the host or target configuration is always created as
+ // well and the module configuration is never a root
+ // configuration.
+ //
+ assert (create_target || create_host);
+
+ // Root configuration through which we will be configuring the
+ // cluster.
+ //
+ const dir_path& root_conf (create_target ? target_conf : host_conf);
+
+ // Runtime tests configuration. Should only be used if there are
+ // any.
+ //
+ const dir_path& runtime_tests_conf (target_pkg
+ ? target_conf
+ : host_conf);
+
+ // Create the target configuration.
+ //
+ // bpkg create <env-modules> <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ //
+ if (create_target)
+ {
+ step_id b (step_id::bpkg_test_separate_installed_create);
+
+ // Note that here and below the _for_* step ids are determined
+ // by the main package type (and, yes, that means we will use
+ // the same step ids for target and host configuration -- that,
+ // however, should be ok since host configuration will only be
+ // created in the self-hosted case).
+ //
+ step_id s (
+ target_pkg
+ ? step_id::bpkg_test_separate_installed_create_for_target
+ : host_pkg
+ ? step_id::bpkg_test_separate_installed_create_for_host
+ : step_id::bpkg_test_separate_installed_create_for_module);
+
+ // Note: no fallback for modules.
+ //
+ optional<step_id> f (!module_pkg
+ ? step_id::bpkg_test_separate_installed_create
+ : optional<step_id> ());
+
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-V",
+ "create",
+ "-d", target_conf,
+ step_args (modules, s, f),
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f));
+
+ if (!r.status)
+ break;
+ }
+
+ // Create the host configuration.
+ //
+ if (create_host)
+ {
+ // bpkg create --type host <env-modules> <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ //
+ step_id b (step_id::bpkg_test_separate_installed_create);
+
+ step_id s (host_pkg
+ ? step_id::bpkg_test_separate_installed_create_for_host
+ : step_id::bpkg_test_separate_installed_create_for_module);
+
+ // Note: no fallback for modules.
+ //
+ optional<step_id> f (!module_pkg
+ ? step_id::bpkg_test_separate_installed_create
+ : optional<step_id> ());
+
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-V",
+ "create",
+ "-d", host_conf,
+ "--type", "host",
+ "--name", "host",
+ step_args (modules, s, f),
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f));
+
+ if (!r.status)
+ break;
+ }
+
+ // Create the module configuration.
+ //
+ // Note that we never build any tests in it but only configure the
+ // system package. Note, however, that the host/module package
+ // build-time tests can potentially build some other modules here.
+ //
if (create_module)
{
+ // b create(<dir>) config.config.load=~build2
+ //
+ step_id b (step_id::bpkg_test_separate_installed_create);
+
+ r.status |= run_b (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-V",
+ "create(" + module_conf.representation () + ",cc)",
+ "config.config.load=~build2",
+ "config.config.persist+='config.*'@unused=drop");
+
+ if (!r.status)
+ break;
+
+ // bpkg create --existing --type build2
+ //
r.status |= run_bpkg (
b,
trace, r.log, wre,
bkp_step, bkp_status, last_cmd,
"-v",
- "link",
- "-d", host_conf,
- module_conf);
+ "create",
+ "--existing",
+ "-d", module_conf,
+ "--type", "build2",
+ "--name", "module");
if (!r.status)
break;
}
- }
- }
- // Add and fetch the repositories.
- //
- if (has_runtime_tests)
- {
- // bpkg add <env-config-args> <tgt-config-args> <repository-url>
- //
- {
- step_id b (step_id::bpkg_test_separate_installed_configure_add);
- step_id s (step_id::bpkg_test_separate_installed_configure_add);
- step_id f (step_id::bpkg_configure_add);
+ // Link the configurations.
+ //
+ // bpkg link -d <dir> <dir>
+ //
+ {
+ step_id b (step_id::bpkg_test_separate_installed_link);
- r.status |= run_bpkg (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "add",
- "-d", runtime_tests_conf,
- step_args (env_args, s, f),
- step_args (tgt_args, s, f),
- repo);
+ if (create_target)
+ {
+ if (create_host)
+ {
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "link",
+ "-d", target_conf,
+ host_conf);
+
+ if (!r.status)
+ break;
+ }
- if (!r.status)
- break;
- }
+ if (create_module)
+ {
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "link",
+ "-d", target_conf,
+ module_conf);
+
+ if (!r.status)
+ break;
+ }
+ }
- // bpkg fetch <env-config-args> <tgt-config-args> <trust-options>
- //
- {
- step_id b (step_id::bpkg_test_separate_installed_configure_fetch);
- step_id s (step_id::bpkg_test_separate_installed_configure_fetch);
- step_id f (step_id::bpkg_configure_fetch);
+ if (create_host)
+ {
+ if (create_module)
+ {
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "link",
+ "-d", host_conf,
+ module_conf);
+
+ if (!r.status)
+ break;
+ }
+ }
+ }
- r.status |= run_bpkg (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "fetch",
- "-d", runtime_tests_conf,
- step_args (env_args, s, f),
- step_args (tgt_args, s, f),
- trust_ops);
+ // Add and fetch the repositories.
+ //
+ if (has_runtime_tests)
+ {
+ // bpkg add <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <repository-url>
+ //
+ {
+ step_id b (step_id::bpkg_test_separate_installed_configure_add);
+ step_id s (step_id::bpkg_test_separate_installed_configure_add);
+ step_id f (step_id::bpkg_configure_add);
- if (!r.status)
- break;
- }
- }
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "add",
+ "-d", runtime_tests_conf,
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f),
+ repo);
+
+ if (!r.status)
+ break;
+ }
- if (has_buildtime_tests)
- {
- // bpkg add <env-config-args> <tgt-config-args> <repository-url>
- //
- {
- step_id b (step_id::bpkg_test_separate_installed_configure_add);
- step_id s (step_id::bpkg_test_separate_installed_configure_add);
- step_id f (step_id::bpkg_configure_add);
+ // bpkg fetch <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <trust-options>
+ //
+ {
+ step_id b (step_id::bpkg_test_separate_installed_configure_fetch);
+ step_id s (step_id::bpkg_test_separate_installed_configure_fetch);
+ step_id f (step_id::bpkg_configure_fetch);
- r.status |= run_bpkg (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "add",
- "-d", target_conf,
- step_args (env_args, s, f),
- step_args (tgt_args, s, f),
- repo);
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "fetch",
+ "-d", runtime_tests_conf,
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f),
+ trust_ops);
+
+ if (!r.status)
+ break;
+ }
+ }
- if (!r.status)
- break;
- }
+ if (has_buildtime_tests)
+ {
+ // bpkg add <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <repository-url>
+ //
+ {
+ step_id b (step_id::bpkg_test_separate_installed_configure_add);
+ step_id s (step_id::bpkg_test_separate_installed_configure_add);
+ step_id f (step_id::bpkg_configure_add);
- // bpkg fetch <env-config-args> <tgt-config-args> <trust-options>
- //
- {
- step_id b (step_id::bpkg_test_separate_installed_configure_fetch);
- step_id s (step_id::bpkg_test_separate_installed_configure_fetch);
- step_id f (step_id::bpkg_configure_fetch);
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "add",
+ "-d", target_conf,
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f),
+ repo);
+
+ if (!r.status)
+ break;
+ }
- r.status |= run_bpkg (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "fetch",
- "-d", target_conf,
- step_args (env_args, s, f),
- step_args (tgt_args, s, f),
- trust_ops);
+ // bpkg fetch <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <trust-options>
+ //
+ {
+ step_id b (step_id::bpkg_test_separate_installed_configure_fetch);
+ step_id s (step_id::bpkg_test_separate_installed_configure_fetch);
+ step_id f (step_id::bpkg_configure_fetch);
- if (!r.status)
- break;
- }
- }
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "fetch",
+ "-d", target_conf,
+ step_args (env_args, s, f),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, s, f),
+ trust_ops);
+
+ if (!r.status)
+ break;
+ }
+ }
- // Configure all the packages using a single bpkg-pkg-build command.
- //
- // bpkg build --configure-only <env-config-args> <tgt-config-args>
- // { <config> }+ { <runtime-test>... }
- // <buildtime-test>...
- // ?sys:<pkg>
- //
- strings pkg_args;
+ // Configure all the packages using a single bpkg-pkg-build command.
+ //
+ // bpkg build --configure-only <env-config-args>
+ // <tgt-config-args>
+ // <pkg-config-args>
+ // { <config> }+ { <runtime-test>... }
+ // <buildtime-test>...
+ // ?sys:<pkg>
+ //
+ strings pkgs;
- if (has_runtime_tests)
- {
- // Note that only host package runtime tests can (but not
- // necessarily) be configured in a linked configuration and require
- // --config-name to be specified for them.
- //
- assert (!module_pkg);
+ if (has_runtime_tests)
+ {
+ // Note that only host package runtime tests can (but not
+ // necessarily) be configured in a linked configuration and
+ // require --config-name to be specified for them.
+ //
+ assert (!module_pkg);
- string conf_name (runtime_tests_conf == root_conf
- ? ""
- : "host");
+ string conf_name (runtime_tests_conf == root_conf
+ ? ""
+ : "host");
- bool og (!conf_name.empty ());
+ bool og (!conf_name.empty ());
- if (og)
- {
- pkg_args.push_back ("{");
+ if (og)
+ {
+ pkgs.push_back ("{");
- pkg_args.push_back ("--config-name");
- pkg_args.push_back (conf_name);
+ pkgs.push_back ("--config-name");
+ pkgs.push_back (conf_name);
- pkg_args.push_back ("}+");
- }
+ pkgs.push_back ("}+");
+ }
- if (og && runtime_tests.size () != 1)
- pkg_args.push_back ("{");
+ if (og && runtime_tests.size () != 1)
+ pkgs.push_back ("{");
- for (const auto& t: runtime_tests)
- pkg_args.push_back (t.string ());
+ for (const auto& t: runtime_tests)
+ pkgs.push_back (t.string ());
- if (og && runtime_tests.size () != 1)
- pkg_args.push_back ("}");
- }
+ if (og && runtime_tests.size () != 1)
+ pkgs.push_back ("}");
+ }
- if (has_buildtime_tests)
- {
- // Strip the build-time mark.
- //
- for (const auto& t: buildtime_tests)
- pkg_args.push_back (t.dependency::string ());
- }
+ if (has_buildtime_tests)
+ {
+ // Strip the build-time mark.
+ //
+ for (const auto& t: buildtime_tests)
+ pkgs.push_back (t.dependency::string ());
+ }
- pkg_args.push_back ("?sys:" + pkg_rev);
+ pkgs.push_back ("?sys:" + pkg_rev);
- // Finally, configure all the test packages.
- //
- {
- step_id b (step_id::bpkg_test_separate_installed_configure_build);
+ // Finally, configure all the test packages.
+ //
+ {
+ step_id b (step_id::bpkg_test_separate_installed_configure_build);
- step_id g (step_id::bpkg_global_configure_build); // Global.
+ step_id g (step_id::bpkg_global_configure_build); // Global.
- step_id s (
- target_pkg
- ? step_id::bpkg_test_separate_installed_create_for_target
- : host_pkg
- ? step_id::bpkg_test_separate_installed_create_for_host
- : step_id::bpkg_test_separate_installed_create_for_module);
+ step_id s (
+ target_pkg
+ ? step_id::bpkg_test_separate_installed_create_for_target
+ : host_pkg
+ ? step_id::bpkg_test_separate_installed_create_for_host
+ : step_id::bpkg_test_separate_installed_create_for_module);
- step_id f (step_id::bpkg_test_separate_installed_configure_build);
+ step_id f (step_id::bpkg_test_separate_installed_configure_build);
- r.status |= run_bpkg (
- b,
- envvars,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "build",
- "--configure-only",
- "--checkout-root", dist_installed_root,
- "--yes",
- "-d", root_conf,
- step_args (env_args, g),
- step_args (env_args, s, f),
- step_args (tgt_args, g),
- step_args (tgt_args, s, f),
- "--",
- pkg_args);
+ r.status |= run_bpkg (
+ b,
+ envvars,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "build",
+ "--configure-only",
+ "--checkout-root", dist_installed_root,
+ "--yes",
+ "-d", root_conf,
+ step_args (env_args, g),
+ step_args (env_args, s, f),
+ step_args (tgt_args, g),
+ step_args (tgt_args, s, f),
+ step_args (pkg_args, g),
+ step_args (pkg_args, s, f),
+ "--",
+ pkgs);
- if (!r.status)
- break;
- }
+ if (!r.status)
+ break;
+ }
#ifdef _WIN32
- Sleep (5000); // See above.
+ Sleep (5000); // See above.
#endif
- // Run external runtime tests.
- //
- if (has_runtime_tests)
- {
- const dir_path& runtime_tests_conf (target_pkg
- ? target_conf
- : host_conf);
+ // Note that if bpkg.test-separate-installed.update step is
+ // disabled, we also skip bpkg.test-separate-installed.test.
+ //
+ if (!step_disabled (step_id::bpkg_test_separate_installed_update))
+ {
+ bool update_only (
+ step_disabled (step_id::bpkg_test_separate_installed_test));
+
+ // Fail if the breakpoint refers to the
+ // bpkg.test-separate-installed.test step but this step is
+ // disabled.
+ //
+ if (update_only &&
+ bkp_step &&
+ *bkp_step == step_id::bpkg_test_separate_installed_test)
+ {
+ fail_unreached_breakpoint (r);
+ break;
+ }
+
+ // External runtime tests.
+ //
+ if (has_runtime_tests)
+ {
+ const dir_path& runtime_tests_conf (target_pkg
+ ? target_conf
+ : host_conf);
+
+ change_wd (trace, &r.log, runtime_tests_conf);
+
+ if (!test (r,
+ runtime_tests,
+ dist_installed_root,
+ true /* installed */,
+ update_only,
+ envvars))
+ break;
+ }
- change_wd (trace, &r.log, runtime_tests_conf);
+ // External build-time tests.
+ //
+ if (has_buildtime_tests)
+ {
+ change_wd (trace, &r.log, rwd / target_conf);
+
+ if (!test (r,
+ buildtime_tests,
+ dist_installed_root,
+ true /* installed */,
+ update_only,
+ envvars))
+ break;
+ }
+ }
+ //
+ // Fail if the breakpoint refers to some of the
+ // bpkg.test-separate-installed.{update,test} steps but the
+ // bpkg.test-separate-installed.update step is disabled.
+ //
+ else if (bkp_step &&
+ *bkp_step >= step_id::bpkg_test_separate_installed_update &&
+ *bkp_step <= step_id::bpkg_test_separate_installed_test)
+ {
+ fail_unreached_breakpoint (r);
+ break;
+ }
- if (!test (r,
- runtime_tests,
- dist_installed_root,
- true /* installed */,
- envvars))
+ rm.status |= r.status;
+ }
+ //
+ // Fail if the breakpoint refers to some of the
+ // bpkg.test-separate-installed.* steps but the package has no
+ // external tests.
+ //
+ else if (bkp_step &&
+ *bkp_step >= step_id::bpkg_test_separate_installed_create &&
+ *bkp_step <= step_id::bpkg_test_separate_installed_test)
+ {
+ fail_unreached_breakpoint (r);
break;
+ }
}
-
- // Run external build-time tests.
//
- if (has_buildtime_tests)
+ // Fail if the breakpoint refers to some of the test installed steps
+ // but the package has no tests.
+ //
+ else if (bkp_step &&
+ *bkp_step >= step_id::b_test_installed_create &&
+ *bkp_step <= step_id::bpkg_test_separate_installed_test)
{
- change_wd (trace, &r.log, rwd / target_conf);
-
- if (!test (r,
- buildtime_tests,
- dist_installed_root,
- true /* installed */,
- envvars))
+ fail_unreached_breakpoint (add_result ("test-installed"));
break;
}
- rm.status |= r.status;
- }
- }
+ // Uninstall.
+ //
+ {
+ operation_result& r (add_result ("uninstall"));
- // Uninstall.
- //
- {
- operation_result& r (add_result ("uninstall"));
+ change_wd (trace, &r.log, install_conf);
- change_wd (trace, &r.log, install_conf);
+ // bpkg uninstall <env-config-args> <tgt-config-args> <pkg-config-args>
+ // <package-name>
+ //
+ step_id b (step_id::bpkg_uninstall);
+ step_id s (step_id::bpkg_uninstall);
- // bpkg uninstall <env-config-args> <tgt-config-args> <package-name>
- //
- step_id b (step_id::bpkg_uninstall);
- step_id s (step_id::bpkg_uninstall);
+ r.status |= run_bpkg (
+ b,
+ trace, r.log, wre,
+ bkp_step, bkp_status, last_cmd,
+ "-v",
+ "uninstall",
+ step_args (env_args, s),
+ step_args (tgt_args, s),
+ step_args (pkg_args, s),
+ pkg);
- r.status |= run_bpkg (
- b,
- trace, r.log, wre,
- bkp_step, bkp_status, last_cmd,
- "-v",
- "uninstall",
- step_args (env_args, s),
- step_args (tgt_args, s),
- pkg);
+ if (!r.status)
+ break;
- if (!r.status)
+ rm.status |= r.status;
+ }
+ }
+ //
+ // Fail if the breakpoint refers to some of the install/test installed
+ // steps but the package either is not supposed to be installed (the
+ // target configuration doesn't specify config.install.root, etc) or the
+ // bpkg.install step is disabled.
+ //
+ else if (bkp_step &&
+ *bkp_step >= step_id::bpkg_install &&
+ *bkp_step <= step_id::bpkg_uninstall)
+ {
+ fail_unreached_breakpoint (add_result ("install"));
break;
-
- rm.status |= r.status;
+ }
+ }
+ //
+ // Fail if the breakpoint refers to bpkg.update or any dependent step but
+ // the bpkg.update step is disabled.
+ //
+ else if (bkp_step &&
+ *bkp_step >= step_id::bpkg_update &&
+ *bkp_step <= step_id::bpkg_uninstall)
+ {
+ fail_unreached_breakpoint (add_result ("update"));
+ break;
}
break;