aboutsummaryrefslogtreecommitdiff
path: root/bpkg/package.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'bpkg/package.hxx')
-rw-r--r--bpkg/package.hxx546
1 files changed, 439 insertions, 107 deletions
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index 13efcd4..400519a 100644
--- a/bpkg/package.hxx
+++ b/bpkg/package.hxx
@@ -11,9 +11,10 @@
#include <type_traits> // static_assert
#include <odb/core.hxx>
+#include <odb/section.hxx>
#include <odb/nested-container.hxx>
-#include <libbutl/timestamp.mxx>
+#include <libbutl/timestamp.hxx>
#include <libbpkg/package-name.hxx>
@@ -25,9 +26,13 @@
// Used by the data migration entries.
//
-#define DB_SCHEMA_VERSION_BASE 6
+// 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, 12, closed)
+#pragma db model version(DB_SCHEMA_VERSION_BASE, 26, closed)
namespace bpkg
{
@@ -73,7 +78,7 @@ namespace bpkg
std::chrono::nanoseconds::period>::value,
"The following timestamp ODB mapping is invalid");
- // As pointed out in libbutl/timestamp.mxx we will overflow in year 2262, but
+ // As pointed out in libbutl/timestamp.hxx we will overflow in year 2262, but
// by that time some larger basic type will be available for mapping.
//
#pragma db map type(timestamp) as(uint64_t) \
@@ -99,7 +104,7 @@ namespace bpkg
string upstream;
optional<string> release;
- // @@ TMP: work around MSVC 16.2 bug.
+ // Work around MSVC 16.2 bug.
//
_version () = default;
_version (uint16_t e,
@@ -343,7 +348,7 @@ namespace bpkg
repository_url url;
repository_type type;
- // @@ TMP: work around MSVC 16.2 bug.
+ // Work around MSVC 16.2 bug.
//
_repository_location () = default;
_repository_location (repository_url u, repository_type t)
@@ -513,6 +518,10 @@ namespace bpkg
operator size_t () const {return result;}
};
+ // language
+ //
+ #pragma db value(language) definition
+
// package_location
//
#pragma db value
@@ -535,6 +544,7 @@ namespace bpkg
#pragma db value(version_constraint) definition
#pragma db value(dependency) definition
#pragma db member(dependency::constraint) column("")
+ #pragma db value(dependency_alternative) definition
#pragma db value(dependency_alternatives) definition
// Extend dependency_alternatives to also represent the special test
@@ -555,12 +565,15 @@ namespace bpkg
dependency_alternatives_ex (dependency_alternatives da)
: dependency_alternatives (move (da)) {}
+ // As above but built incrementally.
+ //
+ dependency_alternatives_ex (bool b, std::string c)
+ : dependency_alternatives (b, move (c)) {}
+
// Create the special test dependencies object (built incrementally).
//
dependency_alternatives_ex (test_dependency_type t, bool buildtime)
- : dependency_alternatives (false /* conditional */,
- buildtime,
- "" /* comment */),
+ : dependency_alternatives (buildtime, "" /* comment */),
type (t) {}
};
@@ -576,9 +589,39 @@ namespace bpkg
make_move_iterator (das.end ()));
}
+ // Return true if this is a toolchain build-time dependency. If the package
+ // argument is specified and this is a toolchain build-time dependency then
+ // also verify its constraint and fail if it is unsatisfied. Note that the
+ // package argument is used for diagnostics only.
+ //
+ class common_options;
+
+ bool
+ toolchain_buildtime_dependency (const common_options&,
+ const dependency_alternatives&,
+ const package_name*);
+
+ // Return true if any dependency other than toolchain build-time
+ // dependencies is specified. Optionally, verify toolchain build-time
+ // dependencies specifying the package argument which will be used for
+ // diagnostics only.
+ //
+ bool
+ has_dependencies (const common_options&,
+ const dependencies&,
+ const package_name* = nullptr);
+
+ // Return true if some clause that is a buildfile fragment is specified for
+ // any of the dependencies.
+ //
+ template <typename T>
+ bool
+ has_buildfile_clause (const vector<T>& dependencies);
+
// tests
//
#pragma db value(test_dependency) definition
+
#pragma db member(test_dependency::buildtime) default(false)
using optional_test_dependency_type = optional<test_dependency_type>;
@@ -600,6 +643,19 @@ namespace bpkg
//
extern const version wildcard_version;
+ // Return true if the version constraint represents the wildcard version.
+ //
+ inline bool
+ wildcard (const version_constraint& vc)
+ {
+ bool r (vc.min_version && *vc.min_version == wildcard_version);
+
+ if (r)
+ assert (vc.max_version == vc.min_version);
+
+ return r;
+ }
+
// package_name
//
#pragma db value(package_name) type("TEXT") options("COLLATE NOCASE")
@@ -616,14 +672,31 @@ namespace bpkg
available_package_id (package_name, const bpkg::version&);
};
+ // buildfile
+ //
+ #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)
@@ -643,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;
@@ -652,6 +734,18 @@ namespace bpkg
small_vector<test_dependency, 1> tests;
+ // Note that while the bootstrap buildfile is always present for stub
+ // packages, we don't save buildfiles for stubs of any kind (can come from
+ // repository, be based on system selected package, etc), leaving *_build
+ // as nullopt and buildfiles empty.
+ //
+ optional<bool> alt_naming;
+ optional<string> bootstrap_build;
+ 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).
//
@@ -662,14 +756,31 @@ namespace bpkg
mutable optional<version_type> system_version_;
public:
- // Note: version constraints must be complete.
+ // Note: version constraints must be complete and the bootstrap build must
+ // be present, unless this is a stub.
//
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)),
- sha256sum (move (m.sha256sum)) {}
+ distribution_values (move (m.distribution_values)),
+ sha256sum (move (m.sha256sum))
+ {
+ if (!stub ())
+ {
+ assert (m.bootstrap_build.has_value () && m.alt_naming.has_value ());
+
+ alt_naming = m.alt_naming;
+ bootstrap_build = move (m.bootstrap_build);
+ root_build = move (m.root_build);
+ buildfiles = move (m.buildfiles);
+ }
+ }
// Create available stub package.
//
@@ -689,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.
//
@@ -705,37 +828,111 @@ 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
// dependencies
//
- using _dependency_key = odb::nested_key<dependency_alternatives_ex>;
- using _dependency_alternatives_ex_type =
- std::map<_dependency_key, dependency>;
-
- #pragma db value(_dependency_key)
- #pragma db member(_dependency_key::outer) column("dependency_index")
- #pragma db member(_dependency_key::inner) column("index")
+ // Note that this is a 2-level nested container which is mapped to three
+ // container tables each containing data of each dimension.
+ // Container of the dependency_alternatives_ex values.
+ //
#pragma db member(dependencies) id_column("") value_column("")
- #pragma db member(dependency_alternatives_ex) \
- table("available_package_dependency_alternatives") \
- virtual(_dependency_alternatives_ex_type) \
+
+ // Container of the dependency_alternative values.
+ //
+ using _dependency_alternative_key =
+ odb::nested_key<dependency_alternatives_ex>;
+
+ using _dependency_alternatives_type =
+ std::map<_dependency_alternative_key, dependency_alternative>;
+
+ #pragma db value(_dependency_alternative_key)
+ #pragma db member(_dependency_alternative_key::outer) column("dependency_index")
+ #pragma db member(_dependency_alternative_key::inner) column("index")
+
+ #pragma db member(dependency_alternatives) \
+ virtual(_dependency_alternatives_type) \
after(dependencies) \
get(odb::nested_get (this.dependencies)) \
set(odb::nested_set (this.dependencies, std::move (?))) \
+ id_column("") key_column("") value_column("")
+
+ // Container of the dependency values.
+ //
+ using _dependency_key = odb::nested2_key<dependency_alternatives_ex>;
+ using _dependency_alternative_dependencies_type =
+ std::map<_dependency_key, dependency>;
+
+ #pragma db value(_dependency_key)
+ #pragma db member(_dependency_key::outer) column("dependency_index")
+ #pragma db member(_dependency_key::middle) column("alternative_index")
+ #pragma db member(_dependency_key::inner) column("index")
+
+ #pragma db member(dependency_alternative_dependencies) \
+ virtual(_dependency_alternative_dependencies_type) \
+ after(dependency_alternatives) \
+ get(odb::nested2_get (this.dependencies)) \
+ set(odb::nested2_set (this.dependencies, std::move (?))) \
id_column("") key_column("") value_column("dep_")
// tests
//
#pragma db member(tests) id_column("") value_column("test_")
+ // distribution_values
+ //
+ #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.
+ //
+ #pragma db member(alt_naming) default(false)
+
+ // *_build
+ //
+ // 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("")
+
+ // buildfiles
+ //
+ #pragma db member(buildfiles) id_column("") value_column("")
+
private:
friend class odb::access;
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
{
@@ -786,46 +983,6 @@ namespace bpkg
shared_ptr<available_package> package;
};
- // Query the available packages that optionally satisfy the specified
- // version constraint and return them in the version descending order, by
- // default. Note that a stub satisfies any constraint.
- //
- odb::result<available_package>
- query_available (database&,
- const package_name&,
- const optional<version_constraint>&,
- bool order = true);
-
- // Only return packages that are in the specified repository fragments, their
- // complements or prerequisites (if prereq is true), recursively. While you
- // could maybe come up with a (barely comprehensible) view/query to achieve
- // this, doing it on the "client side" is definitely more straightforward.
- //
- vector<shared_ptr<available_package>>
- filter (const shared_ptr<repository_fragment>&,
- odb::result<available_package>&&,
- bool prereq = true);
-
- pair<shared_ptr<available_package>, shared_ptr<repository_fragment>>
- filter_one (const shared_ptr<repository_fragment>&,
- odb::result<available_package>&&,
- bool prereq = true);
-
- shared_ptr<repository_fragment>
- filter (const shared_ptr<repository_fragment>&,
- const shared_ptr<available_package>&,
- bool prereq = true);
-
- vector<pair<shared_ptr<available_package>, shared_ptr<repository_fragment>>>
- filter (const vector<shared_ptr<repository_fragment>>&,
- odb::result<available_package>&&,
- bool prereq = true);
-
- pair<shared_ptr<available_package>, shared_ptr<repository_fragment>>
- filter_one (const vector<shared_ptr<repository_fragment>>&,
- odb::result<available_package>&&,
- bool prereq = true);
-
// Check if there are packages available in the specified configurations. If
// that's not the case then print the info message into the diag record or,
// if it is NULL, print the error message and fail.
@@ -920,21 +1077,35 @@ namespace bpkg
}
// A map of "effective" prerequisites (i.e., pointers to other selected
- // packages) to optional version constraint. Note that because it is a
- // single constraint, we don't support multiple dependencies on the same
- // package (e.g., two ranges of versions). See pkg_configure().
+ // packages) to optional version constraint (plus some other info). Note
+ // that because it is a single constraint, we don't support multiple
+ // dependencies on the same package (e.g., two ranges of versions). See
+ // pkg_configure().
//
// Note also that the pointer can refer to a selected package in another
// database.
//
class selected_package;
+ #pragma db value
+ struct prerequisite_info
+ {
+ // The "tightest" version constraint among all dependencies resolved to
+ // this prerequisite.
+ //
+ optional<version_constraint> constraint;
+
+ // Database mapping.
+ //
+ #pragma db member(constraint) column("")
+ };
+
// Note that the keys for this map need to be created with the database
// passed to their constructor, which is required for persisting them (see
// _selected_package_ref() implementation for details).
//
using package_prerequisites = std::map<lazy_shared_ptr<selected_package>,
- optional<version_constraint>,
+ prerequisite_info,
compare_lazy_ptr>;
// Database mapping for lazy_shared_ptr<selected_package> to configuration
@@ -964,6 +1135,30 @@ namespace bpkg
to(bpkg::_selected_package_ref (?)) \
from(std::move (?).to_ptr (*db))
+ enum class config_source
+ {
+ user, // User configuration specified on command line.
+ dependent, // Dependent-imposed configuration from prefer/require clauses.
+ reflect // Package-reflected configuration from reflect clause.
+ };
+
+ string
+ to_string (config_source);
+
+ config_source
+ to_config_source (const string&); // May throw std::invalid_argument.
+
+ #pragma db map type(config_source) as(string) \
+ to(to_string (?)) \
+ from(bpkg::to_config_source (?))
+
+ #pragma db value
+ struct config_variable
+ {
+ string name;
+ config_source source;
+ };
+
#pragma db object pointer(shared_ptr) session
class selected_package
{
@@ -1016,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
@@ -1030,18 +1225,46 @@ namespace bpkg
//
optional<std::string> manifest_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.
+ // 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 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 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
@@ -1065,7 +1288,10 @@ namespace bpkg
// pkg-unpack --existing <dir>
//
- (repository_fragment.empty () && !archive);
+ // Note that the system package can have no repository associated (see
+ // imaginary system repository in pkg-build.cxx for details).
+ //
+ (repository_fragment.empty () && !archive && !system ());
}
// Represent the wildcard version with the "*" string. Represent naturally
@@ -1083,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.
//
@@ -1095,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
@@ -1104,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;
}
@@ -1114,6 +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,
@@ -1128,6 +1383,7 @@ namespace bpkg
optional<dir_path> sr,
bool ps,
optional<std::string> mc,
+ optional<std::string> bc,
optional<dir_path> o,
package_prerequisites pps)
: name (move (n)),
@@ -1142,6 +1398,7 @@ namespace bpkg
src_root (move (sr)),
purge_src (ps),
manifest_checksum (move (mc)),
+ buildfiles_checksum (move (bc)),
out_root (move (o)),
prerequisites (move (pps)) {}
@@ -1156,6 +1413,16 @@ namespace bpkg
return os << p.string ();
}
+ // Create a transient (or fake, if you prefer) available_package object
+ // corresponding to the specified selected object, which is expected to not
+ // be in the broken state. Note that the package locations list is left
+ // empty.
+ //
+ shared_ptr<available_package>
+ make_available (const common_options&,
+ database&,
+ const shared_ptr<selected_package>&);
+
// Try to find a dependency in the dependency configurations (see
// database::dependency_configs() for details). Return pointers to the found
// package and the configuration it belongs to. Return a pair of NULLs if no
@@ -1171,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
@@ -1199,8 +1469,6 @@ namespace bpkg
// - The manifest file located in the specified directory is not parsed, and
// so is not checked to match the specified package name and version.
//
- class common_options;
-
// Note: loads selected packages.
//
optional<version>
@@ -1348,40 +1616,104 @@ namespace bpkg
// not detached during such map lifetimes. Considers both package name and
// database for objects comparison.
//
- struct config_package
+ struct package_key
{
- database& db;
- package_name name;
+ reference_wrapper<database> db;
+ package_name name;
- config_package (database& d, package_name n): db (d), name (move (n)) {}
+ package_key (database& d, package_name n): db (d), name (move (n)) {}
+
+ bool
+ operator== (const package_key& v) const
+ {
+ // See operator==(database, database).
+ //
+ return name == v.name && &db.get () == &v.db.get ();
+ }
+
+ bool
+ operator!= (const package_key& v) const
+ {
+ return !(*this == v);
+ }
+
+ bool
+ operator< (const package_key&) const;
+
+ // Return the package string representation in the form:
+ //
+ // <name>[ <config-dir>]
+ //
+ std::string
+ string () const;
+ };
+
+ inline ostream&
+ operator<< (ostream& os, const package_key& p)
+ {
+ 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).
//
- config_package (database& d, string n)
+ package_version_key (database& d, string n)
: db (d),
- name (n.empty () ? package_name () : package_name (move (n))) {}
+ name (move (n), package_name::raw_string) {}
bool
- operator== (const config_package& v) const
+ operator== (const package_version_key& v) const
{
// See operator==(database, database).
//
- return name == v.name && &db == &v.db;
+ return name == v.name &&
+ version == v.version &&
+ &db.get () == &v.db.get ();
}
bool
- operator< (const config_package& v) const
+ operator!= (const package_version_key& v) const
{
- // See operator==(database, database).
- //
- int r (name.compare (v.name));
- return r != 0 ? (r < 0) : (&db < &v.db);
+ 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 () const;
+ 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")