# Copyright 2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 __all__ = ( 'LocationsManager', ) import codecs from portage import os, eapi_is_supported, _encodings, _unicode_encode from portage.const import CUSTOM_PROFILE_PATH, GLOBAL_CONFIG_PATH, \ PROFILE_PATH, USER_CONFIG_PATH from portage.exception import DirectoryNotFound, ParseError from portage.localization import _ from portage.util import ensure_dirs, grabfile, \ normalize_path, shlex_split, writemsg class LocationsManager(object): def __init__(self, config_root=None, eprefix=None, config_profile_path=None, local_config=True, \ target_root=None): self.user_profile_dir = None self._local_repo_conf_path = None self.eprefix = eprefix self.config_root = config_root self.target_root = target_root self._user_config = local_config if self.eprefix is None: self.eprefix = "" if self.config_root is None: self.config_root = self.eprefix + os.sep self.config_root = normalize_path(os.path.abspath( self.config_root)).rstrip(os.path.sep) + os.path.sep self._check_var_directory("PORTAGE_CONFIGROOT", self.config_root) self.abs_user_config = os.path.join(self.config_root, USER_CONFIG_PATH) if not config_profile_path: config_profile_path = \ os.path.join(self.config_root, PROFILE_PATH) if os.path.isdir(config_profile_path): self.profile_path = config_profile_path else: config_profile_path = \ os.path.join(self.abs_user_config, 'make.profile') if os.path.isdir(config_profile_path): self.profile_path = config_profile_path else: self.profile_path = None else: self.profile_path = config_profile_path # The symlink might not exist or might not be a symlink. self.profiles = [] if self.profile_path is not None: try: self._addProfile(os.path.realpath(self.profile_path)) except ParseError as e: writemsg(_("!!! Unable to parse profile: '%s'\n") % \ self.profile_path, noiselevel=-1) writemsg("!!! ParseError: %s\n" % str(e), noiselevel=-1) self.profiles = [] if self._user_config and self.profiles: custom_prof = os.path.join( self.config_root, CUSTOM_PROFILE_PATH) if os.path.exists(custom_prof): self.user_profile_dir = custom_prof self.profiles.append(custom_prof) del custom_prof self.profiles = tuple(self.profiles) def _check_var_directory(self, varname, var): if not os.path.isdir(var): writemsg(_("!!! Error: %s='%s' is not a directory. " "Please correct this.\n") % (varname, var), noiselevel=-1) raise DirectoryNotFound(var) def _addProfile(self, currentPath): parentsFile = os.path.join(currentPath, "parent") eapi_file = os.path.join(currentPath, "eapi") try: eapi = codecs.open(_unicode_encode(eapi_file, encoding=_encodings['fs'], errors='strict'), mode='r', encoding=_encodings['content'], errors='replace' ).readline().strip() except IOError: pass else: if not eapi_is_supported(eapi): raise ParseError(_( "Profile contains unsupported " "EAPI '%s': '%s'") % \ (eapi, os.path.realpath(eapi_file),)) if os.path.exists(parentsFile): parents = grabfile(parentsFile) if not parents: raise ParseError( _("Empty parent file: '%s'") % parentsFile) for parentPath in parents: parentPath = normalize_path(os.path.join( currentPath, parentPath)) if os.path.exists(parentPath): self._addProfile(parentPath) else: raise ParseError( _("Parent '%s' not found: '%s'") % \ (parentPath, parentsFile)) self.profiles.append(currentPath) def set_root_override(self, root_overwrite=None): # Allow ROOT setting to come from make.conf if it's not overridden # by the constructor argument (from the calling environment). if self.target_root is None and root_overwrite is not None: self.target_root = root_overwrite if not self.target_root.strip(): self.target_root = None if self.target_root is None: self.target_root = "/" self.target_root = normalize_path(os.path.abspath( self.target_root)).rstrip(os.path.sep) + os.path.sep ensure_dirs(self.target_root) self._check_var_directory("ROOT", self.target_root) self.eroot = self.target_root.rstrip(os.sep) + self.eprefix + os.sep # make.globals should not be relative to config_root # because it only contains constants. However, if EPREFIX # is set then there are two possible scenarios: # 1) If $ROOT == "/" then make.globals should be # relative to EPREFIX. # 2) If $ROOT != "/" then the correct location of # make.globals needs to be specified in the constructor # parameters, since it's a property of the host system # (and the current config represents the target system). self.global_config_path = GLOBAL_CONFIG_PATH if self.eprefix: if self.target_root == "/": # case (1) above self.global_config_path = os.path.join(self.eprefix, GLOBAL_CONFIG_PATH.lstrip(os.sep)) else: # case (2) above # For now, just assume make.globals is relative # to EPREFIX. # TODO: Pass in more info to the constructor, # so we know the host system configuration. self.global_config_path = os.path.join(self.eprefix, GLOBAL_CONFIG_PATH.lstrip(os.sep)) def set_port_dirs(self, portdir, portdir_overlay): self.portdir = portdir self.portdir_overlay = portdir_overlay if self.portdir_overlay is None: self.portdir_overlay = "" self.overlay_profiles = [] for ov in shlex_split(self.portdir_overlay): ov = normalize_path(ov) profiles_dir = os.path.join(ov, "profiles") if os.path.isdir(profiles_dir): self.overlay_profiles.append(profiles_dir) self.profile_locations = [os.path.join(portdir, "profiles")] + self.overlay_profiles self.profile_and_user_locations = self.profile_locations[:] if self._user_config: self.profile_and_user_locations.append(self.abs_user_config) self.profile_locations = tuple(self.profile_locations) self.profile_and_user_locations = tuple(self.profile_and_user_locations) self.pmask_locations = ( tuple([os.path.join(portdir, "profiles")] + self.overlay_profiles), tuple(self.profiles), )