From a2b084651909929d58f6b4bc0f3c742d87ee31f6 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 27 Apr 2018 15:53:00 +0300 Subject: Add support for repository fragments --- bpkg/rep-remove.cxx | 177 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 137 insertions(+), 40 deletions(-) (limited to 'bpkg/rep-remove.cxx') diff --git a/bpkg/rep-remove.cxx b/bpkg/rep-remove.cxx index fafe5a8..056883d 100644 --- a/bpkg/rep-remove.cxx +++ b/bpkg/rep-remove.cxx @@ -44,21 +44,45 @@ namespace bpkg if (!traversed.insert (r).second) // We have already been here. return false; - for (const auto& rc: db.query ( + // Iterate over repository fragments that depend on this repository as a + // complement. + // + for (const auto& rf: db.query ( query::complement::name == nm)) { - const shared_ptr& r (rc); - if (r->name.empty () /* Root? */ || reachable (db, r, traversed)) + const shared_ptr& f (rf); + + if (f->name.empty ()) // Root? return true; + + // Iterate over repositories that contain this repository fragment. + // + for (const auto& fr: db.query ( + query::repository_fragment::name == f->name)) + { + if (reachable (db, fr, traversed)) + return true; + } } - for (const auto& rd: db.query ( + // Iterate over repository fragments that depend on this repository as a + // prerequisite. + // + for (const auto& rf: db.query ( query::prerequisite::name == nm)) { - // Note that the root repository has no prerequisites. + // Note that the root repository fragment has no prerequisites. // - if (reachable (db, rd, traversed)) - return true; + const shared_ptr& f (rf); + + // Iterate over repositories that contain this repository fragment. + // + for (const auto& fr: db.query ( + query::repository_fragment::name == f->name)) + { + if (reachable (db, fr, traversed)) + return true; + } } return false; @@ -72,22 +96,28 @@ namespace bpkg } void - rep_remove_package_locations (transaction& t, const string& name) + rep_remove_package_locations (transaction& t, const string& fragment_name) { + tracer trace ("rep_remove_package_locations"); + database& db (t.database ()); + tracer_guard tg (db, trace); + + using query = query; - for (const auto& rp: db.query ( - query::repository::name == name)) + for (const auto& rp: db.query ( + query::repository_fragment::name == fragment_name)) { const shared_ptr& p (rp); vector& ls (p->locations); - for (auto i (ls.cbegin ()); i != ls.cend (); ) + for (auto i (ls.cbegin ()); i != ls.cend (); ++i) { - if (i->repository.object_id () == name) - i = ls.erase (i); - else - ++i; + if (i->repository_fragment.object_id () == fragment_name) + { + ls.erase (i); + break; + } } if (ls.empty ()) @@ -117,17 +147,29 @@ namespace bpkg transaction& t, const shared_ptr& r) { - const string& nm (r->name); - assert (!nm.empty ()); // Can't be the root repository. + assert (!r->name.empty ()); // Can't be the root repository. + + tracer trace ("rep_remove"); database& db (t.database ()); + tracer_guard tg (db, trace); if (reachable (db, r)) return; - rep_remove_package_locations (t, nm); + // Note that it is essential to erase the repository object from the + // database prior to the repository fragments it contains as they must be + // un-referenced first. + // + db.erase (r); - // Cleanup the repository state if present. + // Remove dangling repository fragments. + // + for (const repository::fragment_type& fr: r->fragments) + rep_remove_fragment (c, t, fr.fragment.load ()); + + // Cleanup the repository state if present and there are no more + // repositories referring this state. // // Note that this step is irreversible on failure. If something goes wrong // we will end up with a state-less fetched repository and the @@ -145,14 +187,60 @@ namespace bpkg dir_path sd (c / repos_dir / d); if (exists (sd)) - rmdir (sd); + { + // There is no way to get the list of repositories that share this + // state other than traversing all repositories of this type. + // + bool rm (true); + + using query = query; + + for (shared_ptr r: + pointer_result ( + db.query ( + query::name != "" && + query::location.type == to_string (r->location.type ())))) + { + if (repository_state (r->location) == d) + { + rm = false; + break; + } + } + + if (rm) + rmdir (sd); + } } + } - // Note that it is essential to erase the repository object from the - // database prior to its complements and prerequisites removal as they - // must be un-referenced first. + void + rep_remove_fragment (const dir_path& c, + transaction& t, + const shared_ptr& rf) + { + tracer trace ("rep_remove_fragment"); + + database& db (t.database ()); + tracer_guard tg (db, trace); + + // Bail out if the repository fragment is still used. // - db.erase (r); + using query = query; + + if (db.query_value ( + "fragment=" + query::_val (rf->name)) != 0) + return; + + // Remove the repository fragment from locations of the available packages + // it contains. Note that this must be done before the repository fragment + // removal. + // + rep_remove_package_locations (t, rf->name); + + // Remove the repository fragment. + // + db.erase (rf); // Remove dangling complements and prerequisites. // @@ -167,7 +255,7 @@ namespace bpkg rep_remove (c, t, r); }; - for (const lazy_shared_ptr& cr: r->complements) + for (const lazy_shared_ptr& cr: rf->complements) { // Remove the complement unless it is the root repository (see // rep_fetch() for details). @@ -176,8 +264,15 @@ namespace bpkg remove (cr); } - for (const lazy_weak_ptr& pr: r->prerequisites) + for (const lazy_weak_ptr& pr: rf->prerequisites) remove (lazy_shared_ptr (pr)); + + // If there are no repositories stayed in the database then no repository + // fragments nor packages should stay either. + // + assert (db.query_value () != 0 || + (db.query_value () == 0 && + db.query_value () == 0)); } void @@ -187,12 +282,13 @@ namespace bpkg bool quiet) { tracer trace ("rep_remove_clean"); + tracer_guard tg (db, trace); assert (!transaction::has_current ()); - // Clean repositories and available packages. At the end only repositories - // that were explicitly added by the user and the special root repository - // should remain. + // Clean repositories, repository fragments and available packages. At the + // end only repositories that were explicitly added by the user and the + // special root repository should remain. // { // Note that we don't rely on being in session nor create one. @@ -201,19 +297,19 @@ namespace bpkg db.erase_query (); - shared_ptr root (db.load ("")); - repository::complements_type& ua (root->complements); + db.erase_query ( + query::name != ""); + + shared_ptr root (db.load ("")); + repository_fragment::complements_type& ua (root->complements); for (shared_ptr r: pointer_result (db.query ())) { if (r->name == "") - { - l5 ([&]{trace << "skipping root";}); - } + l5 ([&]{trace << "skipping root repository";}); else if (ua.find (lazy_shared_ptr (db, r)) != ua.end ()) { - r->complements.clear (); - r->prerequisites.clear (); + r->fragments.clear (); db.update (r); if (verb >= (quiet ? 2 : 1) && !o.no_result ()) @@ -298,8 +394,8 @@ namespace bpkg transaction t (db); session s; // Repository dependencies can have cycles. - shared_ptr root (db.load ("")); - repository::complements_type& ua (root->complements); + shared_ptr root (db.load ("")); + repository_fragment::complements_type& ua (root->complements); if (o.all ()) { @@ -392,11 +488,12 @@ namespace bpkg // assert (!o.all () || ua.empty ()); - // If we removed all the user-added repositories then no repositories nor - // packages should stay in the database. + // If we removed all the user-added repositories then no repositories, + // repository fragments or packages should stay in the database. // assert (!ua.empty () || (db.query_value () == 0 && + db.query_value () == 0 && db.query_value () == 0)); t.commit (); -- cgit v1.1