def loads(text): # This is used for search functionality, search prints info from this file # Other use is from the BinariesAnalyzer, to get the recipe_hash and know # if package is outdated parser = ConfigParser(text, [ "settings", "full_settings", "options", "full_options", "requires", "full_requires", "scope", "recipe_hash", "env" ], raise_unexpected_field=False) result = ConanInfo() result.invalid = None result.settings = Values.loads(parser.settings) result.full_settings = Values.loads(parser.full_settings) result.options = OptionsValues.loads(parser.options) result.full_options = OptionsValues.loads(parser.full_options) result.full_requires = _PackageReferenceList.loads( parser.full_requires) # Requires after load are not used for any purpose, CAN'T be used, they are not correct result.requires = RequirementsInfo(result.full_requires, "semver_direct_mode") result.recipe_hash = parser.recipe_hash or None # TODO: Missing handling paring of requires, but not necessary now result.env_values = EnvValues.loads(parser.env) return result
def settings_defaults(self, settings): default_settings = self.get_conf("settings_defaults") values = Values.from_list(default_settings) settings.values = values mixed_settings = _mix_settings_with_env(default_settings) values = Values.from_list(mixed_settings) settings.values = values
def deserialize(data): res = ConanInfo() res.settings = Values.deserialize(data["settings"]) res.full_settings = Values.deserialize(data["full_settings"]) res.options = OptionsValues.deserialize(data["options"]) res.full_options = OptionsValues.deserialize(data["full_options"]) res.requires = RequirementsInfo.deserialize(data["requires"]) res.full_requires = RequirementsList.deserialize(data["full_requires"]) return res
def loads(text): parser = ConfigParser(text, ["settings", "full_settings", "options", "full_options", "requires", "full_requires"]) result = ConanInfo() result.settings = Values.loads(parser.settings) result.full_settings = Values.loads(parser.full_settings) result.options = OptionsValues.loads(parser.options) result.full_options = OptionsValues.loads(parser.full_options) result.full_requires = RequirementsList.loads(parser.full_requires) result.requires = RequirementsInfo(result.full_requires) # TODO: Missing handling paring of requires, but not necessary now return result
def from_list(data): result = OptionsValues() by_package = defaultdict(list) for k, v in data: tokens = k.split(":") if len(tokens) == 2: package, option = tokens by_package[package.strip()].append((option, v)) else: by_package[None].append((k, v)) result._options = Values.from_list(by_package[None]) for k, v in by_package.items(): if k is not None: result._reqs_options[k] = Values.from_list(v) return result
def load_conanfile(self, conanfile_path, output, processed_profile, consumer=False, reference=None): """ loads a ConanFile object from the given file """ conanfile = self.load_basic(conanfile_path, output, reference) if processed_profile._dev_reference and processed_profile._dev_reference == reference: conanfile.develop = True try: # Prepare the settings for the loaded conanfile # Mixing the global settings with the specified for that name if exist tmp_settings = processed_profile._settings.copy() if (processed_profile._package_settings and conanfile.name in processed_profile._package_settings): # Update the values, keeping old ones (confusing assign) values_tuple = processed_profile._package_settings[ conanfile.name] tmp_settings.values = Values.from_list(values_tuple) conanfile.initialize(tmp_settings, processed_profile._env_values) if consumer: conanfile.develop = True processed_profile._user_options.descope_options(conanfile.name) conanfile.options.initialize_upstream( processed_profile._user_options, name=conanfile.name) processed_profile._user_options.clear_unscoped_options() return conanfile except Exception as e: # re-raise with file name raise ConanException("%s: %s" % (conanfile_path, str(e)))
def _loader(self, current_path=None, user_settings_values=None, package_settings=None, user_options_values=None, scopes=None, env_values=None, use_conaninfo=True): # The disk settings definition, already including the default disk values settings = self._client_cache.settings conaninfo_scopes = Scopes() user_options = OptionsValues(user_options_values) mixed_env_values = EnvValues() mixed_env_values.update(env_values) if current_path: conan_info_path = os.path.join(current_path, CONANINFO) if use_conaninfo and os.path.exists(conan_info_path): existing_info = ConanInfo.load_file(conan_info_path) settings.values = existing_info.full_settings options = existing_info.full_options # Take existing options from conaninfo.txt options.update(user_options) user_options = options conaninfo_scopes = existing_info.scope # Update with info (prioritize user input) mixed_env_values.update(existing_info.env_values) if user_settings_values: aux_values = Values.from_list(user_settings_values) settings.values = aux_values if scopes: conaninfo_scopes.update_scope(scopes) self._current_scopes = conaninfo_scopes return ConanFileLoader(self._runner, settings, package_settings=package_settings, options=user_options, scopes=conaninfo_scopes, env_values=mixed_env_values)
def setUp(self): package_options = PackageOptions.loads("""{static: [True, False], optimized: [2, 3, 4], path: ANY}""") package_options.values = Values.loads( "static=True\noptimized=3\npath=NOTDEF") self.sut = Options(package_options)
def loads(text): parser = ConfigParser(text, ["settings", "full_settings", "options", "full_options", "requires", "full_requires", "scope", "recipe_hash", "env"], raise_unexpected_field=False) result = ConanInfo() result.settings = Values.loads(parser.settings) result.full_settings = Values.loads(parser.full_settings) result.options = OptionsValues.loads(parser.options) result.full_options = OptionsValues.loads(parser.full_options) result.full_requires = RequirementsList.loads(parser.full_requires) result.requires = RequirementsInfo(result.full_requires) result.recipe_hash = parser.recipe_hash or None # TODO: Missing handling paring of requires, but not necessary now result.env_values = EnvValues.loads(parser.env) return result
def load_conan(self, conanfile_path, output, consumer=False, reference=None): """ loads a ConanFile object from the given file """ loaded, filename = self._parse_file(conanfile_path) try: result = self._parse_module(loaded, consumer, filename) # Prepare the settings for the loaded conanfile # Mixing the global settings with the specified for that name if exist tmp_settings = self._settings.copy() if self._package_settings and result.name in self._package_settings: # Update the values, keeping old ones (confusing assign) values_tuple = self._package_settings[result.name] tmp_settings.values = Values.from_list(values_tuple) user, channel = (reference.user, reference.channel) if reference else (None, None) # Instance the conanfile result = result(output, self._runner, tmp_settings, os.path.dirname(conanfile_path), user, channel) # Assign environment result._env_values.update(self._env_values) if consumer: self._user_options.descope_options(result.name) result.options.initialize_upstream(self._user_options) # If this is the consumer project, it has no name result.scope = self._scopes.package_scope() else: result.scope = self._scopes.package_scope(result.name) return result except Exception as e: # re-raise with file name raise ConanException("%s: %s" % (conanfile_path, str(e)))
def process_settings(self, cache, preprocess=True): 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)))
def _loader(self, current_path=None, user_settings_values=None, user_options_values=None, scopes=None): # The disk settings definition, already including the default disk values settings = self._paths.settings options = OptionsValues() conaninfo_scopes = Scopes() if current_path: conan_info_path = os.path.join(current_path, CONANINFO) if os.path.exists(conan_info_path): existing_info = ConanInfo.load_file(conan_info_path) settings.values = existing_info.full_settings options = existing_info.full_options # Take existing options from conaninfo.txt conaninfo_scopes = existing_info.scope if user_settings_values: aux_values = Values.from_list(user_settings_values) settings.values = aux_values if user_options_values is not None: # Install will pass an empty list [] # Install OVERWRITES options, existing options in CONANINFO are not taken # into account, just those from CONANFILE + user command line options = OptionsValues.from_list(user_options_values) if scopes: conaninfo_scopes.update_scope(scopes) self._current_scopes = conaninfo_scopes return ConanFileLoader(self._runner, settings, options=options, scopes=conaninfo_scopes)
def _loader(self, current_path=None, user_settings_values=None, user_options_values=None): # The disk settings definition, already including the default disk values settings = self._paths.settings options = OptionsValues() if current_path: conan_info_path = os.path.join(current_path, CONANINFO) if os.path.exists(conan_info_path): existing_info = ConanInfo.load_file(conan_info_path) settings.values = existing_info.full_settings options = existing_info.full_options # Take existing options from conaninfo.txt if user_settings_values: aux_values = Values.from_list(user_settings_values) settings.values = aux_values if user_options_values is not None: # Install will pass an empty list [] # Install OVERWRITES options, existing options in CONANINFO are not taken # into account, just those from CONANFILE + user command line options = OptionsValues.from_list(user_options_values) return ConanFileLoader(self._runner, settings, options=options)
def loads(text): parser = ConfigParser(text, ["settings", "full_settings", "options", "full_options", "requires", "full_requires", "scope", "recipe_hash", "env"], raise_unexpected_field=False) result = ConanInfo() result.settings = Values.loads(parser.settings) result.full_settings = Values.loads(parser.full_settings) result.options = OptionsValues.loads(parser.options) result.full_options = OptionsValues.loads(parser.full_options) result.full_requires = RequirementsList.loads(parser.full_requires) result.requires = RequirementsInfo(result.full_requires, None) result.recipe_hash = parser.recipe_hash or None # TODO: Missing handling paring of requires, but not necessary now result.scope = Scopes.loads(parser.scope) result.env_values = EnvValues.loads(parser.env) return result
def process_settings(self, cache, preprocess=True): 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())
def initialize_upstream(self, values): """ used to propagate from downstream the options to the upper requirements """ if values is not None: assert isinstance(values, OptionsValues) self._options.values = values._options for name, option_values in values._reqs_options.items(): self._reqs_options.setdefault(name, Values()).update(option_values)
def _initialize_conanfile(conanfile, processed_profile): # Prepare the settings for the loaded conanfile # Mixing the global settings with the specified for that name if exist tmp_settings = processed_profile._settings.copy() if (processed_profile._package_settings and conanfile.name in processed_profile._package_settings): # Update the values, keeping old ones (confusing assign) values_tuple = processed_profile._package_settings[conanfile.name] tmp_settings.values = Values.from_list(values_tuple) conanfile.initialize(tmp_settings, processed_profile._env_values)
def propagate_upstream(self, values, down_ref, own_ref, output): """ used to propagate from downstream the options to the upper requirements """ if values is not None: assert isinstance(values, OptionsValues) own_values = values.pop(own_ref.name) self._options.propagate_upstream(own_values, down_ref, own_ref, output) for name, option_values in sorted(list(values._reqs_options.items())): self._reqs_options.setdefault(name, Values()).propagate_upstream(option_values, down_ref, own_ref, output, name)
def simple_test(self): v = Values() self.assertEqual(v.compiler, None) v.compiler = 3 self.assertTrue(v.compiler == "3") self.assertEqual(v.compiler.version, None) v.compiler.version = "asfaf" self.assertEqual(v.compiler.version, "asfaf") my_list = v.as_list() self.assertEqual(my_list, [('compiler', '3'), ('compiler.version', 'asfaf')]) values = Values.from_list(my_list) self.assertEqual(values.dumps(), v.dumps()) v.compiler = None self.assertEqual(v.as_list(), [('compiler', 'None')]) self.assertEqual(v.dumps(), "compiler=None")
def load_conan(self, conanfile_path, output, consumer=False, reference=None): """ loads a ConanFile object from the given file """ loaded, filename = self._parse_file(conanfile_path) try: result = self._parse_module(loaded, consumer, filename) # Prepare the settings for the loaded conanfile # Mixing the global settings with the specified for that name if exist tmp_settings = self._settings.copy() if self._package_settings and result.name in self._package_settings: # Update the values, keeping old ones (confusing assign) values_tuple = self._package_settings[result.name] tmp_settings.values = Values.from_list(values_tuple) user, channel = (reference.user, reference.channel) if reference else (None, None) # Instance the conanfile result = result(output, self._runner, tmp_settings, os.path.dirname(conanfile_path), user, channel) # Prepare the env variables mixing global env vars with the # package ones if name match tmp_env = [] # Copy only the global variables not present in package level vars for var_name, value in self._env: if result.name in self._package_env: if var_name not in self._package_env[result.name]: tmp_env.append((var_name, value)) else: tmp_env.append((var_name, value)) tmp_env.extend(self._package_env.get(result.name, [])) result.env = tmp_env if consumer: self._user_options.descope_options(result.name) result.options.initialize_upstream(self._user_options) # If this is the consumer project, it has no name result.scope = self._scopes.package_scope() else: result.scope = self._scopes.package_scope(result.name) return result except Exception as e: # re-raise with file name raise ConanException("%s: %s" % (conanfile_path, str(e)))
def loads(text): result = OptionsValues() for line in text.splitlines(): line = line.strip() if not line: continue tokens = line.split(":") if len(tokens) == 2: package, option = tokens current = result._reqs_options.setdefault( package.strip(), Values()) else: option = tokens[0].strip() current = result._options current.add(option) return result
def load_conan(self, conanfile_path, output, consumer=False, reference=None, local=False): """ loads a ConanFile object from the given file """ result = load_conanfile_class(conanfile_path) try: # Prepare the settings for the loaded conanfile # Mixing the global settings with the specified for that name if exist tmp_settings = self._settings.copy() if self._package_settings and result.name in self._package_settings: # Update the values, keeping old ones (confusing assign) values_tuple = self._package_settings[result.name] tmp_settings.values = Values.from_list(values_tuple) if reference: result.name = reference.name result.version = reference.version user, channel = reference.user, reference.channel else: user, channel = None, None # Instance the conanfile result = result(output, self._runner, tmp_settings, user, channel, local) # Assign environment result._env_values.update(self._env_values) if consumer: self._user_options.descope_options(result.name) result.options.initialize_upstream(self._user_options, local=local) self._user_options.clear_unscoped_options() else: result.in_local_cache = True if consumer or (self.dev_reference and self.dev_reference == reference): result.develop = True return result except Exception as e: # re-raise with file name raise ConanException("%s: %s" % (conanfile_path, str(e)))
def simple_test(self): v = Values() self.assertEqual(v.compiler, None) v.compiler = 3 self.assertTrue(v.compiler == "3") self.assertEqual(v.compiler.version, None) v.compiler.version = "asfaf" self.assertEqual(v.compiler.version, "asfaf") my_list = v.as_list() self.assertEqual(my_list, [("compiler", "3"), ("compiler.version", "asfaf")]) values = Values.from_list(my_list) self.assertEqual(values.dumps(), v.dumps()) v.compiler = None self.assertEqual(v.as_list(), [("compiler", "None")]) self.assertEqual(v.dumps(), "compiler=None")
def _initialize_conanfile(conanfile, profile): # Prepare the settings for the loaded conanfile # Mixing the global settings with the specified for that name if exist tmp_settings = profile.processed_settings.copy() package_settings_values = profile.package_settings_values if package_settings_values: pkg_settings = package_settings_values.get(conanfile.name) if pkg_settings is None: # FIXME: This seems broken for packages without user/channel ref = "%s/%s@%s/%s" % (conanfile.name, conanfile.version, conanfile._conan_user, conanfile._conan_channel) for pattern, settings in package_settings_values.items(): if fnmatch.fnmatchcase(ref, pattern): pkg_settings = settings break if pkg_settings: tmp_settings.values = Values.from_list(pkg_settings) conanfile.initialize(tmp_settings, profile.env_values)
def loads(text): """ parses a multiline text in the form Package:option=value other_option=3 OtherPack:opt3=12.1 """ result = OptionsValues() for line in text.splitlines(): line = line.strip() if not line: continue # To avoid problems with values containing ":" as URLs name, value = line.split("=") tokens = name.split(":") if len(tokens) == 2: package, option = tokens current = result._reqs_options.setdefault(package.strip(), Values()) else: option = tokens[0].strip() current = result._options option = "%s=%s" % (option, value) current.add(option) return result
def values(self): return Values.from_list(self.values_list)
def values(self): result = OptionsValues() result._options = Values.from_list(self._options.values_list) for k, v in self._reqs_options.items(): result._reqs_options[k] = v.copy() return result
def deserialize(data): result = OptionsValues() result._options = Values.deserialize(data["options"]) for name, data_values in data["req_options"].items(): result._reqs_options[name] = Values.deserialize(data_values) return result
def __init__(self): self._options = Values() self._reqs_options = {} # {name("Boost": Values}
class OptionsValues(object): """ static= True, Boost.static = False, Poco.optimized = True """ def __init__(self): self._options = Values() self._reqs_options = {} # {name("Boost": Values} def __getitem__(self, item): return self._reqs_options.setdefault(item, Values()) def pop(self, item): return self._reqs_options.pop(item, None) def __repr__(self): return self.dumps() def __getattr__(self, attr): return getattr(self._options, attr) def copy(self): result = OptionsValues() result._options = self._options.copy() for k, v in self._reqs_options.items(): result._reqs_options[k] = v.copy() return result def __setattr__(self, attr, value): if attr[0] == "_": return super(OptionsValues, self).__setattr__(attr, value) return setattr(self._options, attr, value) def clear_indirect(self): for v in self._reqs_options.values(): v.clear() def as_list(self): result = [] options_list = self._options.as_list() if options_list: result.extend(options_list) for key in sorted(self._reqs_options.keys()): for line in self._reqs_options[key].as_list(): line_key, line_value = line result.append(("%s:%s" % (key, line_key), line_value)) return result @staticmethod def from_list(data): result = OptionsValues() by_package = defaultdict(list) for k, v in data: tokens = k.split(":") if len(tokens) == 2: package, option = tokens by_package[package.strip()].append((option, v)) else: by_package[None].append((k, v)) result._options = Values.from_list(by_package[None]) for k, v in by_package.items(): if k is not None: result._reqs_options[k] = Values.from_list(v) return result def dumps(self): result = [] for key, value in self.as_list(): result.append("%s=%s" % (key, value)) return "\n".join(result) @staticmethod def loads(text): result = OptionsValues() for line in text.splitlines(): line = line.strip() if not line: continue tokens = line.split(":") if len(tokens) == 2: package, option = tokens current = result._reqs_options.setdefault(package.strip(), Values()) else: option = tokens[0].strip() current = result._options current.add(option) return result @property def sha(self): result = [] result.append(self._options.sha) for key in sorted(list(self._reqs_options.keys())): result.append(self._reqs_options[key].sha) return sha1('\n'.join(result).encode()) def serialize(self): ret = {} ret["options"] = self._options.serialize() ret["req_options"] = {} for name, values in self._reqs_options.items(): ret["req_options"][name] = values.serialize() return ret @staticmethod def deserialize(data): result = OptionsValues() result._options = Values.deserialize(data["options"]) for name, data_values in data["req_options"].items(): result._reqs_options[name] = Values.deserialize(data_values) return result
def generate_default_config_file(): default_settings = detect_defaults_settings(self._output) default_setting_values = Values.from_list(default_settings) client_conf = default_client_conf + default_setting_values.dumps() save(self.conan_conf_path, normalize(client_conf))
def settings_values(self): return Values.from_list(list(self.settings.items()))
def settings_defaults(self): default_settings = self.get_conf("settings_defaults") values = Values.from_list(default_settings) return values
class OptionsValues(object): """ static= True, Boost.static = False, Poco.optimized = True """ def __init__(self): self._options = Values() self._reqs_options = {} # {name("Boost": Values} def __getitem__(self, item): return self._reqs_options.setdefault(item, Values()) def pop(self, item): return self._reqs_options.pop(item, None) def __repr__(self): return self.dumps() def __getattr__(self, attr): return getattr(self._options, attr) def copy(self): result = OptionsValues() result._options = self._options.copy() for k, v in self._reqs_options.items(): result._reqs_options[k] = v.copy() return result def __setattr__(self, attr, value): if attr[0] == "_": return super(OptionsValues, self).__setattr__(attr, value) return setattr(self._options, attr, value) def clear_indirect(self): for v in self._reqs_options.values(): v.clear() def as_list(self): result = [] options_list = self._options.as_list() if options_list: result.extend(options_list) for key in sorted(self._reqs_options.keys()): for line in self._reqs_options[key].as_list(): line_key, line_value = line result.append(("%s:%s" % (key, line_key), line_value)) return result @staticmethod def from_list(data): result = OptionsValues() by_package = defaultdict(list) for k, v in data: tokens = k.split(":") if len(tokens) == 2: package, option = tokens by_package[package.strip()].append((option, v)) else: by_package[None].append((k, v)) result._options = Values.from_list(by_package[None]) for k, v in by_package.items(): if k is not None: result._reqs_options[k] = Values.from_list(v) return result def dumps(self): result = [] for key, value in self.as_list(): result.append("%s=%s" % (key, value)) return "\n".join(result) @staticmethod def loads(text): """ parses a multiline text in the form Package:option=value other_option=3 OtherPack:opt3=12.1 """ result = OptionsValues() for line in text.splitlines(): line = line.strip() if not line: continue # To avoid problems with values containing ":" as URLs name, value = line.split("=") tokens = name.split(":") if len(tokens) == 2: package, option = tokens current = result._reqs_options.setdefault( package.strip(), Values()) else: option = tokens[0].strip() current = result._options option = "%s=%s" % (option, value) current.add(option) return result def sha(self, non_dev_requirements): result = [] result.append(self._options.sha) if non_dev_requirements is None: # Not filtering for key in sorted(list(self._reqs_options.keys())): result.append(self._reqs_options[key].sha) else: for key in sorted(list(self._reqs_options.keys())): non_dev = key in non_dev_requirements if non_dev: result.append(self._reqs_options[key].sha) return sha1('\n'.join(result).encode()) def serialize(self): ret = {} ret["options"] = self._options.serialize() ret["req_options"] = {} for name, values in self._reqs_options.items(): ret["req_options"][name] = values.serialize() return ret @staticmethod def deserialize(data): result = OptionsValues() result._options = Values.deserialize(data["options"]) for name, data_values in data["req_options"].items(): result._reqs_options[name] = Values.deserialize(data_values) return result
def __getitem__(self, item): return self._reqs_options.setdefault(item, Values())
def setUp(self): package_options = PackageOptions.loads("""{static: [True, False], optimized: [2, 3, 4], path: ANY}""") package_options.values = Values.loads("static=True\noptimized=3\npath=NOTDEF") self.sut = Options(package_options)
def generate_default_config_file(): default_settings = detect_defaults_settings(self._output) default_setting_values = Values.from_list(default_settings) client_conf = default_client_conf + default_setting_values.dumps() save(self.conan_conf_path, client_conf)