From 4e3faacbc3c27e1d01ca95697b34db82cdecdb9d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 10 Oct 2015 08:12:50 +0200 Subject: Implement --replace|-r mode for pkg-fetch --- bpkg/pkg-fetch.cxx | 85 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 18 deletions(-) (limited to 'bpkg/pkg-fetch.cxx') 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 #include +#include #include using namespace std; @@ -38,6 +39,35 @@ namespace bpkg auto_rm arm; bool purge; repository_location rl; + shared_ptr 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 + { + shared_ptr p (db.find (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 () == 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 p ( + shared_ptr ap ( db.find (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 p = db.find (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 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; } } -- cgit v1.1