class Profile(object): """A profile contains a set of setting (with values), environment variables and scopes""" def __init__(self): # Sections self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.scopes = Scopes() self.options = OptionsValues() @property def settings_values(self): return Values.from_list(list(self.settings.items())) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result @staticmethod def read_file(profile_name, cwd, default_folder): """ Will look for "profile_name" in disk if profile_name is absolute path, in current folder if path is relative or in the default folder otherwise. return: a Profile object """ if not profile_name: return None if os.path.isabs(profile_name): profile_path = profile_name folder = os.path.dirname(profile_name) elif profile_name.startswith("."): # relative path name profile_path = os.path.abspath(os.path.join(cwd, profile_name)) folder = os.path.dirname(profile_path) else: folder = default_folder if not os.path.exists(folder): mkdir(folder) profile_path = os.path.join(folder, profile_name) try: text = load(profile_path) except IOError: if os.path.exists(folder): profiles = [name for name in os.listdir(folder) if not os.path.isdir(name)] else: profiles = [] current_profiles = ", ".join(profiles) or "[]" raise ConanException("Specified profile '%s' doesn't exist.\nExisting profiles: " "%s" % (profile_name, current_profiles)) try: text = text.replace("$PROFILE_DIR", os.path.abspath(folder)) # Allows PYTHONPATH=$PROFILE_DIR/pythontools return Profile.loads(text) except ConanException as exc: raise ConanException("Error reading '%s' profile: %s" % (profile_name, exc)) @staticmethod def loads(text): """ Parse and return a Profile object from a text config like representation """ def get_package_name_value(item): '''Parse items like package:name=value or name=value''' package_name = None if ":" in item: tmp = item.split(":", 1) package_name, item = tmp name, value = item.split("=", 1) name = name.strip() value = unquote(value) return package_name, name, value try: obj = Profile() doc = ConfigParser(text, allowed_fields=["settings", "env", "scopes", "options"]) for setting in doc.settings.splitlines(): setting = setting.strip() if setting and not setting.startswith("#"): if "=" not in setting: raise ConanException("Invalid setting line '%s'" % setting) package_name, name, value = get_package_name_value(setting) if package_name: obj.package_settings[package_name][name] = value else: obj.settings[name] = value if doc.scopes: obj.scopes = Scopes.from_list(doc.scopes.splitlines()) if doc.options: obj.options = OptionsValues.loads(doc.options) obj.env_values = EnvValues.loads(doc.env) return obj except ConanException: raise except Exception as exc: raise ConanException("Error parsing the profile text file: %s" % str(exc)) 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("[scopes]") if self.scopes[_root].get("dev", None): # FIXME: Ugly _root import del self.scopes[_root]["dev"] # Do not include dev scopes_txt = self.scopes.dumps() result.append(scopes_txt) result.append("[env]") result.append(self.env_values.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) self.update_scopes(other.scopes) # this is the opposite other.env_values.update(self.env_values) self.env_values = other.env_values self.options.update(other.options) def update_settings(self, new_settings): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_settings: self.settings.update(new_settings) 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) def update_scopes(self, new_scopes): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_scopes: self.scopes.update(new_scopes)
class Profile(object): """A profile contains a set of setting (with values), environment variables """ def __init__(self): # Sections self.processed_settings = None self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.options = OptionsValues() self.build_requires = OrderedDict() # ref pattern: list of ref 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()) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result 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()) 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) 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)
class Profile(object): """A profile contains a set of setting (with values), environment variables and scopes""" def __init__(self): # Sections self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.scopes = Scopes() self.options = OptionsValues() self.build_requires = OrderedDict( ) # conan_ref Pattern: list of conan_ref @property def settings_values(self): return Values.from_list(list(self.settings.items())) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result def dumps(self): result = ["[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("[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("[scopes]") if self.scopes[_root].get("dev", None): # FIXME: Ugly _root import del self.scopes[_root]["dev"] # Do not include dev scopes_txt = self.scopes.dumps() result.append(scopes_txt) result.append("[env]") result.append(self.env_values.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) self.update_scopes(other.scopes) # 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) def update_settings(self, new_settings): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_settings: self.settings.update(new_settings) 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) def update_scopes(self, new_scopes): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_scopes: self.scopes.update(new_scopes)
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)
class Profile(object): '''A profile contains a set of setting (with values), environment variables and scopes''' def __init__(self): # Sections self._settings = OrderedDict() self._package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.scopes = Scopes() @property def package_settings(self): return {package_name: list(settings.items()) for package_name, settings in self._package_settings.items()} @property def settings(self): return list(self._settings.items()) @staticmethod def loads(text): def get_package_name_value(item): '''Parse items like package:name=value or name=value''' package_name = None if ":" in item: tmp = item.split(":", 1) package_name, item = tmp name, value = item.split("=", 1) name = name.strip() value = unquote(value) return package_name, name, value try: obj = Profile() doc = ConfigParser(text, allowed_fields=["settings", "env", "scopes"]) for setting in doc.settings.splitlines(): setting = setting.strip() if setting and not setting.startswith("#"): if "=" not in setting: raise ConanException("Invalid setting line '%s'" % setting) package_name, name, value = get_package_name_value(setting) if package_name: obj._package_settings[package_name][name] = value else: obj._settings[name] = value if doc.scopes: obj.scopes = Scopes.from_list(doc.scopes.splitlines()) obj.env_values = EnvValues.loads(doc.env) obj._order() return obj except ConanException: raise except Exception as exc: raise ConanException("Error parsing the profile text file: %s" % str(exc)) def dumps(self): self._order() # gets in order the settings def dump_simple_items(items, result): for name, value in items: result.append("%s=%s" % (name, value)) def dump_package_items(items, result): for package, values in items: for name, value in values.items(): result.append("%s:%s=%s" % (package, name, value)) result = ["[settings]"] dump_simple_items(self._settings.items(), result) dump_package_items(self._package_settings.items(), result) result.append("[scopes]") if self.scopes[_root].get("dev", None): # FIXME: Ugly _root import del self.scopes[_root]["dev"] # Do not include dev scopes_txt = self.scopes.dumps() result.append(scopes_txt) result.append("[env]") result.append(self.env_values.dumps()) return "\n".join(result).replace("\n\n", "\n") def update_settings(self, new_settings): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_settings: self._settings.update(new_settings) self._order() 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 self._package_settings.items(): if package_name in package_settings: settings.update(dict(package_settings[package_name])) # The rest of new packages settings for package_name, settings in package_settings.items(): if package_name not in self._package_settings: self._package_settings[package_name].update(dict(settings)) self._order() def _mix_env_with_new(self, env_dict, new_env): res_env = OrderedDict() for name, value in new_env: if name in env_dict: del env_dict[name] res_env[name] = value # Insert first in the result for name, value in env_dict.items(): res_env[name] = value # Insert the rest of env vars at the end return res_env def update_packages_env(self, new_packages_env): '''Priorize new_packages_env to override the current package_env''' if not new_packages_env: return res_env = defaultdict(OrderedDict) # Mix the common packages env for package, env_vars in self._package_env.items(): new_env = new_packages_env.get(package, []) res_env[package] = self._mix_env_with_new(env_vars, new_env) # The rest of new packages env variables for package, env_vars in new_packages_env.items(): if package not in res_env: for name, value in env_vars: res_env[package][name] = value # Insert the rest of env vars at the end self._package_env = res_env def update_scopes(self, new_scopes): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_scopes: self.scopes.update(new_scopes) self._order() def _order(self): def order_single_settings(settings): ret = OrderedDict() # Insert in a good order for func in [lambda x: "." not in x, # First the principal settings lambda x: "." in x]: for name, value in settings.items(): if func(name): ret[name] = value return ret # Order global settings self._settings = order_single_settings(self._settings) # Order package settings for package_name, settings in self._package_settings.items(): self._package_settings[package_name] = order_single_settings(settings)
class Profile(object): """A profile contains a set of setting (with values), environment variables and scopes""" def __init__(self): # Sections self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.scopes = Scopes() self.options = OptionsValues() self.build_requires = OrderedDict() # conan_ref Pattern: list of conan_ref @property def settings_values(self): return Values.from_list(list(self.settings.items())) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result def dumps(self): result = ["[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("[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("[scopes]") if self.scopes[_root].get("dev", None): # FIXME: Ugly _root import del self.scopes[_root]["dev"] # Do not include dev scopes_txt = self.scopes.dumps() result.append(scopes_txt) result.append("[env]") result.append(self.env_values.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) self.update_scopes(other.scopes) # 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) def update_settings(self, new_settings): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_settings: self.settings.update(new_settings) 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) def update_scopes(self, new_scopes): '''Mix the specified settings with the current profile. Specified settings are prioritized to profile''' # apply the current profile if new_scopes: self.scopes.update(new_scopes)
class Profile(object): """A profile contains a set of setting (with values), environment variables """ def __init__(self): # Sections self.settings = OrderedDict() self.package_settings = defaultdict(OrderedDict) self.env_values = EnvValues() self.options = OptionsValues() self.build_requires = OrderedDict() # conan_ref Pattern: list of conan_ref @property def settings_values(self): return Values.from_list(list(self.settings.items())) @property def package_settings_values(self): result = {} for pkg, settings in self.package_settings.items(): result[pkg] = list(settings.items()) return result 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()) 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) 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)