From 5d513688ae07d96910dd1eef83bdad4e9d780373 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 22 Apr 2021 21:57:13 +0300 Subject: Add support for linked configurations --- bpkg/cfg-create.cxx | 185 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 146 insertions(+), 39 deletions(-) (limited to 'bpkg/cfg-create.cxx') diff --git a/bpkg/cfg-create.cxx b/bpkg/cfg-create.cxx index f3ca80d..1757e9c 100644 --- a/bpkg/cfg-create.cxx +++ b/bpkg/cfg-create.cxx @@ -8,29 +8,71 @@ #include #include +#include + using namespace std; namespace bpkg { - int - cfg_create (const cfg_create_options& o, cli::scanner& args) + shared_ptr + cfg_create (const common_options& o, + const dir_path& c, + optional name, + string type, + const strings& mods, + const strings& vars, + bool existing, + bool wipe, + optional uid, + const optional& host_config, + const optional& build2_config) { tracer trace ("cfg_create"); - if (o.existing () && o.wipe ()) - fail << "both --existing|-e and --wipe specified"; + // Stash and restore the current transaction, if any. + // + namespace sqlite = odb::sqlite; - if (o.wipe () && !o.directory_specified ()) - fail << "--wipe requires explicit --directory|-d"; + sqlite::transaction* ct (nullptr); + if (sqlite::transaction::has_current ()) + { + ct = &sqlite::transaction::current (); + sqlite::transaction::reset_current (); + } - dir_path c (o.directory ()); - l4 ([&]{trace << "creating configuration in " << c;}); + auto tg (make_guard ([ct] () + { + if (ct != nullptr) + sqlite::transaction::current (*ct); + })); + + // First, let's verify the host/build2 configurations existence and types + // and normalize their paths. + // + auto norm = [&trace] (const dir_path& d, const string& t) + { + dir_path r (normalize (d, string (t + " configuration").c_str ())); + database db (r, trace, false /* pre_attach */); + if (db.type != t) + fail << t << " configuration " << r << " is of '" << db.type + << "' type"; + + return r; + }; + + optional hc (host_config + ? norm (*host_config, host_config_type) + : optional ()); + + optional bc (build2_config + ? norm (*build2_config, build2_config_type) + : optional ()); // Verify the existing directory is compatible with our mode. // if (exists (c)) { - if (o.existing ()) + if (existing) { // Bail if the .bpkg/ directory already exists and is not empty. // @@ -49,7 +91,7 @@ namespace bpkg // if (!empty (c)) { - if (!o.wipe ()) + if (!wipe) fail << "directory " << c << " is not empty" << info << "use --wipe to clean it up but be careful"; @@ -65,29 +107,9 @@ namespace bpkg mk_p (c); } - // Sort arguments into modules and configuration variables. - // - strings mods; - strings vars; - while (args.more ()) - { - string a (args.next ()); - - if (a.find ('=') != string::npos) - { - vars.push_back (move (a)); - } - else if (!a.empty ()) - { - mods.push_back (move (a)); - } - else - fail << "empty string as argument"; - } - // Create and configure. // - if (o.existing ()) + if (existing) { if (!mods.empty ()) fail << "module '" << mods[0] << "' specified with --existing|-e"; @@ -149,7 +171,20 @@ namespace bpkg // Create the database. // - database db (open (c, trace, true)); + shared_ptr r (make_shared (move (name), + move (type), + uid)); + + dir_paths pre_link; + + if (hc) + pre_link.push_back (*hc); + + if (bc) + pre_link.push_back (*bc); + + database db (c, r, trace, pre_link); + transaction t (db); // Add the special, root repository object with empty location and // containing a single repository fragment having an empty location as @@ -161,31 +196,103 @@ namespace bpkg // locations and as a search starting point for held packages (see // pkg-build for details). // - transaction t (db); - shared_ptr fr ( make_shared (repository_location ())); db.persist (fr); - shared_ptr r ( + shared_ptr rep ( make_shared (repository_location ())); - r->fragments.push_back ( + rep->fragments.push_back ( repository::fragment_type {string () /* friendly_name */, move (fr)}); - db.persist (r); + db.persist (rep); + + if (hc) + cfg_link (db, *hc, host_config->relative (), nullopt /* name */); + + if (bc) + cfg_link (db, *bc, build2_config->relative (), nullopt /* name */); t.commit (); + return r; + } + + int + cfg_create (const cfg_create_options& o, cli::scanner& args) + { + tracer trace ("cfg_create"); + + if (o.name_specified ()) + validate_configuration_name (o.name (), "--name option value"); + + if (o.type ().empty ()) + fail << "empty --type option value"; + + if (o.existing () && o.wipe ()) + fail << "both --existing|-e and --wipe specified"; + + if (o.wipe () && !o.directory_specified ()) + fail << "--wipe requires explicit --directory|-d"; + + dir_path c (o.directory ()); + l4 ([&]{trace << "creating configuration in " << c;}); + + // Sort arguments into modules and configuration variables. + // + strings mods; + strings vars; + while (args.more ()) + { + string a (args.next ()); + + if (a.find ('=') != string::npos) + vars.push_back (move (a)); + else if (!a.empty ()) + mods.push_back (move (a)); + else + fail << "empty string as argument"; + } + + // Auto-generate the configuration UUID, unless it is specified + // explicitly. + // + shared_ptr cf ( + cfg_create ( + o, + c, + o.name_specified () ? o.name () : optional (), + o.type (), + mods, + vars, + o.existing (), + o.wipe (), + o.config_uuid_specified () ? o.config_uuid () : optional (), + (o.host_config_specified () + ? o.host_config () + : optional ()), + (o.build2_config_specified () + ? o.build2_config () + : optional ()))); + if (verb && !o.no_result ()) { normalize (c, "configuration"); + diag_record dr (text); + if (o.existing ()) - text << "initialized existing configuration in " << c; + dr << "initialized existing configuration in " << c; else - text << "created new configuration in " << c; + dr << "created new configuration in " << c; + + dr << info << "uuid: " << cf->uuid + << info << "type: " << cf->type; + + if (cf->name) + dr << info << "name: " << *cf->name; } return 0; -- cgit v1.1