From 4d181c3aad97f8ee224666ce5c757036c5f610d5 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 12 Mar 2018 09:41:09 +0200 Subject: Store initialized packages for each configuration in database --- bdep/config.cxx | 3 ++- bdep/init.cxx | 51 ++++++++++++++++++++++++++++++++++++++++++------ bdep/odb.sh | 4 ++-- bdep/project.cxx | 43 ++++++++++++++++++++++++++++++----------- bdep/project.hxx | 59 ++++++++++++++++++++++++++++++++++++++++++++++++-------- bdep/project.xml | 17 ++++++++++++++++ bdep/utility.hxx | 2 +- bdep/utility.txx | 15 +++++++------- 8 files changed, 158 insertions(+), 36 deletions(-) diff --git a/bdep/config.cxx b/bdep/config.cxx index f7d74ed..1e646a3 100644 --- a/bdep/config.cxx +++ b/bdep/config.cxx @@ -48,7 +48,8 @@ namespace bdep name, path, move (rel_path), - *def}); + *def, + {} /* packages */}); try { diff --git a/bdep/init.cxx b/bdep/init.cxx index 44eb37e..1e864eb 100644 --- a/bdep/init.cxx +++ b/bdep/init.cxx @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -24,8 +25,8 @@ namespace bdep const dir_path& prj (pp.project); text << prj; - for (const dir_path& d: pp.packages) - text << " " << (prj / d); + for (const package_location& pl: pp.packages) + text << " " << pl.name << " " << (prj / pl.path); // Create .bdep/. // @@ -103,17 +104,55 @@ namespace bdep // Fall through. } - transaction t (db.begin ()); - // If this is the default mode, then find the configurations the user // wants us to use. // if (cfgs.empty ()) + { + transaction t (db.begin ()); cfgs = find_configurations (prj, t, o); + t.commit (); + } - //@@ TODO: print project/package(s) being initialized. + // Initialize each package in each configuration skipping those that are + // already initialized. Do each configuration in a separate transaction so + // that our state reflects the bpkg configuration as closely as possible. + // + for (const shared_ptr& c: cfgs) + { + transaction t (db.begin ()); + + // Add project repository to the configuration. Note that we don't fetch + // it since sync is going to do it anyway. + // + run_bpkg (o, + "add", + "-d", c->path, + "--type", "dir", + prj); + + for (const package_location& p: pp.packages) + { + if (find_if (c->packages.begin (), + c->packages.end (), + [&p] (const package_state& s) + { + return p.name == s.name; + }) != c->packages.end ()) + { + info << "package " << p.name << " is already initialized " + << "in configuration " << *c; + continue; + } + + c->packages.push_back (package_state {p.name}); + } - t.commit (); + db.update (c); + t.commit (); + } + + //@@ TODO: print project/package(s) being initialized. return 0; } diff --git a/bdep/odb.sh b/bdep/odb.sh index 4bd83b5..07c744a 100755 --- a/bdep/odb.sh +++ b/bdep/odb.sh @@ -11,7 +11,7 @@ lib="\ $odb $lib -I.. -I../../libbpkg -I../../libbutl \ -DLIBODB_BUILD2 -DLIBODB_SQLITE_BUILD2 --generate-schema \ - -d sqlite --std c++11 --generate-query \ + -d sqlite --std c++14 --generate-query \ --odb-epilogue '#include ' \ --hxx-prologue '#include ' \ --include-with-brackets --include-prefix bdep --guard-prefix BDEP \ @@ -19,7 +19,7 @@ $odb $lib -I.. -I../../libbpkg -I../../libbutl \ $odb $lib -I.. -I../../libbpkg -I../../libbutl \ -DLIBODB_BUILD2 -DLIBODB_SQLITE_BUILD2 \ - -d sqlite --std c++11 --generate-query \ + -d sqlite --std c++14 --generate-query \ --odb-epilogue '#include ' \ --hxx-prologue '#include ' \ --include-with-brackets --include-prefix bdep --guard-prefix BDEP \ diff --git a/bdep/project.cxx b/bdep/project.cxx index 84b7acd..d3e3f11 100644 --- a/bdep/project.cxx +++ b/bdep/project.cxx @@ -208,11 +208,16 @@ namespace bdep { // Suppress duplicate packages. // - if (find (r.packages.begin (), - r.packages.end (), - *p.package) == r.packages.end ()) + if (find_if (r.packages.begin (), + r.packages.end (), + [&p] (const package_location& pl) + { + return *p.package == pl.path; + }) == r.packages.end ()) { - r.packages.push_back (move (*p.package)); + // Name is to be extracted later. + // + r.packages.push_back (package_location {"", move (*p.package)}); } } } @@ -225,7 +230,9 @@ namespace bdep if (!ignore_packages && p.package) { - r.packages.push_back (move (*p.package)); + // Name is to be extracted later. + // + r.packages.push_back (move (package_location {"", *p.package})); } } @@ -263,8 +270,10 @@ namespace bdep if (r.packages.empty ()) { + // Name is to be extracted later. + // for (package_manifest& m: ms) - r.packages.push_back (location (m)); + r.packages.push_back (package_location {"", location (m)}); } else { @@ -272,16 +281,18 @@ namespace bdep // comparison. We, however, do not expect more than a handful of // packages so we are probably ok. // - for (const dir_path& pd: r.packages) + for (const package_location& pl: r.packages) { + const dir_path& p (pl.path); + if (find_if (ms.begin (), ms.end (), - [&pd, &location] (const package_manifest& m) + [&p, &location] (const package_manifest& m) { - return pd == location (m); + return p == location (m); }) == ms.end ()) { - fail << "package directory " << pd << " not listed in " << f; + fail << "package directory " << p << " is not listed in " << f; } } } @@ -291,7 +302,17 @@ namespace bdep // If packages.manifest does not exist, then this must be a simple // project. // - assert (r.packages.size () == 1 && r.packages[0].empty ()); + assert (r.packages.size () == 1 && r.packages[0].path.empty ()); + } + + // 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 (f, "package")); + pl.name = move (m.name); } } diff --git a/bdep/project.hxx b/bdep/project.hxx index 42f520a..2d0d3f1 100644 --- a/bdep/project.hxx +++ b/bdep/project.hxx @@ -36,13 +36,28 @@ namespace bdep to((?) ? (?)->string () : bdep::optional_string ()) \ from((?) ? bdep::dir_path (*(?)) : bdep::optional_dir_path ()) - //@@ TODO: do we need session/shared_ptr? + // State of a package in a configuration. + // + // Pretty much everything about the package can change (including location + // within the project) with the only immutable data being its name (even the + // version in the manifest could be bogus without the fix-up). As a result, + // that't the only thing we store in the database with everything else (like + // location) always loaded from the manifest on each run. We may, however, + // need to store some additional state (like manifest hash to speed up noop + // syncs) in the future. + // + #pragma db value + struct package_state + { + string name; + }; + // Configuration associated with a project. + // #pragma db object pointer(shared_ptr) session class configuration { public: - // The configuration stores an absolute and normalized path to the bpkg // configuration. It may also have a name. A configuration can be moved or // renamed so we also have the id (it is NULL'able so that we can assign @@ -62,11 +77,18 @@ namespace bdep bool default_; + // 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- + // tracking vector later (e.g., to optimize updates). + // + vector packages; + // Database mapping. // #pragma db member(id) id auto #pragma db member(name) unique #pragma db member(path) unique + #pragma db member(packages) value_column("") // Make path comparison case-insensitive for certain platforms. // @@ -85,6 +107,19 @@ namespace bdep configuration () = default; }; + // Print configuration name if available and path otherwise. + // + inline ostream& + operator<< (ostream& os, const configuration& c) + { + if (c.name) + os << '@' << *c.name; + else + os << c.path; + + return os; + } + #pragma db view object(configuration) struct configuration_count { @@ -106,17 +141,25 @@ namespace bdep const project_options&); // Given the project options (and CWD) locate the packages and their - // project. The result is the absolute and normalized project directory and - // a vector of relative (to the project directory) package directories - // (which will be empty if ignore_packages is true). + // project. The result is an absolute and normalized project directory and a + // vector of relative (to the project directory) package locations (which + // will be empty if ignore_packages is true). // // Note that if the package directory is the same as project, then the - // package directory will be empty (and not ./). + // package path will be empty (and not ./). // + struct package_location + { + string name; + dir_path path; + }; + + using package_locations = vector; + struct project_packages { - dir_path project; - dir_paths packages; + dir_path project; + package_locations packages; }; project_packages diff --git a/bdep/project.xml b/bdep/project.xml index cf8d2c7..5685945 100644 --- a/bdep/project.xml +++ b/bdep/project.xml @@ -16,5 +16,22 @@ + + + + + + + + + + + + + + + + +
diff --git a/bdep/utility.hxx b/bdep/utility.hxx index 36a405c..d8a4983 100644 --- a/bdep/utility.hxx +++ b/bdep/utility.hxx @@ -100,7 +100,7 @@ namespace bdep start_bpkg (const common_options&, O&& out, E&& err, A&&... args); template - process_exit + void run_bpkg (const common_options&, A&&... args); // Manifest parsing and serialization. diff --git a/bdep/utility.txx b/bdep/utility.txx index 52bbfdb..b796f69 100644 --- a/bdep/utility.txx +++ b/bdep/utility.txx @@ -32,7 +32,7 @@ namespace bdep // Map verbosity level. If we are running quiet or at level 1, then run // bpkg quiet. Otherwise, run it at the same level as us. // - bool quiet (false); // Maybe will become an argument one day. + bool quiet (true); // Maybe will become an argument one day. string vl; if (verb <= (quiet ? 1 : 0)) ops.push_back ("-q"); @@ -80,21 +80,22 @@ namespace bdep } template - process_exit + void run_bpkg (const common_options& co, A&&... args) { process pr (start_bpkg (co, 1 /* stdout */, 2 /* stderr */, forward (args)...)); - pr.wait (); + if (!pr.wait ()) + { + const process_exit& e (*pr.exit); - const process_exit& e (*pr.exit); + if (e.normal ()) + throw failed (); // Assume the child issued diagnostics. - if (!e.normal ()) fail << "process " << name_bpkg (co) << " " << e; - - return e; + } } // *_manifest() -- cgit v1.1