def test_conf_list_operations_fails_with_wrong_types(text1, text2): c1 = ConfDefinition() c1.loads(text1) c1_value_type = type(c1.get("user.company.list:objs")).__name__ c2 = ConfDefinition() c2.loads(text2) with pytest.raises(ConanException) as exc_info: c1.update_conf_definition(c2) assert "It's not possible to compose list values and %s ones" % c1_value_type \ in str(exc_info.value)
def test_compose_conf_complex(): """ Testing the composition between several ConfDefiniton objects and with different value types """ text = textwrap.dedent("""\ user.company.cpu:jobs=10 user.company.build:ccflags=--m superflag zlib:user.company.check:shared=True zlib:user.company.check:shared_str="True" user.company.list:objs=[1, 2, 3, 4, 'mystr', {'a': 1}] user.company.network:proxies={'url': 'http://api.site.com/api', 'dataType': 'json', 'method': 'GET'} """) c = ConfDefinition() c.loads(text) text = textwrap.dedent("""\ user.company.cpu:jobs=5 user.company.build:ccflags=--m otherflag zlib:user.company.check:shared=! zlib:user.company.check:shared_str="False" user.company.list:objs+=[5, 6] user.company.list:objs=+0 user.company.list:objs+={'b': 2} user.company.network:proxies={'url': 'http://api.site.com/apiv2'} """) c2 = ConfDefinition() c2.loads(text) c.update_conf_definition(c2) expected_text = textwrap.dedent("""\ user.company.cpu:jobs=5 user.company.build:ccflags=--m otherflag user.company.list:objs=[0, 1, 2, 3, 4, 'mystr', {'a': 1}, 5, 6, {'b': 2}] user.company.network:proxies={'url': 'http://api.site.com/apiv2'} zlib:user.company.check:shared=! zlib:user.company.check:shared_str="False" """) if sys.version_info.major == 2: # problems with the order in Python 2.x text = c.dumps() assert all([line in text for line in expected_text.splitlines()]) else: assert c.dumps() == expected_text
class Profile(object): """A profile contains a set of setting (with values), environment variables """ def __init__(self): # Input sections, as defined by user profile files and command line self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.options = OptionsValues() self.build_requires = OrderedDict() # ref pattern: list of ref self.conf = ConfDefinition() # Cached processed values self.processed_settings = None # Settings with values, and smart completion self._user_options = None self._package_settings_values = None self.dev_reference = None # Reference of the package being develop @property def user_options(self): if self._user_options is None: self._user_options = self.options.copy() return self._user_options @property def package_settings_values(self): if self._package_settings_values is None: self._package_settings_values = {} for pkg, settings in self.package_settings.items(): self._package_settings_values[pkg] = list(settings.items()) return self._package_settings_values def process_settings(self, cache, preprocess=True): assert self.processed_settings is None, "processed settings must be None" self.processed_settings = cache.settings.copy() self.processed_settings.values = Values.from_list( list(self.settings.items())) if preprocess: settings_preprocessor.preprocess(self.processed_settings) # Redefine the profile settings values with the preprocessed ones # FIXME: Simplify the values.as_list() self.settings = OrderedDict( self.processed_settings.values.as_list()) # Preprocess also scoped settings for pkg, pkg_settings in self.package_settings.items(): pkg_profile = Profile() pkg_profile.settings = self.settings pkg_profile.update_settings(pkg_settings) try: pkg_profile.process_settings(cache=cache, preprocess=True) except Exception as e: pkg_profile = [ "{}={}".format(k, v) for k, v in pkg_profile.settings.items() ] raise ConanException( "Error in resulting settings for package" " '{}': {}\n{}".format(pkg, e, '\n'.join(pkg_profile))) # TODO: Assign the _validated_ settings and do not compute again def dumps(self): result = ["[settings]"] for name, value in self.settings.items(): result.append("%s=%s" % (name, value)) for package, values in self.package_settings.items(): for name, value in values.items(): result.append("%s:%s=%s" % (package, name, value)) result.append("[options]") result.append(self.options.dumps()) result.append("[build_requires]") for pattern, req_list in self.build_requires.items(): result.append("%s: %s" % (pattern, ", ".join(str(r) for r in req_list))) result.append("[env]") result.append(self.env_values.dumps()) if self.conf: result.append("[conf]") result.append(self.conf.dumps()) return "\n".join(result).replace("\n\n", "\n") def update(self, other): self.update_settings(other.settings) self.update_package_settings(other.package_settings) # this is the opposite other.env_values.update(self.env_values) self.env_values = other.env_values self.options.update(other.options) for pattern, req_list in other.build_requires.items(): self.build_requires.setdefault(pattern, []).extend(req_list) self.conf.update_conf_definition(other.conf) def update_settings(self, new_settings): """Mix the specified settings with the current profile. Specified settings are prioritized to profile""" assert (isinstance(new_settings, OrderedDict)) # apply the current profile res = copy.copy(self.settings) if new_settings: # Invalidate the current subsettings if the parent setting changes # Example: new_settings declare a different "compiler", # so invalidate the current "compiler.XXX" for name, value in new_settings.items(): if "." not in name: if name in self.settings and self.settings[name] != value: for cur_name, _ in self.settings.items(): if cur_name.startswith("%s." % name): del res[cur_name] # Now merge the new values res.update(new_settings) self.settings = res def update_package_settings(self, package_settings): """Mix the specified package settings with the specified profile. Specified package settings are prioritized to profile""" for package_name, settings in package_settings.items(): self.package_settings[package_name].update(settings)