diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-09-16 16:12:31 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-09-16 16:12:31 +0200 |
commit | ac6df7a77682bf33b486d451c67ed9650bd9bc2f (patch) | |
tree | 144c60ce90390e0eb07f73843606daab61753758 /bpkg/pkg-purge.cxx | |
parent | 829c0083b1684e7513e0bd1bb0a92f767ba83f77 (diff) |
Implement pkg-status, pkg-purge commands; start ad-hoc test
Diffstat (limited to 'bpkg/pkg-purge.cxx')
-rw-r--r-- | bpkg/pkg-purge.cxx | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/bpkg/pkg-purge.cxx b/bpkg/pkg-purge.cxx new file mode 100644 index 0000000..8831b6d --- /dev/null +++ b/bpkg/pkg-purge.cxx @@ -0,0 +1,175 @@ +// file : bpkg/pkg-purge.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <bpkg/pkg-purge> + +#include <memory> // shared_ptr + +#include <bpkg/types> +#include <bpkg/package> +#include <bpkg/package-odb> +#include <bpkg/utility> +#include <bpkg/database> +#include <bpkg/diagnostics> + +using namespace std; +using namespace butl; + +namespace bpkg +{ + void + pkg_purge (const pkg_purge_options& o, cli::scanner& args) + { + tracer trace ("pkg_purge"); + + dir_path c (o.directory ()); + level4 ([&]{trace << "configuration: " << c;}); + + if (!args.more ()) + fail << "package name argument expected" << + info << "run 'bpkg help pkg-purge' for more information"; + + string n (args.next ()); + + database db (open (c)); + transaction t (db.begin ()); + + shared_ptr<package> p (db.find<package> (n)); + + if (p == nullptr) + fail << "package " << n << " does not exist in configuration " << c; + + // Make sure the package is in a state from which it can be purged. + // + switch (p->state) + { + case state::fetched: + { + // If we have --keep, then this is a no-op. We could have + // detected this and returned but we still want the normal + // diagnostics. So instead the logic below takes care of + // this situation. + // + break; + } + case state::unpacked: + { + if (o.keep () && !p->archive) + fail << "package " << n << " has no archive to keep"; + + break; + } + case state::broken: + { + if (!o.force ()) + fail << "broken package " << n << " can only be purged with --force"; + + if (o.keep ()) + fail << "cannot keep broken package " << n; + + break; + } + default: + { + fail << p->state << " package " << n << " cannot be purged"; + } + } + + // First clean up the package source directory. + // + if (p->source_purge) + { + dir_path d (*p->source); + if (d.relative ()) + d = c / d; + + if (p->state != state::broken) + { + try + { + if (exists (d)) // Don't complain if someone did our job for us. + rm_r (d); + + p->source = optional<dir_path> (); + p->source_purge = false; + } + catch (const failed&) + { + p->state = state::broken; + db.update (p); + t.commit (); + + if (verb) + text << "broke " << p->name << " " << p->version; + + throw; + } + } + else + { + // If we are broken, simply make sure the user cleaned things up + // manually. + // + if (exists (d)) + fail << "broken package " << n << " source directory still exists" << + info << "remove " << d << " manually then re-run pkg-purge"; + } + } + + // Now the archive. Pretty much the same code as above but for a file. + // + if (p->archive_purge && !o.keep ()) + { + path a (*p->archive); + if (a.relative ()) + a = c / a; + + if (p->state != state::broken) + { + try + { + if (exists (a)) + rm (a); + + p->archive = optional<path> (); + p->archive_purge = false; + } + catch (const failed&) + { + p->state = state::broken; + db.update (p); + t.commit (); + + if (verb) + text << "broke " << p->name << " " << p->version; + + throw; + } + } + else + { + if (exists (a)) + fail << "broken package " << n << " archive still exists" << + info << "remove " << a << " manually then re-run pkg-purge"; + } + } + + if (o.keep ()) + { + if (p->state != state::fetched) // That no-op we were talking about. + { + p->state = state::fetched; + db.update (p); + } + } + else + db.erase (p); + + t.commit (); + + if (verb) + text << (o.keep () ? "keeping archive " : "purged ") + << p->name << " " << p->version; + } +} |