aboutsummaryrefslogtreecommitdiff
path: root/bpkg/cfg-create.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bpkg/cfg-create.cxx')
-rw-r--r--bpkg/cfg-create.cxx212
1 files changed, 170 insertions, 42 deletions
diff --git a/bpkg/cfg-create.cxx b/bpkg/cfg-create.cxx
index 355690a..f125e43 100644
--- a/bpkg/cfg-create.cxx
+++ b/bpkg/cfg-create.cxx
@@ -8,29 +8,72 @@
#include <bpkg/database.hxx>
#include <bpkg/diagnostics.hxx>
+#include <bpkg/cfg-link.hxx>
+
using namespace std;
+using namespace butl;
namespace bpkg
{
- int
- cfg_create (const cfg_create_options& o, cli::scanner& args)
+ shared_ptr<configuration>
+ cfg_create (const common_options& o,
+ const dir_path& c,
+ optional<string> name,
+ string type,
+ const strings& mods,
+ const strings& vars,
+ bool existing,
+ bool wipe,
+ optional<uuid> uid,
+ const optional<dir_path>& host_config,
+ const optional<dir_path>& 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<dir_path> hc (host_config
+ ? norm (*host_config, host_config_type)
+ : optional<dir_path> ());
+
+ optional<dir_path> bc (build2_config
+ ? norm (*build2_config, build2_config_type)
+ : optional<dir_path> ());
// 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 +92,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 +108,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";
@@ -99,7 +122,7 @@ namespace bpkg
{
// Assemble the build2 create meta-operation parameters.
//
- string params ("'" + c.representation () + "'");
+ string params ('\'' + c.representation () + '\'');
if (!mods.empty ())
{
params += ',';
@@ -112,15 +135,35 @@ namespace bpkg
// Run quiet. Use path representation to get canonical trailing slash.
//
- run_b (o, verb_b::quiet, vars, "create(" + params + ")");
+ run_b (o, verb_b::quiet, vars, "create(" + params + ')');
}
// Create .bpkg/ and its subdirectories.
//
{
- mk (c / bpkg_dir);
+ dir_path d (c / bpkg_dir);
+
+ mk (d);
mk (c / certs_dir);
mk (c / repos_dir);
+
+ // Create the .gitignore file that ignores everything under .bpkg/
+ // effectively making git ignore it (this prevents people from
+ // accidentally adding this directory to a git repository).
+ //
+ path f (d / ".gitignore");
+ try
+ {
+ ofdstream os (f);
+ os << "# This directory should not be version-controlled." << '\n'
+ << "#" << '\n'
+ << "*" << '\n';
+ os.close ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to write to " << f << ": " << e;
+ }
}
// Initialize tmp directory.
@@ -129,7 +172,20 @@ namespace bpkg
// Create the database.
//
- database db (open (c, trace, true));
+ shared_ptr<configuration> r (make_shared<configuration> (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
@@ -141,31 +197,103 @@ namespace bpkg
// locations and as a search starting point for held packages (see
// pkg-build for details).
//
- transaction t (db);
-
shared_ptr<repository_fragment> fr (
make_shared<repository_fragment> (repository_location ()));
db.persist (fr);
- shared_ptr<repository> r (
+ shared_ptr<repository> rep (
make_shared<repository> (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 (trim (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<configuration> cf (
+ cfg_create (
+ o,
+ c,
+ o.name_specified () ? o.name () : optional<string> (),
+ o.type (),
+ mods,
+ vars,
+ o.existing (),
+ o.wipe (),
+ o.uuid_specified () ? o.uuid () : optional<uuid> (),
+ (o.host_config_specified () && !o.no_host_config ()
+ ? o.host_config ()
+ : optional<dir_path> ()),
+ (o.build2_config_specified () && !o.no_build2_config ()
+ ? o.build2_config ()
+ : optional<dir_path> ())));
+
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 << '\n';
else
- text << "created new configuration in " << c;
+ dr << "created new configuration in " << c << '\n';
+
+ dr << " uuid: " << cf->uuid << '\n'
+ << " type: " << cf->type;
+
+ if (cf->name)
+ dr << "\n name: " << *cf->name;
}
return 0;