diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2018-04-26 09:48:58 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2018-04-26 09:48:58 +0200 |
commit | e86333fa8790f624d82ecea2a8da40f85a1d3630 (patch) | |
tree | 91166f5070c5a43310faa3883030ccdf23182193 | |
parent | 7839410d934bb36fdac2e4125c72febf73991320 (diff) |
Add support for forwarded configurations
-rw-r--r-- | bdep/bdep.cli | 14 | ||||
-rw-r--r-- | bdep/config.cli | 39 | ||||
-rw-r--r-- | bdep/config.cxx | 66 | ||||
-rw-r--r-- | bdep/config.hxx | 7 | ||||
-rw-r--r-- | bdep/init.cli | 16 | ||||
-rw-r--r-- | bdep/init.cxx | 40 | ||||
-rw-r--r-- | bdep/init.hxx | 3 | ||||
-rw-r--r-- | bdep/new.cli | 16 | ||||
-rw-r--r-- | bdep/new.cxx | 30 | ||||
-rw-r--r-- | bdep/project.cli | 25 | ||||
-rw-r--r-- | bdep/project.cxx | 148 | ||||
-rw-r--r-- | bdep/project.hxx | 4 | ||||
-rw-r--r-- | bdep/project.xml | 1 | ||||
-rw-r--r-- | bdep/sync.cxx | 78 | ||||
-rw-r--r-- | bdep/utility.cxx | 8 | ||||
-rw-r--r-- | bdep/utility.hxx | 13 | ||||
-rw-r--r-- | bdep/utility.txx | 75 | ||||
-rwxr-xr-x | doc/cli.sh | 1 |
18 files changed, 423 insertions, 161 deletions
diff --git a/bdep/bdep.cli b/bdep/bdep.cli index 19c79af..d7ce274 100644 --- a/bdep/bdep.cli +++ b/bdep/bdep.cli @@ -217,7 +217,17 @@ namespace bdep -a} in the previous example), then it will print a line identifying each configuration before printing the command's result. - @@ build and run? + By default the project's source directory is configured to forward to + the default build configuration. That is, we can run the build system + in the source directory and it will automatically build in the + forwarded configuration as well as link the results back to the + source directory using symlinks or a another suitable mechanism (see + \l{bdep-config(1)} for details). For example: + + \ + $ b # build in gcc + $ ./hello # run the result + \ | @@ -272,6 +282,8 @@ namespace bdep libhello >= 1.0.0 configured 1.0.0 \ + @@ TODO: build system hook. + | \li|\b{Upgrade or Downgrade Dependencies}\n diff --git a/bdep/config.cli b/bdep/config.cli index 62ef5da..c9b2ce8 100644 --- a/bdep/config.cli +++ b/bdep/config.cli @@ -24,13 +24,22 @@ namespace bdep // @@ Should we be able to remove config with init'ed packages? Who // is going to drop them in configs? Or require them to be de-init'ed? // + // @@ Should set be able to alter forward flag? This will require both + // disfiguring forward on old and configuring on new. Perhaps best + // done by sync? I.e., for this change to take effect, one has to + // run sync on both configs? Then sync would somehow need to know + // to remove forwards. Maybe it should always check for stray + // forwards (via out-root.build). + // "\h|SYNOPSIS| \c{\b{bdep config add} \ \ \ [<options>] [<prj-spec>] [\b{@}<cfg-name>] <cfg-dir>\n \b{bdep config create} [<options>] [<prj-spec>] [\b{@}<cfg-name>] <cfg-dir> [<cfg-args>]\n \b{bdep config remove} [<options>] [<prj-spec>] <cfg-spec>... | \b{--all}|\b{-a}\n \b{bdep config rename} [<options>] [<prj-spec>] <cfg-spec> <cfg-name>\n - \b{bdep config set} \ \ \ [<options>] [<prj-spec>] <cfg-spec> \b{--}[\b{no-}]\b{default}} + \b{bdep config set} \ \ \ [<options>] [<prj-spec>] <cfg-spec>\n + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ [\b{--}[\b{no-}]\b{default}]\n + \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ [\b{--}[\b{no-}]\b{forward}]} \c{<cfg-spec> = \b{@}<cfg-name> | \b{--config}|\b{-c} <cfg-dir>\n <prj-spec> = \b{--directory}|\b{-d} <prj-dir>\n @@ -72,7 +81,15 @@ namespace bdep \cb{bdep} commands use such a configuration by default if no configuration was specified explicitly (see \l{bdep-projects-configs(1)} for details). To make a subsequently - added configuration the default use the \cb{--default} option.| + added configuration the default use the \cb{--default} option. + + The default build configuration is also designated as forwarded + unless the \cb{--no-forward} option is specified or another + configuration is already designated as forwarded. When a project is + initialized in a forwarded build configuration, its source directory + is configured to forward to this configuration (see \l{b(1)} for + details on forwarded configurations). To forward to a non-default + configuration use the \cb{--forward} option.| \li|\cb{remove} @@ -89,8 +106,10 @@ namespace bdep \li|\cb{set} The \cb{set} subcommand sets various properties of the specified - build configuration. These include the default flag - (\c{\b{--}[\b{no-}]\b{default}}).||" + build configuration. These include the default + (\c{\b{--}[\b{no-}]\b{default}}) and forward + (\c{\b{--}[\b{no-}]\b{forward}}) flags. Note that changing the + forward flag requires an explicit \cb{sync} command to take effect.||" bool add; bool create; @@ -102,18 +121,8 @@ namespace bdep // Note that not all project/configuration options are valid for all // subcommands. // - class cmd_config_options: project_options + class cmd_config_options: configuration_add_options, project_options { "\h|CONFIG OPTIONS|" - - bool --default - { - "Make the added or created configuration the default." - } - - bool --no-default - { - "Don't make the first added or created configuration then default." - } }; } diff --git a/bdep/config.cxx b/bdep/config.cxx index 0acd227..0dcea48 100644 --- a/bdep/config.cxx +++ b/bdep/config.cxx @@ -18,6 +18,7 @@ namespace bdep dir_path path, optional<string> name, optional<bool> def, + optional<bool> fwd, optional<uint64_t> id, const char* what) { @@ -27,19 +28,32 @@ namespace bdep transaction t (db.begin ()); using count = configuration_count; - using query = bdep::query<count>; - // By default the first added configuration is the default. - // - if (!def) - def = (db.query_value<count> () == 0); - else if (*def) { using query = bdep::query<configuration>; - if (auto p = db.query_one<configuration> (query::default_)) - fail << "configuration " << *p << " is already the default" << - info << "use 'bdep config set --no-default' to clear"; + // By default the first added configuration is the default. + // + if (!def) + def = (db.query_value<count> () == 0); + else if (*def) + { + if (auto p = db.query_one<configuration> (query::default_)) + fail << "configuration " << *p << " is already the default" << + info << "use 'bdep config set --no-default' to clear"; + } + + // By default the default configuration is forwarded unless another + // is already forwarded. + // + if (!fwd) + fwd = *def && db.query_one<configuration> (query::forward) == nullptr; + else if (*fwd) + { + if (auto p = db.query_one<configuration> (query::forward)) + fail << "configuration " << *p << " is already forwarded" << + info << "use 'bdep config set --no-forward' to clear"; + } } // Make sure the configuration path is absolute and normalized. Also @@ -58,6 +72,7 @@ namespace bdep path, move (rel_path), *def, + *fwd, {} /* packages */}); try @@ -66,6 +81,8 @@ namespace bdep } catch (const odb::exception&) { + using query = bdep::query<count>; + // See if this is id, name, or path conflict. // if (id && db.query_value<count> (query::id == *id) != 0) @@ -94,6 +111,7 @@ namespace bdep if (r->name) dr << '@' << *r->name << ' '; /* */ dr << r->path << " (" << *r->id; if (r->default_) dr << ", default"; + if (r->forward) dr << ", forwarded"; /* */ dr << ')'; } @@ -114,6 +132,7 @@ namespace bdep cli::scanner& cfg_args, optional<string> name, optional<bool> def, + optional<bool> fwd, optional<uint64_t> id) { // Call bpkg to create the configuration. @@ -131,6 +150,7 @@ namespace bdep move (path), move (name), def, + fwd, id, "created"); } @@ -159,6 +179,25 @@ namespace bdep fail << "@@ TODO" << endf; } + const char* + cmd_config_validate_add (const configuration_add_options& o) + { + // --[no-]default + // + if (o.default_ () && o.no_default ()) + fail << "both --default and --no-default specified"; + + // --[no-]forward + // + if (o.forward () && o.no_forward ()) + fail << "both --forward and --no-forward specified"; + + return (o.default_ () ? "--default" : + o.forward () ? "--forward" : + o.no_default () ? "--no-default" : + o.no_forward () ? "--no-forward" : nullptr); + } + int cmd_config (const cmd_config_options& o, cli::scanner& scan) { @@ -171,14 +210,7 @@ namespace bdep // Validate options/subcommands. // - - // --[no-]default - // - if (o.default_ () && o.no_default ()) - fail << "both --default and --no-default specified"; - - if (const char* n = (o.default_ () ? "--default" : - o.no_default () ? "--no-default" : nullptr)) + if (const char* n = cmd_config_validate_add (o)) { if (!(c.add () || c.create () || c.set ())) fail << n << " not valid for this command"; diff --git a/bdep/config.hxx b/bdep/config.hxx index 2ebda45..b521bac 100644 --- a/bdep/config.hxx +++ b/bdep/config.hxx @@ -19,6 +19,7 @@ namespace bdep dir_path path, optional<string> name, optional<bool> default_ = nullopt, + optional<bool> forward = nullopt, optional<uint64_t> id = nullopt, const char* what = "added"); @@ -30,10 +31,16 @@ namespace bdep cli::scanner& args, optional<string> name, optional<bool> default_ = nullopt, + optional<bool> forward = nullopt, optional<uint64_t> id = nullopt); int cmd_config (const cmd_config_options&, cli::scanner& args); + + // Validate returning one of the options or NULL if none specified. + // + const char* + cmd_config_validate_add (const configuration_add_options&); } #endif // BDEP_CONFIG_HXX diff --git a/bdep/init.cli b/bdep/init.cli index c72e4c3..57b1abb 100644 --- a/bdep/init.cli +++ b/bdep/init.cli @@ -137,7 +137,7 @@ namespace bdep " } - class cmd_init_options: project_options + class cmd_init_options: configuration_add_options, project_options { "\h|INIT OPTIONS|" @@ -157,19 +157,5 @@ namespace bdep "<dir>", "Create a new build configuration in <dir>." } - - bool --default - { - "Make the added or created configuration the default. Only valid with - \cb{--config-add} or \cb{--config-create}, see \l{bdep-config(1)} for - details." - } - - bool --no-default - { - "Don't make the first added or created configuration then default. Only - valid with \cb{--config-add} or \cb{--config-create}, see - \l{bdep-config(1)} for details." - } }; } diff --git a/bdep/init.cxx b/bdep/init.cxx index 49a2de4..1875c42 100644 --- a/bdep/init.cxx +++ b/bdep/init.cxx @@ -24,7 +24,8 @@ namespace bdep cli::scanner& args, bool ca, bool cc, - optional<bool> cd) + optional<bool> cd, + optional<bool> cf) { const char* m (!ca ? "--config-create" : !cc ? "--config-add" : nullptr); @@ -32,13 +33,13 @@ namespace bdep if (m == nullptr) fail << "both --config-add and --config-create specified"; - optional<string> name; + optional<string> nm; if (size_t n = o.config_name ().size ()) { if (n > 1) fail << "multiple configuration names specified for " << m; - name = o.config_name ()[0]; + nm = o.config_name ()[0]; } optional<uint64_t> id; @@ -51,8 +52,8 @@ namespace bdep } return ca - ? cmd_config_add ( prj, db, cfg, move (name), cd, move (id)) - : cmd_config_create (o, prj, db, cfg, args, move (name), cd, move (id)); + ? cmd_config_add ( prj, db, cfg, move (nm), cd, cf, move (id)) + : cmd_config_create (o, prj, db, cfg, args, move (nm), cd, cf, move (id)); } void @@ -128,24 +129,18 @@ namespace bdep bool ca (o.config_add_specified ()); bool cc (o.config_create_specified ()); - optional<bool> cd; - if (o.default_ () || o.no_default ()) - { - if (!ca && !cc) - fail << "--[no-]default specified without --config-(add|create)"; - - if (o.default_ () && o.no_default ()) - fail << "both --default and --no-default specified"; - - cd = o.default_ () && !o.no_default (); - } - if (o.empty ()) { if (ca) fail << "both --empty and --config-add specified"; if (cc) fail << "both --empty and --config-create specified"; } + if (const char* n = cmd_config_validate_add (o)) + { + if (!ca && !cc) + fail << n << " specified without --config-(add|create)"; + } + project_packages pp ( find_project_packages (o, o.empty () /* ignore_packages */)); @@ -186,6 +181,14 @@ namespace bdep configurations cfgs; if (ca || cc) { + optional<bool> cd; + if (o.default_ () || o.no_default ()) + cd = o.default_ () && !o.no_default (); + + optional<bool> cf; + if (o.forward () || o.no_forward ()) + cf = o.forward () && !o.no_forward (); + cfgs.push_back ( cmd_init_config ( o, @@ -195,7 +198,8 @@ namespace bdep args, ca, cc, - cd)); + cd, + cf)); // Fall through. } diff --git a/bdep/init.hxx b/bdep/init.hxx index 7905306..6e52737 100644 --- a/bdep/init.hxx +++ b/bdep/init.hxx @@ -23,7 +23,8 @@ namespace bdep cli::scanner& cfg_args, bool config_add_specified, bool config_create_specified, - optional<bool> config_default); + optional<bool> config_default, + optional<bool> config_forward); // Initialize each package in each configuration skipping those that are // already initialized. Then synchronize each configuration. diff --git a/bdep/new.cli b/bdep/new.cli index 377dbec..f5f2a14 100644 --- a/bdep/new.cli +++ b/bdep/new.cli @@ -145,7 +145,7 @@ namespace bdep { }; - class cmd_new_options: configuration_name_options + class cmd_new_options: configuration_add_options, configuration_name_options { "\h|NEW OPTIONS|" @@ -189,19 +189,5 @@ namespace bdep \cb{git} (default) and \cb{none}. Valid values for <opt> are system-specific." } - - bool --default - { - "Make the added or created configuration the default. Only valid with - \cb{--config-add} or \cb{--config-create}, see \l{bdep-config(1)} for - details." - } - - bool --no-default - { - "Don't make the first added or created configuration then default. Only - valid with \cb{--config-add} or \cb{--config-create}, see - \l{bdep-config(1)} for details." - } }; } diff --git a/bdep/new.cxx b/bdep/new.cxx index 97c8352..5f99e6c 100644 --- a/bdep/new.cxx +++ b/bdep/new.cxx @@ -9,6 +9,7 @@ #include <bdep/diagnostics.hxx> #include <bdep/init.hxx> +#include <bdep/config.hxx> using namespace std; @@ -26,24 +27,18 @@ namespace bdep bool ca (o.config_add_specified ()); bool cc (o.config_create_specified ()); - optional<bool> cd; - if (o.default_ () || o.no_default ()) - { - if (!ca && !cc) - fail << "--[no-]default specified without --config-(add|create)"; - - if (o.default_ () && o.no_default ()) - fail << "both --default and --no-default specified"; - - cd = o.default_ () && !o.no_default (); - } - if (o.no_init ()) { if (ca) fail << "both --no-init and --config-add specified"; if (cc) fail << "both --no-init and --config-create specified"; } + if (const char* n = cmd_config_validate_add (o)) + { + if (!ca && !cc) + fail << n << " specified without --config-(add|create)"; + } + // Validate type options. // const type& t (o.type ()); @@ -621,6 +616,14 @@ namespace bdep if (ca || cc) { + optional<bool> cd; + if (o.default_ () || o.no_default ()) + cd = o.default_ () && !o.no_default (); + + optional<bool> cf; + if (o.forward () || o.no_forward ()) + cf = o.forward () && !o.no_forward (); + configurations cfgs { cmd_init_config ( o, @@ -630,7 +633,8 @@ namespace bdep args, ca, cc, - cd)}; + cd, + cf)}; package_locations pkgs {{n, dir_path ()}}; // project == package diff --git a/bdep/project.cli b/bdep/project.cli index 15faea8..137c77d 100644 --- a/bdep/project.cli +++ b/bdep/project.cli @@ -8,6 +8,31 @@ include <bdep/common.cli>; namespace bdep { + // Common options for commands that add/create configurations. + // + class configuration_add_options + { + bool --default + { + "Make the added or created configuration the default." + } + + bool --no-default + { + "Don't make the first added or created configuration then default." + } + + bool --forward + { + "Make the added or created configuration forwarded." + } + + bool --no-forward + { + "Don't make the added or created configuration forwarded." + } + }; + // Common options for commands that accept --config-id and @<cfg-name>. // class configuration_name_options: common_options diff --git a/bdep/project.cxx b/bdep/project.cxx index 6b5ee30..8d922b6 100644 --- a/bdep/project.cxx +++ b/bdep/project.cxx @@ -110,7 +110,7 @@ namespace bdep return r; } - // Given a directory which can a project root, a package root, or one of + // Given a directory which can be a project root, a package root, or one of // their subdirectories, return the absolute project (first) and relative // package (second) directories. The package directory may be absent if the // given directory is not within a package root or empty if the project and @@ -186,6 +186,69 @@ namespace bdep return project_package {move (prj), move (pkg)}; } + static package_locations + load_package_locations (const dir_path& prj) + { + package_locations pls; + + // If exists, load packages.manifest from the project root. Otherwise, + // this must be a simple, single-package project. + // + path f (prj / packages_file); + + if (exists (f)) + { + using bpkg::package_manifest; + using bpkg::dir_package_manifests; + + auto ms (parse_manifest<dir_package_manifests> (f, "packages")); + + // While an empty repository is legal, in our case it doesn't make much + // sense and will just further complicate things. + // + if (ms.empty ()) + fail << "no packages listed in " << f; + + for (package_manifest& m: ms) + { + // Convert the package location from POSIX to the host form and make + // sure the current directory is represented as an empty path. + // + assert (m.location); + dir_path d (path_cast<dir_path> (move (*m.location))); + d.normalize (false /* actualize */, true /* cur_empty */); + + pls.push_back (package_location {string (), move (d)}); + } + } + else + pls.push_back (package_location {string (), dir_path ()}); + + return pls; + } + + static void + load_package_names (const dir_path& prj, package_locations& pls) + { + // Load each package's manifest and obtain its name (name is normally the + // first value so we could optimize this, if necessary). + // + for (package_location& pl: pls) + { + path f (prj / pl.path / manifest_file); + auto m (parse_manifest<bpkg::package_manifest> (f, "package")); + pl.name = move (m.name); + } + } + + package_locations + load_packages (const dir_path& prj) + { + package_locations pls (load_package_locations (prj)); + load_package_names (prj, pls); + return pls; + } + project_packages find_project_packages (const project_options& po, bool ignore_packages, @@ -246,82 +309,37 @@ namespace bdep if (!ignore_packages) { - // If exists, load packages.manifest from the project root and either - // verify that the discovered packages are in it or, if nothing was - // discovered, use it as the source for the package list. + // Load the package locations and either verify that the discovered + // packages are in it or, if nothing was discovered, use it as the + // source for the package list. // - path f (r.project / packages_file); + package_locations pls (load_package_locations (r.project)); - if (exists (f)) + if (!r.packages.empty ()) { - using bpkg::package_manifest; - using bpkg::dir_package_manifests; - - auto ms (parse_manifest<dir_package_manifests> (f, "packages")); - - // While an empty repository is legal, in our case it doesn't make - // much sense and will just further complicate things. - // - if (ms.empty ()) - fail << "no packages listed in " << f; - - // Convert the package location from POSIX to the host form and make - // sure the current directory is represented as an empty path. - // - auto location = [] (const package_manifest& m) + for (const package_location& x: r.packages) { - assert (m.location); - dir_path d (path_cast<dir_path> (*m.location)); - d.normalize (false /* actualize */, true /* cur_empty */); - return d; - }; - - if (!r.packages.empty ()) - { - // It could be costly to normalize the location for each - // comparison. We, however, do not expect more than a handful of - // packages so we are probably ok. - // - for (const package_location& pl: r.packages) + if (find_if (pls.begin (), + pls.end (), + [&x] (const package_location& y) + { + return x.path == y.path; + }) == pls.end ()) { - const dir_path& p (pl.path); - - if (find_if (ms.begin (), - ms.end (), - [&p, &location] (const package_manifest& m) - { - return p == location (m); - }) == ms.end ()) - { - fail << "package directory " << p << " is not listed in " << f; - } + fail << "package directory " << x.path << " is not listed in " + << r.project; } } - else if (load_packages) - { - // Name is to be extracted later. - // - for (package_manifest& m: ms) - r.packages.push_back (package_location {"", location (m)}); - } } - else + else if (load_packages) { - // If packages.manifest does not exist, then this must be a simple - // project. + // Names to be extracted later. // - assert (r.packages.size () == 1 && r.packages[0].path.empty ()); + r.packages = move (pls); } - // Load each package's manifest and obtain its name (name is normally - // the first value so we could optimize this, if necessary). - // - for (package_location& pl: r.packages) - { - path f (r.project / pl.path / manifest_file); - auto m (parse_manifest<bpkg::package_manifest> (f, "package")); - pl.name = move (m.name); - } + if (!r.packages.empty ()) + load_package_names (r.project, r.packages); } return r; diff --git a/bdep/project.hxx b/bdep/project.hxx index 2b1894c..2e8d366 100644 --- a/bdep/project.hxx +++ b/bdep/project.hxx @@ -78,6 +78,7 @@ namespace bdep optional_dir_path relative_path; bool default_; + bool forward; // We made it a vector instead of set/map since we are unlikely to have // more than a handful of packages. We may, however, want to use a change- @@ -162,6 +163,9 @@ namespace bdep using package_locations = vector<package_location>; + package_locations + load_packages (const dir_path& prj); + struct project_packages { dir_path project; diff --git a/bdep/project.xml b/bdep/project.xml index 5685945..8d1bf26 100644 --- a/bdep/project.xml +++ b/bdep/project.xml @@ -6,6 +6,7 @@ <column name="path" type="TEXT" null="true"/> <column name="relative_path" type="TEXT" null="true"/> <column name="default" type="INTEGER" null="true"/> + <column name="forward" type="INTEGER" null="true"/> <primary-key auto="true"> <column name="id"/> </primary-key> diff --git a/bdep/sync.cxx b/bdep/sync.cxx index 370e4f4..6c29a50 100644 --- a/bdep/sync.cxx +++ b/bdep/sync.cxx @@ -70,7 +70,7 @@ namespace bdep }) != prj_pkgs.end ()) { // The project package itself must always be upgraded to the latest - // version/iteration. So we have to translate our option to their + // version/iteration. So we have to translate our options to their // dependency-only --{upgrade,patch}-{recursive,immediate}. // args.push_back ("{"); @@ -119,6 +119,82 @@ namespace bdep "--plan", "synchronizing:", (yes ? "--yes" : nullptr), args); + + + // Handle configuration forwarding. + // + // We do it here (instead of, say init) because a change in a package may + // introduce new subprojects. Though it would be nice to only do this if + // the package was upgraded (probably by comparing before/after versions + // @@ TODO: changed flag below). + // + // Also, the current thinking is that config set --[no-]forward is best + // implemented by just changing the flag on the configuration and then + // requiring an explicit sync to configure/disfigure forwards. + // + // @@ TODO: could optimize out version query/comparison if pkg-build + // signalled that nothing has changed (the --exit-result idea). Would + // be nice to optimize the whole thing. Maybe --force flag (for things + // like config set --no-forward)? Or maybe we should require explicit + // sync for certain changes (and pass --implicit or some such in hook + // -- after all, configuring forward of a project being bootstrapped + // might get tricky). + // + package_locations pls (load_packages (prj)); + + for (const package_state& p: c->packages) + { + // If this is a forwarded configuration, make sure forwarding is + // configured and is up-to-date. Otherwise, make sure it is disfigured + // (the config set --no-forward case). + // + dir_path src (prj); + { + auto i (find_if (pls.begin (), + pls.end (), + [&p] (const package_location& pl) + { + return p.name == pl.name; + })); + + if (i == pls.end ()) + fail << "package " << p.name << " is not listed in " << prj; + + src /= i->path; + } + + // We could run 'b info' and used the 'forwarded' value but this is + // both faster and simpler. + // + path f (src / "build" / "bootstrap" / "out-root.build"); + bool e (exists (f)); + + const char* o (nullptr); + if (c->forward) + { + bool changed (true); + + if (changed || !e) + o = "configure:"; + } + else + { + //@@ This is broken: we will disfigure forwards to other configs. + // Looks like we will need to test that the forward is to this + // config. 'b info' here we come? + + //if (e) + // o = "disfigure:"; + } + + if (o != nullptr) + { + dir_path out (dir_path (c->path) /= p.name); + string arg (src.representation () + '@' + out.representation () + + ",forward"); + run_b (co, o, arg); + } + } } void diff --git a/bdep/utility.cxx b/bdep/utility.cxx index f8ef1df..a902273 100644 --- a/bdep/utility.cxx +++ b/bdep/utility.cxx @@ -107,4 +107,12 @@ namespace bdep ? co.bpkg ().string ().c_str () : "bpkg" BDEP_EXE_SUFFIX; } + + const char* + name_b (const common_options& co) + { + return co.build_specified () + ? co.build ().string ().c_str () + : "b" BDEP_EXE_SUFFIX; + } } diff --git a/bdep/utility.hxx b/bdep/utility.hxx index 4831bab..31cd0cb 100644 --- a/bdep/utility.hxx +++ b/bdep/utility.hxx @@ -114,6 +114,19 @@ namespace bdep void run_bpkg (const common_options&, A&&... args); + // Run the b process. + // + const char* + name_b (const common_options&); + + template <typename O, typename E, typename... A> + process + start_b (const common_options&, O&& out, E&& err, A&&... args); + + template <typename... A> + void + run_b (const common_options&, A&&... args); + // Manifest parsing and serialization. // // For parsing, if path is '-', then read from stdin. diff --git a/bdep/utility.txx b/bdep/utility.txx index 2d6de1d..aa75952 100644 --- a/bdep/utility.txx +++ b/bdep/utility.txx @@ -144,6 +144,81 @@ namespace bdep } } + // *_b() + // + template <typename O, typename E, typename... A> + process + start_b (const common_options& co, + O&& out, + E&& err, + A&&... args) + { + const char* b (name_b (co)); + + try + { + process_path pp (process::path_search (b, exec_dir)); + + small_vector<const char*, 1> ops; + + // Map verbosity level. If we are running quiet or at level 1, then run + // b quiet. Otherwise, run it at the same level as us. + // + bool quiet (true); // Maybe will become an argument one day. + + string vl; + switch (verb) + { + case 0: ops.push_back ("-q"); break; + case 1: if (quiet) ops.push_back ("-q"); break; + case 2: ops.push_back ("-v"); break; + default: + { + vl = to_string (verb); + ops.push_back ("--verbose"); + ops.push_back (vl.c_str ()); + } + } + + return process_start_callback ( + [] (const char* const args[], size_t n) + { + if (verb >= 2) + print_process (args, n); + }, + 0 /* stdin */, + forward<O> (out), + forward<E> (err), + pp, + ops, + co.build_option (), + forward<A> (args)...); + } + catch (const process_error& e) + { + fail << "unable to execute " << b << ": " << e << endf; + } + } + + template <typename... A> + void + run_b (const common_options& co, A&&... args) + { + process pr (start_b (co, + 1 /* stdout */, + 2 /* stderr */, + forward<A> (args)...)); + if (!pr.wait ()) + { + const process_exit& e (*pr.exit); + + if (e.normal ()) + throw failed (); // Assume the child issued diagnostics. + + fail << "process " << name_b (co) << " " << e; + } + } + // *_manifest() // template <typename T> @@ -39,6 +39,7 @@ function compile () cli -I .. -v project="bdep" -v version="$version" -v date="$date" \ --include-base-last "${o[@]}" --generate-html --html-prologue-file \ man-prologue.xhtml --html-epilogue-file man-epilogue.xhtml --html-suffix .xhtml \ +--link-regex '%b([-.].+)%../../build2/doc/b$1%' \ --link-regex '%bpkg([-.].+)%../../bpkg/doc/bpkg$1%' \ --link-regex '%bpkg(#.+)?%../../bpkg/doc/build2-package-manager-manual.xhtml$1%' \ --link-regex '%bdep(#.+)?%build2-project-manager-manual.xhtml$1%' \ |