aboutsummaryrefslogtreecommitdiff
path: root/bpkg/pkg-unpack.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bpkg/pkg-unpack.cxx')
-rw-r--r--bpkg/pkg-unpack.cxx208
1 files changed, 142 insertions, 66 deletions
diff --git a/bpkg/pkg-unpack.cxx b/bpkg/pkg-unpack.cxx
index b8ac08e..22ff02f 100644
--- a/bpkg/pkg-unpack.cxx
+++ b/bpkg/pkg-unpack.cxx
@@ -10,6 +10,7 @@
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
#include <bpkg/checksum.hxx>
+#include <bpkg/rep-mask.hxx>
#include <bpkg/diagnostics.hxx>
#include <bpkg/manifest-utility.hxx>
@@ -24,14 +25,13 @@ namespace bpkg
// diagnose all the illegal cases.
//
static void
- pkg_unpack_check (const dir_path& c,
- transaction& t,
+ pkg_unpack_check (database& db,
+ transaction&,
const package_name& n,
bool replace)
{
tracer trace ("pkg_update_check");
- database& db (t.database ());
tracer_guard tg (db, trace);
if (shared_ptr<selected_package> p = db.find<selected_package> (n))
@@ -42,6 +42,7 @@ namespace bpkg
if (!replace || !s)
{
diag_record dr (fail);
+ const dir_path& c (db.config_orig);
dr << "package " << n << " already exists in configuration " << c <<
info << "version: " << p->version_string ()
@@ -54,41 +55,30 @@ namespace bpkg
}
}
- // Select the external package in this configuration. Can return a new
- // selected package object, replacing the existing one.
+ // Select the external package in this configuration. Return the selected
+ // package object which may replace the existing one.
//
static shared_ptr<selected_package>
- pkg_unpack (const common_options& o,
- dir_path c,
+ pkg_unpack (database& db,
transaction& t,
- package_name n,
- version v,
- dir_path d,
- repository_location rl,
+ package_name&& n,
+ version&& v,
+ dir_path&& d,
+ repository_location&& rl,
+ shared_ptr<selected_package>&& p,
+ optional<string>&& mc,
+ optional<string>&& bc,
bool purge,
bool simulate)
{
- tracer trace ("pkg_unpack");
-
- database& db (t.database ());
- tracer_guard tg (db, trace);
-
- optional<string> mc;
-
- if (!simulate)
- mc = sha256 (o, d / manifest_file);
-
- // Make the package and configuration paths absolute and normalized.
- // If the package is inside the configuration, use the relative path.
- // This way we can move the configuration around.
+ // Make the package path absolute and normalized. If the package is inside
+ // the configuration, use the relative path. This way we can move the
+ // configuration around.
//
- normalize (c, "configuration");
normalize (d, "package");
- if (d.sub (c))
- d = d.leaf (c);
-
- shared_ptr<selected_package> p (db.find<selected_package> (n));
+ if (d.sub (db.config))
+ d = d.leaf (db.config);
if (p != nullptr)
{
@@ -96,7 +86,7 @@ namespace bpkg
// replacing. Once this is done, there is no going back. If things
// go badly, we can't simply abort the transaction.
//
- pkg_purge_fs (c, t, p, simulate);
+ pkg_purge_fs (db, t, p, simulate);
// Note that if the package name spelling changed then we need to update
// it, to make sure that the subsequent commands don't fail and the
@@ -118,6 +108,7 @@ namespace bpkg
p->src_root = move (d);
p->purge_src = purge;
p->manifest_checksum = move (mc);
+ p->buildfiles_checksum = move (bc);
db.update (p);
}
@@ -136,6 +127,7 @@ namespace bpkg
move (d),
purge,
move (mc),
+ move (bc),
nullopt, // No output directory yet.
{}}); // No prerequisites captured yet.
@@ -145,12 +137,68 @@ namespace bpkg
assert (p->external ());
t.commit ();
- return p;
+ return move (p);
+ }
+
+ template <typename T>
+ static shared_ptr<selected_package>
+ pkg_unpack (const common_options& o,
+ database& db,
+ transaction& t,
+ package_name n,
+ version v,
+ const vector<T>& deps,
+ const package_info* pi,
+ dir_path d,
+ repository_location rl,
+ bool purge,
+ bool simulate)
+ {
+ tracer trace ("pkg_unpack");
+
+ tracer_guard tg (db, trace);
+
+ shared_ptr<selected_package> p (db.find<selected_package> (n));
+
+ optional<string> mc;
+ optional<string> bc;
+
+ // Only calculate the manifest/subprojects and buildfiles checksums for
+ // external packages (see selected_package::external() for details).
+ //
+ if (!simulate && (rl.empty () || rl.directory_based ()))
+ {
+ mc = package_checksum (o, d, pi);
+
+ // Calculate the buildfiles checksum if the package has any buildfile
+ // clauses in the dependencies. Always calculate it over the buildfiles
+ // since the package is external.
+ //
+ if ((p != nullptr && p->manifest_checksum == mc)
+ ? p->buildfiles_checksum.has_value ()
+ : has_buildfile_clause (deps))
+ bc = package_buildfiles_checksum (nullopt /* bootstrap_build */,
+ nullopt /* root_build */,
+ {} /* buildfiles */,
+ d);
+ }
+
+ return pkg_unpack (db,
+ t,
+ move (n),
+ move (v),
+ move (d),
+ move (rl),
+ move (p),
+ move (mc),
+ move (bc),
+ purge,
+ simulate);
}
shared_ptr<selected_package>
pkg_unpack (const common_options& o,
- const dir_path& c,
+ database& db,
transaction& t,
const dir_path& d,
bool replace,
@@ -162,37 +210,59 @@ namespace bpkg
if (!exists (d))
fail << "package directory " << d << " does not exist";
+ // For better diagnostics, let's obtain the package info after
+ // pkg_verify() verifies that this is a package directory.
+ //
+ package_version_info pvi;
+
// Verify the directory is a package and get its manifest.
//
package_manifest m (
- pkg_verify (d,
+ pkg_verify (o,
+ d,
true /* ignore_unknown */,
- [&o, &d] (version& v)
+ false /* ignore_toolchain */,
+ false /* load_buildfiles */,
+ [&o, &d, &pvi] (version& v)
{
- if (optional<version> pv = package_version (o, d))
- v = move (*pv);
+ // Note that we also query subprojects since the package
+ // information will be used for the subsequent
+ // package_iteration() call.
+ //
+ pvi = package_version (o, d, b_info_flags::subprojects);
+
+ if (pvi.version)
+ v = move (*pvi.version);
}));
l4 ([&]{trace << d << ": " << m.name << " " << m.version;});
// Check/diagnose an already existing package.
//
- pkg_unpack_check (c, t, m.name, replace);
+ pkg_unpack_check (db, t, m.name, replace);
// Fix-up the package version.
//
- if (optional<version> v = package_iteration (
- o, c, t, d, m.name, m.version, true /* check_external */))
+ if (optional<version> v = package_iteration (o,
+ db,
+ t,
+ d,
+ m.name,
+ m.version,
+ &pvi.info,
+ true /* check_external */))
m.version = move (*v);
// Use the special root repository fragment as the repository fragment of
// this package.
//
return pkg_unpack (o,
- c,
+ db,
t,
move (m.name),
move (m.version),
+ m.dependencies,
+ &pvi.info,
d,
repository_location (),
purge,
@@ -201,7 +271,8 @@ namespace bpkg
shared_ptr<selected_package>
pkg_unpack (const common_options& o,
- const dir_path& c,
+ database& pdb,
+ database& rdb,
transaction& t,
package_name n,
version v,
@@ -210,20 +281,19 @@ namespace bpkg
{
tracer trace ("pkg_unpack");
- database& db (t.database ());
- tracer_guard tg (db, trace);
+ tracer_guard tg (pdb, trace); // NOTE: sets tracer for the whole cluster.
// Check/diagnose an already existing package.
//
- pkg_unpack_check (c, t, n, replace);
+ pkg_unpack_check (pdb, t, n, replace);
- check_any_available (c, t);
+ check_any_available (rdb, t);
- // Note that here we compare including the revision (see pkg-fetch()
+ // Note that here we compare including the revision (see pkg_fetch()
// implementation for more details).
//
shared_ptr<available_package> ap (
- db.find<available_package> (available_package_id (n, v)));
+ rdb.find<available_package> (available_package_id (n, v)));
if (ap == nullptr)
fail << "package " << n << " " << v << " is not available";
@@ -235,7 +305,8 @@ namespace bpkg
for (const package_location& l: ap->locations)
{
- if (l.repository_fragment.load ()->location.directory_based ())
+ if (!rep_masked_fragment (l.repository_fragment) &&
+ l.repository_fragment.load ()->location.directory_based ())
{
pl = &l;
break;
@@ -253,35 +324,37 @@ namespace bpkg
const repository_location& rl (pl->repository_fragment->location);
return pkg_unpack (o,
- c,
+ pdb,
t,
move (n),
move (v),
+ ap->dependencies,
+ nullptr /* package_info */,
path_cast<dir_path> (rl.path () / pl->location),
rl,
- false /* purge */,
+ false /* purge */,
simulate);
}
shared_ptr<selected_package>
pkg_unpack (const common_options& co,
- const dir_path& c,
+ database& db,
transaction& t,
const package_name& name,
bool simulate)
{
tracer trace ("pkg_unpack");
- database& db (t.database ());
tracer_guard tg (db, trace);
+ const dir_path& c (db.config_orig);
shared_ptr<selected_package> p (db.find<selected_package> (name));
if (p == nullptr)
fail << "package " << name << " does not exist in configuration " << c;
if (p->state != package_state::fetched)
- fail << "package " << name << " is " << p->state <<
+ fail << "package " << name << db << " is " << p->state <<
info << "expected it to be fetched";
l4 ([&]{trace << *p;});
@@ -293,20 +366,22 @@ namespace bpkg
// Also, since we must have verified the archive during fetch,
// here we can just assume what the resulting directory will be.
//
- dir_path d (c / dir_path (p->name.string () + '-' + p->version.string ()));
+ const package_name& n (p->name);
+ const version& v (p->version);
- if (exists (d))
- fail << "package directory " << d << " already exists";
+ dir_path d (c / dir_path (n.string () + '-' + v.string ()));
auto_rmdir arm;
- optional<string> mc;
if (!simulate)
{
+ if (exists (d))
+ fail << "package directory " << d << " already exists";
+
// If the archive path is not absolute, then it must be relative
// to the configuration.
//
- path a (p->archive->absolute () ? *p->archive : c / *p->archive);
+ path a (p->effective_archive (c));
l4 ([&]{trace << "archive: " << a;});
@@ -329,15 +404,11 @@ namespace bpkg
{
fail << "unable to extract " << a << " to " << c << ": " << e;
}
-
- mc = sha256 (co, d / manifest_file);
}
p->src_root = d.leaf (); // For now assuming to be in configuration.
p->purge_src = true;
- p->manifest_checksum = move (mc);
-
p->state = package_state::unpacked;
db.update (p);
@@ -356,7 +427,7 @@ namespace bpkg
const dir_path& c (o.directory ());
l4 ([&]{trace << "configuration: " << c;});
- database db (open (c, trace));
+ database db (c, trace, true /* pre_attach */);
transaction t (db);
shared_ptr<selected_package> p;
@@ -371,7 +442,7 @@ namespace bpkg
info << "run 'bpkg help pkg-unpack' for more information";
p = pkg_unpack (o,
- c,
+ db,
t,
dir_path (args.next ()),
o.replace (),
@@ -400,9 +471,14 @@ namespace bpkg
// "unpack" it from the directory-based repository.
//
p = v.empty ()
- ? pkg_unpack (o, c, t, n, false /* simulate */)
+ ? pkg_unpack (o,
+ db /* pdb */,
+ t,
+ n,
+ false /* simulate */)
: pkg_unpack (o,
- c,
+ db /* pdb */,
+ db /* rdb */,
t,
move (n),
move (v),