blob: 83d61050f36172ed480ac29b4b48becaddf02c8f [file] [log] [blame]
# 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),
)