diff options
Diffstat (limited to 'bpkg/rep-remove.cxx')
-rw-r--r-- | bpkg/rep-remove.cxx | 143 |
1 files changed, 87 insertions, 56 deletions
diff --git a/bpkg/rep-remove.cxx b/bpkg/rep-remove.cxx index c377fc5..ad10f56 100644 --- a/bpkg/rep-remove.cxx +++ b/bpkg/rep-remove.cxx @@ -5,7 +5,7 @@ #include <set> -#include <libbutl/filesystem.mxx> // dir_iterator +#include <libbutl/filesystem.hxx> // dir_iterator #include <bpkg/package.hxx> #include <bpkg/package-odb.hxx> @@ -25,8 +25,7 @@ namespace bpkg // prerequisites. Thus we need to make sure that the repository was not // traversed yet. // - using repositories = set<reference_wrapper<const shared_ptr<repository>>, - compare_reference_target>; + using repositories = set<shared_ptr<repository>>; static bool reachable (database& db, @@ -94,11 +93,12 @@ namespace bpkg } void - rep_remove_package_locations (transaction& t, const string& fragment_name) + rep_remove_package_locations (database& db, + transaction&, + const string& fragment_name) { tracer trace ("rep_remove_package_locations"); - database& db (t.database ()); tracer_guard tg (db, trace); using query = query<repository_fragment_package>; @@ -129,9 +129,12 @@ namespace bpkg // the chances for the operation to succeed. // static void - rmdir (const dir_path& d) + rmdir (const dir_path& cfg, const dir_path& d) { - dir_path td (temp_dir / d.leaf ()); + auto i (tmp_dirs.find (cfg)); + assert (i != tmp_dirs.end ()); + + dir_path td (i->second / d.leaf ()); if (exists (td)) rm_r (td); @@ -140,16 +143,25 @@ namespace bpkg rm_r (td, true /* dir_itself */, 3, rm_error_mode::warn); } + static void + rep_remove_fragment (database&, + transaction&, + const shared_ptr<repository_fragment>&, + bool mask); + + // In the mask repositories mode don't cleanup the repository state in the + // filesystem (see rep-mask.hxx for the details on repository masking). + // void - rep_remove (const dir_path& c, + rep_remove (database& db, transaction& t, - const shared_ptr<repository>& r) + const shared_ptr<repository>& r, + bool mask) { 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)) @@ -164,7 +176,7 @@ namespace bpkg // Remove dangling repository fragments. // for (const repository::fragment_type& fr: r->fragments) - rep_remove_fragment (c, t, fr.fragment.load ()); + rep_remove_fragment (db, t, fr.fragment.load (), mask); // If there are no repositories stayed in the database then no repository // fragments should stay either. @@ -172,8 +184,8 @@ namespace bpkg if (db.query_value<repository_count> () == 0) assert (db.query_value<repository_fragment_count> () == 0); - // Cleanup the repository state if present and there are no more - // repositories referring this state. + // Unless in the mask repositories mode, 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 @@ -184,48 +196,61 @@ namespace bpkg // then remove them after committing the transaction. Though, we still may // fail in the middle due to the filesystem error. // - dir_path d (repository_state (r->location)); - - if (!d.empty ()) + if (!mask) { - dir_path sd (c / repos_dir / d); + dir_path d (repository_state (r->location)); - if (exists (sd)) + if (!d.empty ()) { - // 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<repository>; + dir_path sd (db.config_orig / repos_dir / d); - for (shared_ptr<repository> rp: - pointer_result ( - db.query<repository> ( - query::name != "" && - query::location.type == to_string (r->location.type ())))) + if (exists (sd)) { - if (repository_state (rp->location) == d) + // 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<repository>; + + for (shared_ptr<repository> rp: + pointer_result ( + db.query<repository> ( + query::name != "" && + query::location.type == to_string (r->location.type ())))) { - rm = false; - break; + if (repository_state (rp->location) == d) + { + rm = false; + break; + } } - } - if (rm) - rmdir (sd); + if (rm) + rmdir (db.config_orig, sd); + } } } } void - rep_remove_fragment (const dir_path& c, + rep_remove (database& db, transaction& t, const shared_ptr<repository>& r) + { + rep_remove (db, t, r, false /* mask */); + } + + // In the mask repositories mode don't remove the repository fragment from + // locations of the available packages it contains (see rep-mask.hxx for the + // details on repository masking). + // + static void + rep_remove_fragment (database& db, transaction& t, - const shared_ptr<repository_fragment>& rf) + const shared_ptr<repository_fragment>& rf, + bool mask) { tracer trace ("rep_remove_fragment"); - database& db (t.database ()); tracer_guard tg (db, trace); // Bail out if the repository fragment is still used. @@ -236,11 +261,12 @@ namespace bpkg "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. + // Unless in the mask repositories mode, 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); + if (!mask) + rep_remove_package_locations (db, t, rf->name); // Remove the repository fragment. // @@ -256,8 +282,8 @@ namespace bpkg // if (db.query_value<repository_fragment_count> () == 0) { - assert (db.query_value<repository_count> () == 0); - assert (db.query_value<available_package_count> () == 0); + assert (db.query_value<repository_count> () == 0); + assert (mask || db.query_value<available_package_count> () == 0); } // Remove dangling complements and prerequisites. @@ -265,10 +291,10 @@ namespace bpkg // Prior to removing a prerequisite/complement we need to make sure it // still exists, which may not be the case due to the dependency cycle. // - auto remove = [&c, &db, &t] (const lazy_weak_ptr<repository>& rp) + auto remove = [&db, &t, mask] (const lazy_weak_ptr<repository>& rp) { if (shared_ptr<repository> r = db.find<repository> (rp.object_id ())) - rep_remove (c, t, r); + rep_remove (db, t, r, mask); }; for (const lazy_weak_ptr<repository>& cr: rf->complements) @@ -285,10 +311,15 @@ namespace bpkg } void - rep_remove_clean (const common_options& o, - const dir_path& c, - database& db, - bool quiet) + rep_remove_fragment (database& db, + transaction& t, + const shared_ptr<repository_fragment>& rf) + { + return rep_remove_fragment (db, t, rf, false /* mask */); + } + + void + rep_remove_clean (const common_options& o, database& db, bool quiet) { tracer trace ("rep_remove_clean"); tracer_guard tg (db, trace); @@ -336,14 +367,14 @@ namespace bpkg // Remove repository state subdirectories. // - dir_path rd (c / repos_dir); + dir_path rd (db.config_orig / repos_dir); try { - for (const dir_entry& de: dir_iterator (rd, false /* ignore_dangling */)) + for (const dir_entry& de: dir_iterator (rd, dir_iterator::no_follow)) { if (de.ltype () == entry_type::directory) - rmdir (rd / path_cast<dir_path> (de.path ())); + rmdir (db.config_orig, rd / path_cast<dir_path> (de.path ())); } } catch (const system_error& e) @@ -384,13 +415,13 @@ namespace bpkg dr << info << "run 'bpkg help rep-remove' for more information"; } - database db (open (c, trace)); + database db (c, trace, false /* pre_attach */); // Clean the configuration if requested. // if (o.clean ()) { - rep_remove_clean (o, c, db, false /* quiet */); + rep_remove_clean (o, db, false /* quiet */); return 0; } @@ -484,7 +515,7 @@ namespace bpkg // for (const lazy_shared_ptr<repository>& r: repos) { - rep_remove (c, t, r.load ()); + rep_remove (db, t, r.load ()); if (verb && !o.no_result ()) text << "removed " << r.object_id (); |