aboutsummaryrefslogtreecommitdiff
path: root/bpkg/rep-remove.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bpkg/rep-remove.cxx')
-rw-r--r--bpkg/rep-remove.cxx143
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 ();