aboutsummaryrefslogtreecommitdiff
path: root/bpkg/pkg-fetch.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-10-10 08:12:50 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-10-10 08:12:50 +0200
commit4e3faacbc3c27e1d01ca95697b34db82cdecdb9d (patch)
tree5144d4bddbb376318fcaf20dafa0c391ddce93b1 /bpkg/pkg-fetch.cxx
parent803acc23f8cea3079681e9e624702e104adfd775 (diff)
Implement --replace|-r mode for pkg-fetch
Diffstat (limited to 'bpkg/pkg-fetch.cxx')
-rw-r--r--bpkg/pkg-fetch.cxx85
1 files changed, 67 insertions, 18 deletions
diff --git a/bpkg/pkg-fetch.cxx b/bpkg/pkg-fetch.cxx
index daa2d5e..c8b8543 100644
--- a/bpkg/pkg-fetch.cxx
+++ b/bpkg/pkg-fetch.cxx
@@ -15,6 +15,7 @@
#include <bpkg/diagnostics>
#include <bpkg/manifest-utility>
+#include <bpkg/pkg-purge>
#include <bpkg/pkg-verify>
using namespace std;
@@ -38,6 +39,35 @@ namespace bpkg
auto_rm arm;
bool purge;
repository_location rl;
+ shared_ptr<selected_package> sp;
+
+ // Check if the package already exists in this configuration and
+ // diagnose all the illegal cases. We want to do this as soon as
+ // the package name is known which happens at different times
+ // depending on whether we are dealing with an existing archive
+ // or fetching one.
+ //
+ auto check = [&o, &c, &db] (const string& n)
+ -> shared_ptr<selected_package>
+ {
+ shared_ptr<selected_package> p (db.find<selected_package> (n));
+
+ if (p == nullptr ||
+ (p->state == package_state::fetched && o.replace ()))
+ return p;
+
+ {
+ diag_record dr (error);
+
+ dr << "package " << n << " already exists in configuration " << c <<
+ info << "version: " << p->version << ", state: " << p->state;
+
+ if (p->state == package_state::fetched)
+ dr << info << "use 'pkg-fetch --replace|-r' to replace its archive";
+ }
+
+ throw failed ();
+ };
if (o.existing ())
{
@@ -71,6 +101,10 @@ namespace bpkg
fail << "package version expected" <<
info << "run 'bpkg help pkg-fetch' for more information";
+ // Check/diagnose an already existing package.
+ //
+ sp = check (n);
+
if (db.query_value<repository_count> () == 0)
fail << "configuration " << c << " has no repositories" <<
info << "use 'bpkg rep-add' to add a repository";
@@ -79,18 +113,18 @@ namespace bpkg
fail << "configuration " << c << " has no available packages" <<
info << "use 'bpkg rep-fetch' to fetch available packages list";
- shared_ptr<available_package> p (
+ shared_ptr<available_package> ap (
db.find<available_package> (available_package_id (n, v)));
- if (p == nullptr)
+ if (ap == nullptr)
fail << "package " << n << " " << v << " is not available";
- // Pick a repository. Preferring local ones over the remote seems
+ // Pick a repository. Preferring a local one over the remotes seems
// like a sensible thing to do.
//
- const package_location* pl (&p->locations.front ());
+ const package_location* pl (&ap->locations.front ());
- for (const package_location& l: p->locations)
+ for (const package_location& l: ap->locations)
{
if (!l.repository.load ()->location.remote ())
{
@@ -116,13 +150,10 @@ namespace bpkg
package_manifest m (pkg_verify (o, a));
level4 ([&]{trace << m.name << " " << m.version;});
- const auto& n (m.name);
-
- // See if this package already exists in this configuration.
+ // Check/diagnose an already existing package.
//
- if (shared_ptr<selected_package> p = db.find<selected_package> (n))
- fail << "package " << n << " already exists in configuration " << c <<
- info << "version: " << p->version << ", state: " << p->state;
+ if (o.existing ())
+ sp = check (m.name);
// Make the archive and configuration paths absolute and normalized.
// If the archive is inside the configuration, use the relative path.
@@ -134,9 +165,27 @@ namespace bpkg
if (a.sub (c))
a = a.leaf (c);
- // Add the package to the configuration.
- //
- shared_ptr<selected_package> p (new selected_package {
+ if (sp != nullptr)
+ {
+ // Clean up the archive we are replacing. Once this is done, there
+ // is no going back. If things go badly, we can't simply abort the
+ // transaction.
+ //
+ if (sp->purge_archive)
+ pkg_purge_archive (c, t, sp);
+
+ sp->version = move (m.version);
+ sp->repository = move (rl);
+ sp->archive = move (a);
+ sp->purge_archive = purge;
+
+ db.update (sp);
+ }
+ else
+ {
+ // Add the package to the configuration.
+ //
+ sp.reset (new selected_package {
move (m.name),
move (m.version),
package_state::fetched,
@@ -146,15 +195,15 @@ namespace bpkg
nullopt, // No source directory yet.
false,
nullopt, // No output directory yet.
- {} // No prerequisites captured yet.
- });
+ {}}); // No prerequisites captured yet.
- db.persist (p);
+ db.persist (sp);
+ }
t.commit ();
arm.cancel ();
if (verb)
- text << "fetched " << p->name << " " << p->version;
+ text << "fetched " << sp->name << " " << sp->version;
}
}