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/package.cxx | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 173 insertions(+), 15 deletions(-) (limited to 'bpkg/package.cxx') diff --git a/bpkg/package.cxx b/bpkg/package.cxx index 3532f3d..7995c34 100644 --- a/bpkg/package.cxx +++ b/bpkg/package.cxx @@ -15,17 +15,98 @@ namespace bpkg { const version wildcard_version (0, "0", nullopt, nullopt, 0); - // available_package_id + // configuration // - bool - operator< (const available_package_id& x, const available_package_id& y) + configuration:: + configuration (optional n, string t, optional uid) + : id (0), + name (move (n)), + type (move (t)), + expl (false) { - int r (x.name.compare (y.name)); - return r != 0 ? r < 0 : x.version < y.version; + try + { + uuid = uid ? *uid : uuid_type::generate (); + } + catch (const system_error& e) + { + fail << "unable to generate configuration uuid: " << e; + } + } + + dir_path configuration:: + effective_path (const dir_path& d) const + { + if (path.relative ()) + { + dir_path r (d / path); + + string what ("linked with " + d.representation () + " configuration " + + (name ? *name : to_string (*id))); + + normalize (r, what.c_str ()); + return r; + } + else + return path; + } + + // config_package + // + string config_package:: + string () const + { + std::string s (db.string ()); + return !s.empty () ? name.string () + ' ' + s : name.string (); } // available_package // + const version* available_package:: + system_version (database& db) const + { + if (!system_version_) + { + assert (db.system_repository); + + if (const system_package* sp = db.system_repository->find (id.name)) + { + // Only cache if it is authoritative. + // + if (sp->authoritative) + system_version_ = sp->version; + else + return &sp->version; + } + } + + return system_version_ ? &*system_version_ : nullptr; + } + + pair available_package:: + system_version_authoritative (database& db) const + { + assert (db.system_repository); + + const system_package* sp (db.system_repository->find (id.name)); + + if (!system_version_) + { + if (sp != nullptr) + { + // Only cache if it is authoritative. + // + if (sp->authoritative) + system_version_ = sp->version; + else + return make_pair (&sp->version, false); + } + } + + return make_pair (system_version_ ? &*system_version_ : nullptr, + sp != nullptr ? sp->authoritative : false); + } + odb::result query_available (database& db, const package_name& name, @@ -309,11 +390,9 @@ namespace bpkg } void - check_any_available (const dir_path& c, - transaction& t, - const diag_record* dr) + check_any_available (database& db, transaction&, const diag_record* dr) { - database& db (t.database ()); + const dir_path& c (db.config_orig); if (db.query_value () == 0) { @@ -382,15 +461,81 @@ namespace bpkg // selected_package // string selected_package:: - version_string () const + string (database& db) const + { + std::string s (db.string ()); + return !s.empty () ? string () + ' ' + s : string (); + } + + _selected_package_ref:: + _selected_package_ref (const lazy_shared_ptr& p) + : configuration (p.database ().uuid), + prerequisite (p.object_id ()) { - return version != wildcard_version ? version.string () : "*"; + } + + lazy_shared_ptr _selected_package_ref:: + to_ptr (odb::database& db) && + { + database& pdb (static_cast (db)); + + // Note that if this points to a different configuration, then it should + // already be pre-attached since it must be explicitly linked. + // + database& ddb (pdb.find_dependency_config (configuration)); + + // Make sure the prerequisite exists in the explicitly linked + // configuration, so that a subsequent load() call will not fail. This, + // for example, can happen in unlikely but possible situation when the + // implicitly linked configuration containing a dependent was temporarily + // renamed before its prerequisite was dropped. + // + // Note that the diagnostics lacks information about the dependent and its + // configuration. However, handling this situation at all the load() + // function call sites where this information is available, for example by + // catching the odb::object_not_persistent exception, feels a bit + // hairy. Given the situation is not common, let's keep it simple for now + // and see how it goes. + // + if (ddb != pdb && ddb.find (prerequisite) == nullptr) + fail << "unable to find prerequisite package " << prerequisite + << " in linked configuration " << ddb.config_orig; + + return lazy_shared_ptr (ddb, move (prerequisite)); + } + + pair, database*> + find_dependency (database& db, const package_name& pn, bool buildtime) + { + pair, database*> r; + + for (database& ldb: db.dependency_configs (pn, buildtime)) + { + shared_ptr p (ldb.find (pn)); + + if (p != nullptr) + { + if (r.first == nullptr) + { + r.first = move (p); + r.second = &ldb; + } + else + { + fail << "package " << pn << " appears in multiple configurations" << + info << r.first->state << " in " << r.second->config_orig << + info << p->state << " in " << ldb.config_orig; + } + } + } + + return r; } optional package_iteration (const common_options& o, - const dir_path& c, - transaction& t, + database& db, + transaction&, const dir_path& d, const package_name& n, const version& v, @@ -398,7 +543,6 @@ namespace bpkg { tracer trace ("package_iteration"); - database& db (t.database ()); tracer_guard tg (db, trace); if (check_external) @@ -447,7 +591,7 @@ namespace bpkg // if (!changed && p->external ()) { - dir_path src_root (p->effective_src_root (c)); + dir_path src_root (p->effective_src_root (db.config)); // We need to complete and normalize the source directory as it may // generally be completed against the configuration directory (unlikely @@ -532,4 +676,18 @@ namespace bpkg return os; } + + // package_dependent + // + odb::result + query_dependents (database& db, + const package_name& dep, + database& dep_db) + { + using query = query; + + return db.query ( + "prerequisite = " + query::_val (dep.string ()) + "AND" + + "configuration = " + query::_val (dep_db.uuid.string ())); + } } -- cgit v1.1