From def2c2dfaf5374f139b310c4f05b0614cb99359e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 28 Mar 2022 15:04:35 +0200 Subject: Implement dependency configuration negotiation For the detailed history see the dep-config and dep-config-neg branches. --- bpkg/package-configuration.hxx | 206 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 bpkg/package-configuration.hxx (limited to 'bpkg/package-configuration.hxx') diff --git a/bpkg/package-configuration.hxx b/bpkg/package-configuration.hxx new file mode 100644 index 0000000..73f05ff --- /dev/null +++ b/bpkg/package-configuration.hxx @@ -0,0 +1,206 @@ +// file : bpkg/package-configuration.hxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#ifndef BPKG_PACKAGE_CONFIGURATION_HXX +#define BPKG_PACKAGE_CONFIGURATION_HXX + +#include // build2::names +#include // build2::config::variable_origin + +#include +#include + +#include + +using namespace std; + +namespace bpkg +{ + class package_skeleton; + + // Serialize the variable value as a command line override. + // + string + serialize_cmdline (const string& name, const optional& value); + + struct config_variable_value + { + string name; + + // The variable_origin values have the following meaning: + // + // default -- default value from the config directive + // buildfile -- dependent configuration (config_source::dependent) + // override -- user configuration (config_source::user) + // undefined -- none of the above + // + build2::config::variable_origin origin; + + // Variable type name with absent signifying untyped. + // + optional type; + + // If origin is not undefined, then this is the reversed variable value + // with absent signifying NULL. + // + optional value; + + // If origin is buildfile, then this is the "originating dependent" which + // first set this variable to this value. + // + optional dependent; + + // If origin is buildfile, then this flag indicates whether the + // originating dependent has been encountered during the negotiation + // retry. + // + bool confirmed; + + public: + void + undefine () + { + origin = build2::config::variable_origin::undefined; + value = nullopt; + dependent = nullopt; + confirmed = false; + } + + string + serialize_cmdline () const + { + return bpkg::serialize_cmdline (name, value); + } + }; + + void + to_checksum (sha256&, const config_variable_value&); + + // A subset of config_variable_value for variable values set by the + // dependents (origin is buildfile). Used to track change history. + // + struct dependent_config_variable_value + { + string name; + optional value; + package_key dependent; + + public: + string + serialize_cmdline () const + { + return bpkg::serialize_cmdline (name, value); + } + }; + + inline bool + operator== (const dependent_config_variable_value& x, + const dependent_config_variable_value& y) + { + return x.name == y.name && x.value == y.value && x.dependent == y.dependent; + } + + class dependent_config_variable_values: + public small_vector + { + public: + const dependent_config_variable_value* + find (const string& name) const + { + auto i (find_if (begin (), end (), + [&name] (const dependent_config_variable_value& v) + { + return v.name == name; + })); + return i != end () ? &*i : nullptr; + } + }; + + class package_configuration: public vector + { + public: + package_key package; + bool system = false; // True if system package without skeleton info. + + explicit + package_configuration (package_key p): package (move (p)) {} + + config_variable_value* + find (const string& name) + { + auto i (find_if (begin (), end (), + [&name] (const config_variable_value& v) + { + return v.name == name; + })); + return i != end () ? &*i : nullptr; + } + + const config_variable_value* + find (const string& name) const + { + auto i (find_if (begin (), end (), + [&name] (const config_variable_value& v) + { + return v.name == name; + })); + return i != end () ? &*i : nullptr; + } + + // Print buildfile and override configuration variable values as command + // line overrides one per line with the specified indentation. After each + // variable also print in parenthesis its origin. If overrides is not + // NULL, then it is used to override the value/dependent information. + // + void + print (diag_record&, const char* indent, + const dependent_config_variable_values* overrides = nullptr) const; + }; + + class package_configurations: public small_vector + { + public: + // Note: may invalidate references. + // + package_configuration& + operator[] (const package_key& p) + { + auto i (find_if (begin (), end (), + [&p] (const package_configuration& pc) + { + return pc.package == p; + })); + if (i != end ()) + return *i; + + push_back (package_configuration (p)); + return back (); + } + + void + clear () + { + small_vector::clear (); + change_history_.clear (); + } + + // Implementation details. + // + public: + // Note: dependent_config_variable_values must be sorted by name. + // + small_vector change_history_; + }; + + // Negotiate the configuration for the specified dependencies of the + // specified dependent. Return true if the configuration has changed. + // + bool + negotiate_configuration ( + package_configurations&, + package_skeleton& dependent, + pair position, + const small_vector, 1>& dependencies); +} + +#endif // BPKG_PACKAGE_CONFIGURATION_HXX -- cgit v1.1