aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bpkg/bpkg.cxx19
-rw-r--r--bpkg/cfg-create.cli10
-rw-r--r--bpkg/cfg-create.cxx4
-rw-r--r--bpkg/diagnostics.hxx20
-rw-r--r--bpkg/pkg-build.cli21
-rw-r--r--bpkg/pkg-build.cxx133
-rw-r--r--bpkg/pkg-verify.cxx4
7 files changed, 170 insertions, 41 deletions
diff --git a/bpkg/bpkg.cxx b/bpkg/bpkg.cxx
index 12c44ad..0fc1dbe 100644
--- a/bpkg/bpkg.cxx
+++ b/bpkg/bpkg.cxx
@@ -554,16 +554,9 @@ try
assert (false);
fail << "unhandled command";
}
- // Derived from failed and so needs to be caught first.
- //
- catch (const recoverable&)
+ catch (const failed& e)
{
- r = 2;
- break;
- }
- catch (const failed&)
- {
- r = 1;
+ r = e.code;
break;
}
@@ -585,22 +578,22 @@ try
return 0;
}
-catch (const failed&)
+catch (const failed& e)
{
- return 1; // Diagnostics has already been issued.
+ return e.code; // Diagnostics has already been issued.
}
catch (const cli::exception& e)
{
error << e;
return 1;
}
-/*
+#if 0
catch (const std::exception& e)
{
error << e;
return 1;
}
-*/
+#endif
int
main (int argc, char* argv[])
diff --git a/bpkg/cfg-create.cli b/bpkg/cfg-create.cli
index 29cb2a4..990bd08 100644
--- a/bpkg/cfg-create.cli
+++ b/bpkg/cfg-create.cli
@@ -119,6 +119,11 @@ namespace bpkg
created as if by running the \l{bpkg-cfg-link(1)} command."
}
+ bool --no-host-config
+ {
+ "Ignore any specified \cb{--host-config} options."
+ }
+
dir_path --build2-config
{
"<dir>",
@@ -127,6 +132,11 @@ namespace bpkg
command."
}
+ bool --no-build2-config
+ {
+ "Ignore any specified \cb{--build2-config} options."
+ }
+
string --name
{
"<name>",
diff --git a/bpkg/cfg-create.cxx b/bpkg/cfg-create.cxx
index 09d8e79..29de01c 100644
--- a/bpkg/cfg-create.cxx
+++ b/bpkg/cfg-create.cxx
@@ -270,10 +270,10 @@ namespace bpkg
o.existing (),
o.wipe (),
o.uuid_specified () ? o.uuid () : optional<uuid> (),
- (o.host_config_specified ()
+ (o.host_config_specified () && !o.no_host_config ()
? o.host_config ()
: optional<dir_path> ()),
- (o.build2_config_specified ()
+ (o.build2_config_specified () && !o.no_build2_config ()
? o.build2_config ()
: optional<dir_path> ())));
diff --git a/bpkg/diagnostics.hxx b/bpkg/diagnostics.hxx
index 925b080..04ede36 100644
--- a/bpkg/diagnostics.hxx
+++ b/bpkg/diagnostics.hxx
@@ -16,15 +16,27 @@ namespace bpkg
{
using butl::diag_record;
- // Throw this exception to terminate the process. The handler should
- // assume that the diagnostics has already been issued.
+ // Throw this exception to terminate the process potentially with a custom
+ // exit code. The handler should assume that suitable diagnostics has
+ // already been issued.
//
- class failed: public std::exception {};
+ class failed: public std::exception
+ {
+ public:
+ uint16_t code;
+
+ explicit
+ failed (uint16_t c = 1): code (c) {}
+ };
// As above but needs to be used for recoverable errors which are likely to
// disappear on the command retry.
//
- class recoverable: public failed {};
+ class recoverable: public failed
+ {
+ public:
+ recoverable (): failed (2) {}
+ };
// Print process commmand line. If the number of elements is specified
// (or the second version is used), then it will print the piped multi-
diff --git a/bpkg/pkg-build.cli b/bpkg/pkg-build.cli
index 501d8c8..02df2d1 100644
--- a/bpkg/pkg-build.cli
+++ b/bpkg/pkg-build.cli
@@ -350,6 +350,27 @@ namespace bpkg
\cb{pkg-build} or \cb{pkg-drop} command execution if the command
is otherwise a noop (performs no new package builds, upgrades, etc)."
}
+
+ uint16_t --no-private-config
+ {
+ "<code>",
+
+ "If no configuration of a suitable type is linked to build a
+ build-time dependency, instead of automatically creating a private
+ configuration of this type, exit with the specified error code
+ printing to \cb{stdout} the dependency chain starting from the
+ build-time dependency (together with its constraint, if present)
+ and ending with the top-level dependent (together with their
+ configuration directories), one entry per line. For example:
+
+ \
+ yacc ^1.0.0
+ libbar/1.0.0 /path/to/libbar/cfg/
+ libfoo/1.0.0 /path/to/libfoo/cfg/
+ \
+
+ See \l{bpkg-cfg-create(1)} for details on linked configurations."
+ }
};
"
diff --git a/bpkg/pkg-build.cxx b/bpkg/pkg-build.cxx
index 08e1868..d78e739 100644
--- a/bpkg/pkg-build.cxx
+++ b/bpkg/pkg-build.cxx
@@ -615,6 +615,9 @@ namespace bpkg
using build_package_list = list<reference_wrapper<build_package>>;
+ using build_package_refs =
+ small_vector<reference_wrapper<const build_package>, 16>;
+
struct build_packages: build_package_list
{
// Packages collection of whose prerequisites has been postponed due the
@@ -658,17 +661,22 @@ namespace bpkg
// private_configs for details).
//
build_package*
- collect_build (const common_options& options,
+ collect_build (const pkg_build_options& options,
build_package pkg,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
private_configs& priv_cfgs,
- postponed_packages* recursively = nullptr)
+ postponed_packages* recursively = nullptr,
+ build_package_refs* dep_chain = nullptr)
{
using std::swap; // ...and not list::swap().
tracer trace ("collect_build");
+ // Must both be either specified or not.
+ //
+ assert ((recursively == nullptr) == (dep_chain == nullptr));
+
// Only builds are allowed here.
//
assert (pkg.action && *pkg.action == build_package::build &&
@@ -836,7 +844,8 @@ namespace bpkg
recursively,
fdb,
rpt_depts,
- priv_cfgs);
+ priv_cfgs,
+ *dep_chain);
return &p;
}
@@ -858,12 +867,13 @@ namespace bpkg
// we won't be able to be reconfigure it anyway.
//
void
- collect_build_prerequisites (const common_options& options,
+ collect_build_prerequisites (const pkg_build_options& options,
const build_package& pkg,
postponed_packages* postponed,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
- private_configs& priv_cfgs)
+ private_configs& priv_cfgs,
+ build_package_refs& dep_chain)
{
tracer trace ("collect_build_prerequisites");
@@ -900,13 +910,27 @@ namespace bpkg
return;
}
+ dep_chain.push_back (pkg);
+
// Show how we got here if things go wrong.
//
+ // To suppress printing this information clear the dependency chain
+ // before throwing an exception.
+ //
auto g (
make_exception_guard (
- [&pkg] ()
+ [&dep_chain] ()
{
- info << "while satisfying " << pkg.available_name_version_db ();
+ // Note that we also need to clear the dependency chain, to
+ // prevent the caller's exception guard from printing it.
+ //
+ while (!dep_chain.empty ())
+ {
+ info << "while satisfying "
+ << dep_chain.back ().get ().available_name_version_db ();
+
+ dep_chain.pop_back ();
+ }
}));
const shared_ptr<available_package>& ap (pkg.available);
@@ -1158,10 +1182,50 @@ namespace bpkg
}
}
- // If no suitable configuration is found, then create and link it.
+ // If no suitable configuration is found, then create and link it,
+ // unless the --no-private-config options is specified. In the
+ // latter case, print the dependency chain to stdout and exit with
+ // the specified code.
//
if (db == nullptr)
{
+ if (options.no_private_config_specified ())
+ try
+ {
+ // Note that we don't have the dependency package version yet.
+ // We could probably rearrange the code and obtain the available
+ // dependency package by now, given that it comes from the main
+ // database and may not be specified as system (we would have
+ // the configuration otherwise). However, let's not complicate
+ // the code further and instead print the package name and the
+ // constraint, if present.
+ //
+ // Also, in the future, we may still need the configuration to
+ // obtain the available dependency package for some reason (may
+ // want to fetch repositories locally, etc).
+ //
+ cout << d << '\n';
+
+ // Note that we also need to clean the dependency chain, to
+ // prevent the exception guard from printing it to stderr.
+ //
+ for (build_package_refs dc (move (dep_chain)); !dc.empty (); )
+ {
+ const build_package& p (dc.back ());
+
+ cout << p.available_name_version () << ' '
+ << p.db.get ().config << '\n';
+
+ dc.pop_back ();
+ }
+
+ throw failed (options.no_private_config ());
+ }
+ catch (const io_error&)
+ {
+ fail << "unable to write to stdout";
+ }
+
const strings mods {"cc"};
const strings vars {
@@ -1289,7 +1353,7 @@ namespace bpkg
if (dep_constr && !system && postponed)
{
postponed->insert (&pkg);
- return;
+ break;
}
diag_record dr (fail);
@@ -1407,7 +1471,8 @@ namespace bpkg
fdb,
rpt_depts,
priv_cfgs,
- postponed));
+ postponed,
+ &dep_chain));
if (p != nullptr && force && !dep_optional)
{
@@ -1450,6 +1515,8 @@ namespace bpkg
}
}
}
+
+ dep_chain.pop_back ();
}
// Collect the repointed dependents and their replaced prerequisites,
@@ -1462,7 +1529,7 @@ namespace bpkg
//
void
collect_repointed_dependents (
- const common_options& o,
+ const pkg_build_options& o,
database& mdb,
const repointed_dependents& rpt_depts,
build_packages::postponed_packages& postponed,
@@ -1524,12 +1591,15 @@ namespace bpkg
false, // Required by dependents.
build_package::adjust_reconfigure | build_package::build_repoint};
+ build_package_refs dep_chain;
+
collect_build (o,
move (p),
fdb,
rpt_depts,
priv_cfgs,
- &postponed);
+ &postponed,
+ &dep_chain);
}
}
@@ -1617,7 +1687,7 @@ namespace bpkg
}
void
- collect_build_prerequisites (const common_options& o,
+ collect_build_prerequisites (const pkg_build_options& o,
database& db,
const package_name& name,
postponed_packages& postponed,
@@ -1628,16 +1698,19 @@ namespace bpkg
auto mi (map_.find (db, name));
assert (mi != map_.end ());
+ build_package_refs dep_chain;
+
collect_build_prerequisites (o,
mi->second.package,
&postponed,
fdb,
rpt_depts,
- priv_cfgs);
+ priv_cfgs,
+ dep_chain);
}
void
- collect_build_postponed (const common_options& o,
+ collect_build_postponed (const pkg_build_options& o,
postponed_packages& pkgs,
const function<find_database_function>& fdb,
const repointed_dependents& rpt_depts,
@@ -1651,12 +1724,17 @@ namespace bpkg
postponed_packages npkgs;
for (const build_package* p: pkgs)
+ {
+ build_package_refs dep_chain;
+
collect_build_prerequisites (o,
*p,
prog ? &npkgs : nullptr,
fdb,
rpt_depts,
- priv_cfgs);
+ priv_cfgs,
+ dep_chain);
+ }
assert (prog); // collect_build_prerequisites() should have failed.
prog = (npkgs != pkgs);
@@ -3108,6 +3186,13 @@ namespace bpkg
const dir_path& c (o.directory ());
l4 ([&]{trace << "configuration: " << c;});
+ // Make sure that potential stdout writing failures can be detected.
+ //
+ cout.exceptions (ostream::badbit | ostream::failbit);
+
+ // @@ Should we also validate the --no-private-config value, if specified
+ // (>2 and belongs to the "usable exit code range").
+ //
validate_options (o, ""); // Global package options.
if (o.update_dependent () && o.leave_dependent ())
@@ -4034,13 +4119,15 @@ namespace bpkg
{
// Not a valid path so cannot be an archive.
}
- catch (const failed&)
+ catch (const failed& e)
{
// If this is a valid package archive but something went wrong
// afterwards, then we are done.
//
if (package_arc)
throw;
+
+ assert (e.code == 1);
}
// Is this a package directory?
@@ -4121,13 +4208,15 @@ namespace bpkg
{
// Not a valid path so cannot be a package directory.
}
- catch (const failed&)
+ catch (const failed& e)
{
// If this is a valid package directory but something went wrong
// afterwards, then we are done.
//
if (package_dir)
throw;
+
+ assert (e.code == 1);
}
}
}
@@ -4211,8 +4300,9 @@ namespace bpkg
af = move (rp.second);
}
}
- catch (const failed&)
+ catch (const failed& e)
{
+ assert (e.code == 1);
diag = true;
continue;
}
@@ -4940,12 +5030,15 @@ namespace bpkg
false, // Required by dependents.
0}; // State flags.
+ build_package_refs dep_chain;
+
pkgs.collect_build (o,
move (p),
find_prereq_database,
rpt_depts,
priv_cfgs,
- &postponed /* recursively */);
+ &postponed /* recursively */,
+ &dep_chain);
}
}
diff --git a/bpkg/pkg-verify.cxx b/bpkg/pkg-verify.cxx
index 38b4d68..03f854e 100644
--- a/bpkg/pkg-verify.cxx
+++ b/bpkg/pkg-verify.cxx
@@ -247,9 +247,9 @@ namespace bpkg
return 0;
}
- catch (const failed&)
+ catch (const failed& e)
{
- return 1;
+ return e.code;
}
}
}