aboutsummaryrefslogtreecommitdiff
path: root/bpkg/package.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'bpkg/package.hxx')
-rw-r--r--bpkg/package.hxx325
1 files changed, 222 insertions, 103 deletions
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index d7c9461..400519a 100644
--- a/bpkg/package.hxx
+++ b/bpkg/package.hxx
@@ -11,6 +11,7 @@
#include <type_traits> // static_assert
#include <odb/core.hxx>
+#include <odb/section.hxx>
#include <odb/nested-container.hxx>
#include <libbutl/timestamp.hxx>
@@ -25,9 +26,13 @@
// Used by the data migration entries.
//
-#define DB_SCHEMA_VERSION_BASE 7
+// NOTE: drop all the `#pragma db member(...) default(...)` pragmas when
+// migration is no longer supported (i.e., the current and base schema
+// versions are the same).
+//
+#define DB_SCHEMA_VERSION_BASE 12
-#pragma db model version(DB_SCHEMA_VERSION_BASE, 20, closed)
+#pragma db model version(DB_SCHEMA_VERSION_BASE, 26, closed)
namespace bpkg
{
@@ -513,6 +518,10 @@ namespace bpkg
operator size_t () const {return result;}
};
+ // language
+ //
+ #pragma db value(language) definition
+
// package_location
//
#pragma db value
@@ -613,9 +622,6 @@ namespace bpkg
//
#pragma db value(test_dependency) definition
- // @@ TMP Drop when database migration to the schema version 11 is no longer
- // supported.
- //
#pragma db member(test_dependency::buildtime) default(false)
using optional_test_dependency_type = optional<test_dependency_type>;
@@ -670,14 +676,27 @@ namespace bpkg
//
#pragma db value(buildfile) definition
+ // distribution_name_value
+ //
+ #pragma db value(distribution_name_value) definition
+
#pragma db object pointer(shared_ptr) session
class available_package
{
public:
using version_type = bpkg::version;
+ using upstream_version_type = bpkg::upstream_version;
available_package_id id;
- upstream_version version;
+ upstream_version_type version;
+
+ optional<string> upstream_version;
+ optional<string> type;
+
+ small_vector<language, 1> languages;
+ odb::section languages_section;
+
+ optional<package_name> project;
// List of repository fragments to which this package version belongs
// (yes, in our world, it can be in multiple, unrelated repositories)
@@ -697,8 +716,17 @@ namespace bpkg
// Package manifest data and, potentially, the special test dependencies.
//
- // Note that there can be only one special test dependencies entry in the
- // list and it's always the last one, if present.
+ // Note that there can only be one special test dependencies entry in the
+ // list. It can only be present for a test package and specifies all the
+ // main packages as the alternative dependencies. If present, it is
+ // located right after the last explicit depends clause which specifies a
+ // main package for this test package, if such a clause is present, and as
+ // the first entry otherwise. The idea here is to inject the special
+ // depends clause as early as possible, so that the other clauses could
+ // potentially refer to the reflection variables it may set. But not too
+ // early, so that the explicit main package dependencies are already
+ // resolved by the time of resolving the special clause to avoid the
+ // 'unable to select dependency alternative' error.
//
using dependencies_type = bpkg::dependencies;
@@ -716,6 +744,8 @@ namespace bpkg
optional<string> root_build;
vector<buildfile> buildfiles;
+ vector<distribution_name_value> distribution_values;
+
// Present for non-transient objects only (and only for certain repository
// types).
//
@@ -732,8 +762,13 @@ namespace bpkg
available_package (package_manifest&& m)
: id (move (m.name), m.version),
version (move (m.version)),
+ upstream_version (move (m.upstream_version)),
+ type (move (m.type)),
+ languages (move (m.languages)),
+ project (move (m.project)),
dependencies (convert (move (m.dependencies))),
tests (move (m.tests)),
+ distribution_values (move (m.distribution_values)),
sha256sum (move (m.sha256sum))
{
if (!stub ())
@@ -765,6 +800,18 @@ namespace bpkg
bool
stub () const {return version.compare (wildcard_version, true) == 0;}
+ string
+ effective_type () const
+ {
+ return package_manifest::effective_type (type, id.name);
+ }
+
+ small_vector<language, 1>
+ effective_languages () const
+ {
+ return package_manifest::effective_languages (languages, id.name);
+ }
+
// Return package system version if one has been discovered. Note that
// we do not implicitly assume a wildcard version.
//
@@ -781,6 +828,16 @@ namespace bpkg
//
#pragma db member(id) id column("")
#pragma db member(version) set(this.version.init (this.id.version, (?)))
+
+ // languages
+ //
+ #pragma db member(languages) id_column("") value_column("language_") \
+ section(languages_section)
+
+ #pragma db member(languages_section) load(lazy) update(always)
+
+ // locations
+ //
#pragma db member(locations) id_column("") value_column("") \
unordered value_not_null
@@ -834,31 +891,27 @@ namespace bpkg
//
#pragma db member(tests) id_column("") value_column("test_")
- // alt_naming
+ // distribution_values
//
- // @@ TMP Drop when database migration to the schema version 20 is no
- // longer supported.
+ #pragma db member(distribution_values) id_column("") value_column("dist_")
+
+ // alt_naming
//
- // Note that since no real packages with alternative buildfile naming
- // use conditional dependencies yet, we can just set alt_naming to
- // false during migration to the database schema version 20. Also we
- // never rely on alt_naming to be nullopt for the stub packages, so
- // let's not complicate things and set alt_naming to false for them
- // either.
+ // Note that since no real packages with alternative buildfile naming use
+ // conditional dependencies yet, we can just set alt_naming to false
+ // during migration to the database schema version 20. Also we never rely
+ // on alt_naming to be nullopt for the stub packages, so let's not
+ // complicate things and set alt_naming to false for them either.
//
#pragma db member(alt_naming) default(false)
// *_build
//
- // @@ TMP Drop when database migration to the schema version 15 is no
- // longer supported.
- //
- // Note that since no real packages use conditional dependencies yet,
- // we can just set bootstrap_build to the empty string during migration
- // to the database schema version 15. Also we never rely on
- // bootstrap_build to be nullopt for the stub packages, so let's not
- // complicate things and set bootstrap_build to the empty string for
- // them either.
+ // Note that since no real packages use conditional dependencies yet, we
+ // can just set bootstrap_build to the empty string during migration to
+ // the database schema version 15. Also we never rely on bootstrap_build
+ // to be nullopt for the stub packages, so let's not complicate things and
+ // set bootstrap_build to the empty string for them either.
//
#pragma db member(bootstrap_build) default("")
@@ -871,6 +924,15 @@ namespace bpkg
available_package () = default;
};
+ // The available packages together with the repository fragments they belong
+ // to.
+ //
+ // Note that lazy_shared_ptr is used to also convey the databases the
+ // objects belong to.
+ //
+ using available_packages = vector<pair<shared_ptr<available_package>,
+ lazy_shared_ptr<repository_fragment>>>;
+
#pragma db view object(available_package)
struct available_package_count
{
@@ -1033,37 +1095,9 @@ namespace bpkg
//
optional<version_constraint> constraint;
- // Position of the first dependency alternative with a configuration
- // clause, if any.
- //
- // Specifically, if there is such an alternative then this is a pair of
- // 1-based indexes of the respective depends value (first) and the
- // dependency alternative (second) in the dependent's manifest. Otherwise,
- // this is a pair of zeros.
- //
- // For example, for the following dependent the position for libfoo/1.2.0
- // prerequisite will be {2,2}:
- //
- // libbar: depends: libfoo >= 1.1.0
- // depends: libfox | libfoo >= 1.2.0 {require {...}}
- //
- pair<size_t, size_t> config_position;
-
// Database mapping.
//
#pragma db member(constraint) column("")
-
- #pragma db member(config_position) transient
-
- #pragma db member(config_dependency_index) \
- virtual(size_t) \
- access(config_position.first) \
- default(0)
-
- #pragma db member(config_alternative_index) \
- virtual(size_t) \
- access(config_position.second) \
- default(0)
};
// Note that the keys for this map need to be created with the database
@@ -1177,9 +1211,9 @@ namespace bpkg
// package version revision increment. In particular, new subprojects
// should trigger the package reconfiguration.
//
- // Must be present if the source directory is present, unless the object
- // is created/updated during the package build simulation (see pkg-build
- // for details). Note that during the simulation the manifest may not be
+ // Only present for external packages, unless the objects are
+ // created/updated during the package build simulation (see pkg-build for
+ // details). Note that during the simulation the manifest may not be
// available.
//
// @@ Currently we don't consider subprojects recursively (would most
@@ -1191,30 +1225,46 @@ namespace bpkg
//
optional<std::string> manifest_checksum;
- // Absent if the package has no buildfile clauses in the dependencies.
- // Otherwise, the checksum of the buildfiles calculated over the *-build
- // manifest values or, if unspecified, the files in the package source
- // directory.
+ // Only present for external packages which have buildfile clauses in the
+ // dependencies, unless the objects are created/updated during the package
+ // build simulation (see pkg-build for details).
//
- // Note that for external packages the checksum is always calculated over
- // the files. This is "parallel" to the package skeleton logic.
+ // Note that the checksum is always calculated over the files rather than
+ // the *-build manifest values. This is "parallel" to the package skeleton
+ // logic.
//
optional<std::string> buildfiles_checksum;
- // Path to the output directory of this package, if any. It is
- // always relative to the configuration directory, and is <name>
- // for external packages and <name>-<version> for others. It is
- // only set once the package is configured and its main purse is
- // to keep track of what needs to be cleaned by the user before
- // a broken package can be purged. Note that it could be the
- // same as src_root.
+ // Path to the output directory of this package, if any. It is always
+ // relative to the configuration directory, and is <name> for external
+ // packages and <name>-<version> for others. It is only set once the
+ // package is configured and its main purpose is to keep track of what
+ // needs to be cleaned by the user before a broken package can be
+ // purged. Note that it could be the same as src_root.
//
optional<dir_path> out_root;
package_prerequisites prerequisites;
+ // 1-based indexes of the selected dependency alternatives which the
+ // prerequisite packages are resolved from. Parallel to the dependencies
+ // member of the respective available package. Entries which don't
+ // correspond to a selected alternative (toolchain build-time dependency,
+ // not enabled alternatives, etc) are set to 0.
+ //
+ using indexes_type = vector<size_t>; // Make sure ODB maps it portably.
+ indexes_type dependency_alternatives;
+ odb::section dependency_alternatives_section;
+
+ // Project configuration variable names and their sources.
+ //
vector<config_variable> config_variables;
+ // SHA256 checksum of variables (names and values) referred to by the
+ // config_variables member.
+ //
+ std::string config_checksum;
+
public:
bool
system () const
@@ -1259,6 +1309,18 @@ namespace bpkg
std::string
string (database&) const;
+ // Return the relative archive path completed using the configuration
+ // directory. Return the absolute archive path as is.
+ //
+ path
+ effective_archive (const dir_path& configuration) const
+ {
+ // Cast for compiling with ODB (see above).
+ //
+ assert (static_cast<bool> (archive));
+ return archive->absolute () ? *archive : configuration / *archive;
+ }
+
// Return the relative source directory completed using the configuration
// directory. Return the absolute source directory as is.
//
@@ -1271,8 +1333,7 @@ namespace bpkg
return src_root->absolute () ? *src_root : configuration / *src_root;
}
- // Return the output directory using the configuration directory. Note
- // that the output directory is always relative.
+ // Return the output directory using the configuration directory.
//
dir_path
effective_out_root (const dir_path& configuration) const
@@ -1280,6 +1341,9 @@ namespace bpkg
// Cast for compiling with ODB (see above).
//
assert (static_cast<bool> (out_root));
+
+ // Note that out_root is always relative.
+ //
return configuration / *out_root;
}
@@ -1290,8 +1354,21 @@ namespace bpkg
#pragma db member(prerequisites) id_column("package") \
key_column("") value_column("")
+ #pragma db member(dependency_alternatives) id_column("package") \
+ value_column("position") section(dependency_alternatives_section)
+
+ #pragma db member(dependency_alternatives_section) load(lazy) update(always)
+
#pragma db member(config_variables) id_column("package") value_column("")
+ // For the sake of simplicity let's not calculate the checksum during
+ // migration. It seems that the only drawback of this approach is a
+ // (single) spurious reconfiguration of a dependency of a dependent with
+ // configuration clause previously configured by bpkg with the database
+ // schema version prior to 24.
+ //
+ #pragma db member(config_checksum) default("")
+
// Explicit aggregate initialization for C++20 (private default ctor).
//
selected_package (package_name n,
@@ -1361,21 +1438,24 @@ namespace bpkg
//
// Pass the build2 project info for the package, if available, to speed up
// the call and NULL otherwise (in which case it will be queried by the
- // implementation).
+ // implementation). In the former case it is assumed that the package info
+ // has been retrieved with the b_info_flags::subprojects flag.
//
// Notes:
//
// - The package directory is considered an iteration of the package if this
// upstream version and revision is already present (selected) in the
- // configuration and has a source directory. If that's the case, then the
- // specified directory path and the checksum of the manifest file it
- // contains are compared to the ones of the package present in the
- // configuration. If both match, then the present package version
- // (including its iteration, if any) is returned. Otherwise (the package
- // has moved and/or the packaging information has changed), the present
- // package version with the incremented iteration number is returned. Note
- // that the directory path is matched only for the external selected
- // packages.
+ // configuration and has a source directory. If that's the case and if the
+ // present version is not external (the package is being switched to a
+ // local potentially amended version), then the present package version
+ // with the incremented iteration number is returned. Otherwise (the
+ // present package is external), the specified directory path and the
+ // package checksum (see package_checksum() for details) are compared to
+ // the ones of the package present in the configuration. If both match,
+ // then the present package version (including its iteration, if any) is
+ // returned. Otherwise (the package has moved and/or the package
+ // information has changed), the present package version with the
+ // incremented iteration number is returned.
//
// - Only a single package iteration is valid per version in the
// configuration. This, in particular, means that a package of the
@@ -1511,21 +1591,6 @@ namespace bpkg
#pragma db column("pp.package")
package_name name;
- #pragma db transient
- pair<size_t, size_t> config_position;
-
- #pragma db member(config_dependency_index) \
- column("pp.config_dependency_index") \
- virtual(size_t) \
- access(config_position.first) \
- default(0)
-
- #pragma db member(config_alternative_index) \
- column("pp.config_alternative_index") \
- virtual(size_t) \
- access(config_position.second) \
- default(0)
-
#pragma db column("pp.")
optional<version_constraint> constraint;
};
@@ -1558,12 +1623,6 @@ namespace bpkg
package_key (database& d, package_name n): db (d), name (move (n)) {}
- // Create a pseudo-package (command line as a dependent, etc).
- //
- package_key (database& d, string n)
- : db (d),
- name (n.empty () ? package_name () : package_name (move (n))) {}
-
bool
operator== (const package_key& v) const
{
@@ -1595,6 +1654,66 @@ namespace bpkg
return os << p.string ();
}
+ // Database, package name, and package version.
+ //
+ // It is normally used as a key for maps containing data for package
+ // versions across multiple linked configurations. Assumes that the
+ // respective databases are not detached during such map lifetimes.
+ // Considers all package name, package version, and database for objects
+ // comparison.
+ //
+ // The package name can be a pseudo-package (command line as a dependent,
+ // etc), in which case the version is absent. The version can also be empty,
+ // denoting a package of an unknown version.
+ //
+ struct package_version_key
+ {
+ reference_wrapper<database> db;
+ package_name name;
+ optional<bpkg::version> version;
+
+ package_version_key (database& d, package_name n, bpkg::version v)
+ : db (d), name (move (n)), version (move (v)) {}
+
+ // Create a pseudo-package (command line as a dependent, etc).
+ //
+ package_version_key (database& d, string n)
+ : db (d),
+ name (move (n), package_name::raw_string) {}
+
+ bool
+ operator== (const package_version_key& v) const
+ {
+ // See operator==(database, database).
+ //
+ return name == v.name &&
+ version == v.version &&
+ &db.get () == &v.db.get ();
+ }
+
+ bool
+ operator!= (const package_version_key& v) const
+ {
+ return !(*this == v);
+ }
+
+ bool
+ operator< (const package_version_key&) const;
+
+ // Return the package string representation in the form:
+ //
+ // <name>[/<version>] [ <config-dir>]
+ //
+ std::string
+ string (bool ignore_version = false) const;
+ };
+
+ inline ostream&
+ operator<< (ostream& os, const package_version_key& p)
+ {
+ return os << p.string ();
+ }
+
// Return a count of repositories that contain this repository fragment.
//
#pragma db view table("main.repository_fragments")