コード例 #1
0
ファイル: __init__.py プロジェクト: exheredludis/exheredtage
def load_default_config(settings, trees):

    if not _ENABLE_SET_CONFIG:
        return SetConfig(None, settings, trees)

    global_config_path = GLOBAL_CONFIG_PATH
    if portage.const.EPREFIX:
        global_config_path = os.path.join(portage.const.EPREFIX,
                                          GLOBAL_CONFIG_PATH.lstrip(os.sep))
    vcs_dirs = [
        _unicode_encode(x, encoding=_encodings['fs']) for x in VCS_DIRS
    ]

    def _getfiles():
        for path, dirs, files in os.walk(
                os.path.join(global_config_path, "sets")):
            for d in dirs:
                if d in vcs_dirs or d.startswith(b".") or d.endswith(b"~"):
                    dirs.remove(d)
            for f in files:
                if not f.startswith(b".") and not f.endswith(b"~"):
                    yield os.path.join(path, f)

        dbapi = trees["porttree"].dbapi
        for repo in dbapi.getRepositories():
            path = dbapi.getRepositoryPath(repo)
            yield os.path.join(path, "sets.conf")

        yield os.path.join(settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH,
                           "sets.conf")

    return SetConfig(_getfiles(), settings, trees)
コード例 #2
0
ファイル: __init__.py プロジェクト: aeroniero33/portage
def load_default_config(settings, trees):

	if not _ENABLE_SET_CONFIG:
		return SetConfig(None, settings, trees)

	global_config_path = GLOBAL_CONFIG_PATH
	if portage.const.EPREFIX:
		global_config_path = os.path.join(portage.const.EPREFIX,
			GLOBAL_CONFIG_PATH.lstrip(os.sep))
	vcs_dirs = [_unicode_encode(x, encoding=_encodings['fs']) for x in VCS_DIRS]
	def _getfiles():
		for path, dirs, files in os.walk(os.path.join(global_config_path, "sets")):
			for d in dirs:
				if d in vcs_dirs or d.startswith(b".") or d.endswith(b"~"):
					dirs.remove(d)
			for f in files:
				if not f.startswith(b".") and not f.endswith(b"~"):
					yield os.path.join(path, f)

		dbapi = trees["porttree"].dbapi
		for repo in dbapi.getRepositories():
			path = dbapi.getRepositoryPath(repo)
			yield os.path.join(path, "sets.conf")

		yield os.path.join(settings["PORTAGE_CONFIGROOT"],
			USER_CONFIG_PATH, "sets.conf")

	return SetConfig(_getfiles(), settings, trees)
コード例 #3
0
    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
        self.target_root = self.target_root or os.sep

        self.target_root = normalize_path(os.path.abspath(
            self.target_root)).rstrip(os.path.sep) + os.path.sep

        if self.sysroot != "/" and self.sysroot != self.target_root:
            writemsg(_("!!! Error: SYSROOT (currently %s) must "
                       "equal / or ROOT (currently %s).\n") %
                     (self.sysroot, self.target_root),
                     noiselevel=-1)
            raise InvalidLocation(self.sysroot)

        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

        self.global_config_path = GLOBAL_CONFIG_PATH
        if portage.const.EPREFIX:
            self.global_config_path = os.path.join(
                portage.const.EPREFIX, GLOBAL_CONFIG_PATH.lstrip(os.sep))
コード例 #4
0
ファイル: LocationsManager.py プロジェクト: gentoo/portage
	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
		self.target_root = self.target_root or os.sep

		self.target_root = normalize_path(os.path.abspath(
			self.target_root)).rstrip(os.path.sep) + os.path.sep

		if self.sysroot != "/" and self.sysroot != self.target_root:
			writemsg(_("!!! Error: SYSROOT (currently %s) must "
				"equal / or ROOT (currently %s).\n") %
				(self.sysroot, self.target_root),
				noiselevel=-1)
			raise InvalidLocation(self.sysroot)

		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

		self.global_config_path = GLOBAL_CONFIG_PATH
		if portage.const.EPREFIX:
			self.global_config_path = os.path.join(portage.const.EPREFIX,
				GLOBAL_CONFIG_PATH.lstrip(os.sep))
コード例 #5
0
def main():
    """
    If the current installation is still configured to use the old
    default BINPKG_COMPRESS=bzip2 setting, then patch make.globals
    inside ${ED} to maintain backward compatibility, ensuring that
    binary package consumers are not caught off guard. This is
    intended to be called from the ebuild as follows:

    pkg_preinst() {
            python_setup
            env -u BINPKG_COMPRESS
                    PYTHONPATH="${D%/}$(python_get_sitedir)${PYTHONPATH:+:${PYTHONPATH}}" \
                    "${PYTHON}" -m portage._compat_upgrade.binpkg_compression || die
    }
    """
    if (portage.settings.get(
            "BINPKG_COMPRESS",
            COMPAT_BINPKG_COMPRESS) == COMPAT_BINPKG_COMPRESS):
        config_path = os.path.join(os.environ["ED"],
                                   GLOBAL_CONFIG_PATH.lstrip(os.sep),
                                   "make.globals")
        with open(config_path) as f:
            content = f.read()
            compat_setting = 'BINPKG_COMPRESS="{}"'.format(
                COMPAT_BINPKG_COMPRESS)
            portage.output.EOutput().einfo(
                "Setting make.globals default {} for backward compatibility".
                format(compat_setting))
            content = re.sub("^BINPKG_COMPRESS=.*$",
                             compat_setting,
                             content,
                             flags=re.MULTILINE)
        with open(config_path, "wt") as f:
            f.write(content)
コード例 #6
0
ファイル: __init__.py プロジェクト: clickbeetle/portage-cb
def load_default_config(settings, trees):

    if not _ENABLE_SET_CONFIG:
        return SetConfig(None, settings, trees)

    global_config_path = GLOBAL_CONFIG_PATH
    if settings['EPREFIX']:
        global_config_path = os.path.join(settings['EPREFIX'],
                                          GLOBAL_CONFIG_PATH.lstrip(os.sep))

    def _getfiles():
        for path, dirs, files in os.walk(
                os.path.join(global_config_path, "sets")):
            for f in files:
                if not f.startswith(b'.'):
                    yield os.path.join(path, f)

        dbapi = trees["porttree"].dbapi
        for repo in dbapi.getRepositories():
            path = dbapi.getRepositoryPath(repo)
            yield os.path.join(path, "sets.conf")

        yield os.path.join(settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH,
                           "sets.conf")

    return SetConfig(_getfiles(), settings, trees)
コード例 #7
0
	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))
コード例 #8
0
ファイル: LocationsManager.py プロジェクト: entoo/portage-src
	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

		self.global_config_path = GLOBAL_CONFIG_PATH
		if portage.const.EPREFIX:
			self.global_config_path = os.path.join(portage.const.EPREFIX,
				GLOBAL_CONFIG_PATH.lstrip(os.sep))
コード例 #9
0
    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

        self.global_config_path = GLOBAL_CONFIG_PATH
        if portage.const.EPREFIX:
            self.global_config_path = os.path.join(
                portage.const.EPREFIX, GLOBAL_CONFIG_PATH.lstrip(os.sep))
コード例 #10
0
def load_default_config(settings, trees):

    if not _ENABLE_SET_CONFIG:
        return SetConfig(None, settings, trees)

    global_config_path = GLOBAL_CONFIG_PATH
    if settings["EPREFIX"]:
        global_config_path = os.path.join(settings["EPREFIX"], GLOBAL_CONFIG_PATH.lstrip(os.sep))

    def _getfiles():
        for path, dirs, files in os.walk(os.path.join(global_config_path, "sets")):
            for f in files:
                if not f.startswith(b"."):
                    yield os.path.join(path, f)

        dbapi = trees["porttree"].dbapi
        for repo in dbapi.getRepositories():
            path = dbapi.getRepositoryPath(repo)
            yield os.path.join(path, "sets.conf")

        yield os.path.join(settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH, "sets.conf")

    return SetConfig(_getfiles(), settings, trees)
コード例 #11
0
def main():
    """
    If the current installation is still has binpkg-multi-instance
    disabled, then patch make.globals inside ${ED} to maintain backward
    compatibility. This is intended to be called from the ebuild as
    follows:

    pkg_preinst() {
            python_setup
            env -u FEATURES -u PORTAGE_REPOSITORIES \
                    PYTHONPATH="${D}$(python_get_sitedir)${PYTHONPATH:+:${PYTHONPATH}}" \
                    "${PYTHON}" -m portage._compat_upgrade.binpkg_multi_instance || die
    }
    """
    if "binpkg-multi-instance" not in portage.settings.features:
        portage.output.EOutput().einfo(
            "Setting make.globals default {} for backward compatibility".
            format(COMPAT_FEATURES))
        config_path = os.path.join(os.environ["ED"],
                                   GLOBAL_CONFIG_PATH.lstrip(os.sep),
                                   "make.globals")
        with open(config_path, "at") as f:
            f.write("{}\n".format(COMPAT_FEATURES))
コード例 #12
0
ファイル: default_locations.py プロジェクト: gentoo/portage
def main():
	"""
	If the current installation is still configured to use any of the
	legacy default /usr/portage locations, then patch make.globals and
	repos.conf inside ${ED} to maintain compatible defaults. This is
	intended to be called from the ebuild as follows:

	pkg_preinst() {
		python_setup
		python_export PYTHON_SITEDIR
		env -u DISTDIR \
			-u PORTAGE_OVERRIDE_EPREFIX \
			-u PORTAGE_REPOSITORIES \
			-u PORTDIR \
			-u PORTDIR_OVERLAY \
			PYTHONPATH="${ED%/}${PYTHON_SITEDIR}${PYTHONPATH:+:${PYTHONPATH}}" \
			"${PYTHON}" -m portage._compat_upgrade.default_locations || die
	}
	"""
	out = portage.output.EOutput()
	config = portage.settings

	compat_distdir = os.path.join(portage.const.EPREFIX or '/', COMPAT_DISTDIR)
	try:
		do_distdir = os.path.samefile(config['DISTDIR'], compat_distdir)
	except OSError:
		do_distdir = False

	compat_pkgdir = os.path.join(portage.const.EPREFIX or '/', COMPAT_PKGDIR)
	try:
		do_pkgdir = os.path.samefile(config['PKGDIR'], compat_pkgdir)
	except OSError:
		do_pkgdir = False

	compat_main_repo = os.path.join(portage.const.EPREFIX or '/', COMPAT_MAIN_REPO)
	try:
		do_main_repo = os.path.samefile(config.repositories.mainRepoLocation(), compat_main_repo)
	except OSError:
		do_main_repo = False

	if do_distdir or do_pkgdir:
		config_path = os.path.join(os.environ['ED'], GLOBAL_CONFIG_PATH.lstrip(os.sep), 'make.globals')
		with open(config_path) as f:
			content = f.read()
			if do_distdir:
				compat_setting = 'DISTDIR="{}"'.format(compat_distdir)
				out.einfo('Setting make.globals default {} for backward compatibility'.format(compat_setting))
				content = re.sub('^DISTDIR=.*$', compat_setting, content, flags=re.MULTILINE)
			if do_pkgdir:
				compat_setting = 'PKGDIR="{}"'.format(compat_pkgdir)
				out.einfo('Setting make.globals default {} for backward compatibility'.format(compat_setting))
				content = re.sub('^PKGDIR=.*$', compat_setting, content, flags=re.MULTILINE)
		with open(config_path, 'wt') as f:
			f.write(content)

	if do_main_repo:
		config_path = os.path.join(os.environ['ED'], GLOBAL_CONFIG_PATH.lstrip(os.sep), 'repos.conf')
		with open(config_path) as f:
			content = f.read()
			compat_setting = 'location = {}'.format(compat_main_repo)
			out.einfo('Setting repos.conf default {} for backward compatibility'.format(compat_setting))
			content = re.sub('^location =.*$', compat_setting, content, flags=re.MULTILINE)
		with open(config_path, 'wt') as f:
			f.write(content)
コード例 #13
0
ファイル: fetch.py プロジェクト: clickbeetle/portage-cb
def fetch(myuris, mysettings, listonly=0, fetchonly=0,
	locks_in_subdir=".locks", use_locks=1, try_mirrors=1, digests=None,
	allow_missing_digests=True):
	"fetch files.  Will use digest file if available."

	if not myuris:
		return 1

	features = mysettings.features
	restrict = mysettings.get("PORTAGE_RESTRICT","").split()

	userfetch = secpass >= 2 and "userfetch" in features
	userpriv = secpass >= 2 and "userpriv" in features

	# 'nomirror' is bad/negative logic. You Restrict mirroring, not no-mirroring.
	restrict_mirror = "mirror" in restrict or "nomirror" in restrict
	if restrict_mirror:
		if ("mirror" in features) and ("lmirror" not in features):
			# lmirror should allow you to bypass mirror restrictions.
			# XXX: This is not a good thing, and is temporary at best.
			print(_(">>> \"mirror\" mode desired and \"mirror\" restriction found; skipping fetch."))
			return 1

	# Generally, downloading the same file repeatedly from
	# every single available mirror is a waste of bandwidth
	# and time, so there needs to be a cap.
	checksum_failure_max_tries = 5
	v = checksum_failure_max_tries
	try:
		v = int(mysettings.get("PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS",
			checksum_failure_max_tries))
	except (ValueError, OverflowError):
		writemsg(_("!!! Variable PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS"
			" contains non-integer value: '%s'\n") % \
			mysettings["PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS"], noiselevel=-1)
		writemsg(_("!!! Using PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS "
			"default value: %s\n") % checksum_failure_max_tries,
			noiselevel=-1)
		v = checksum_failure_max_tries
	if v < 1:
		writemsg(_("!!! Variable PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS"
			" contains value less than 1: '%s'\n") % v, noiselevel=-1)
		writemsg(_("!!! Using PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS "
			"default value: %s\n") % checksum_failure_max_tries,
			noiselevel=-1)
		v = checksum_failure_max_tries
	checksum_failure_max_tries = v
	del v

	fetch_resume_size_default = "350K"
	fetch_resume_size = mysettings.get("PORTAGE_FETCH_RESUME_MIN_SIZE")
	if fetch_resume_size is not None:
		fetch_resume_size = "".join(fetch_resume_size.split())
		if not fetch_resume_size:
			# If it's undefined or empty, silently use the default.
			fetch_resume_size = fetch_resume_size_default
		match = _fetch_resume_size_re.match(fetch_resume_size)
		if match is None or \
			(match.group(2).upper() not in _size_suffix_map):
			writemsg(_("!!! Variable PORTAGE_FETCH_RESUME_MIN_SIZE"
				" contains an unrecognized format: '%s'\n") % \
				mysettings["PORTAGE_FETCH_RESUME_MIN_SIZE"], noiselevel=-1)
			writemsg(_("!!! Using PORTAGE_FETCH_RESUME_MIN_SIZE "
				"default value: %s\n") % fetch_resume_size_default,
				noiselevel=-1)
			fetch_resume_size = None
	if fetch_resume_size is None:
		fetch_resume_size = fetch_resume_size_default
		match = _fetch_resume_size_re.match(fetch_resume_size)
	fetch_resume_size = int(match.group(1)) * \
		2 ** _size_suffix_map[match.group(2).upper()]

	# Behave like the package has RESTRICT="primaryuri" after a
	# couple of checksum failures, to increase the probablility
	# of success before checksum_failure_max_tries is reached.
	checksum_failure_primaryuri = 2
	thirdpartymirrors = mysettings.thirdpartymirrors()

	# In the background parallel-fetch process, it's safe to skip checksum
	# verification of pre-existing files in $DISTDIR that have the correct
	# file size. The parent process will verify their checksums prior to
	# the unpack phase.

	parallel_fetchonly = "PORTAGE_PARALLEL_FETCHONLY" in mysettings
	if parallel_fetchonly:
		fetchonly = 1

	check_config_instance(mysettings)

	custommirrors = grabdict(os.path.join(mysettings["PORTAGE_CONFIGROOT"],
		CUSTOM_MIRRORS_FILE), recursive=1)

	mymirrors=[]

	if listonly or ("distlocks" not in features):
		use_locks = 0

	fetch_to_ro = 0
	if "skiprocheck" in features:
		fetch_to_ro = 1

	if not os.access(mysettings["DISTDIR"],os.W_OK) and fetch_to_ro:
		if use_locks:
			writemsg(colorize("BAD",
				_("!!! For fetching to a read-only filesystem, "
				"locking should be turned off.\n")), noiselevel=-1)
			writemsg(_("!!! This can be done by adding -distlocks to "
				"FEATURES in /etc/make.conf\n"), noiselevel=-1)
#			use_locks = 0

	# local mirrors are always added
	if "local" in custommirrors:
		mymirrors += custommirrors["local"]

	if restrict_mirror:
		# We don't add any mirrors.
		pass
	else:
		if try_mirrors:
			mymirrors += [x.rstrip("/") for x in mysettings["GENTOO_MIRRORS"].split() if x]

	hash_filter = _hash_filter(mysettings.get("PORTAGE_CHECKSUM_FILTER", ""))
	if hash_filter.transparent:
		hash_filter = None
	skip_manifest = mysettings.get("EBUILD_SKIP_MANIFEST") == "1"
	if skip_manifest:
		allow_missing_digests = True
	pkgdir = mysettings.get("O")
	if digests is None and not (pkgdir is None or skip_manifest):
		mydigests = mysettings.repositories.get_repo_for_location(
			os.path.dirname(os.path.dirname(pkgdir))).load_manifest(
			pkgdir, mysettings["DISTDIR"]).getTypeDigests("DIST")
	elif digests is None or skip_manifest:
		# no digests because fetch was not called for a specific package
		mydigests = {}
	else:
		mydigests = digests

	ro_distdirs = [x for x in \
		shlex_split(mysettings.get("PORTAGE_RO_DISTDIRS", "")) \
		if os.path.isdir(x)]

	fsmirrors = []
	for x in range(len(mymirrors)-1,-1,-1):
		if mymirrors[x] and mymirrors[x][0]=='/':
			fsmirrors += [mymirrors[x]]
			del mymirrors[x]

	restrict_fetch = "fetch" in restrict
	force_mirror = "force-mirror" in features and not restrict_mirror
	custom_local_mirrors = custommirrors.get("local", [])
	if restrict_fetch:
		# With fetch restriction, a normal uri may only be fetched from
		# custom local mirrors (if available).  A mirror:// uri may also
		# be fetched from specific mirrors (effectively overriding fetch
		# restriction, but only for specific mirrors).
		locations = custom_local_mirrors
	else:
		locations = mymirrors

	file_uri_tuples = []
	# Check for 'items' attribute since OrderedDict is not a dict.
	if hasattr(myuris, 'items'):
		for myfile, uri_set in myuris.items():
			for myuri in uri_set:
				file_uri_tuples.append((myfile, myuri))
	else:
		for myuri in myuris:
			file_uri_tuples.append((os.path.basename(myuri), myuri))

	filedict = OrderedDict()
	primaryuri_dict = {}
	thirdpartymirror_uris = {}
	for myfile, myuri in file_uri_tuples:
		if myfile not in filedict:
			filedict[myfile]=[]
			for y in range(0,len(locations)):
				filedict[myfile].append(locations[y]+"/distfiles/"+myfile)
		if myuri[:9]=="mirror://":
			eidx = myuri.find("/", 9)
			if eidx != -1:
				mirrorname = myuri[9:eidx]
				path = myuri[eidx+1:]

				# Try user-defined mirrors first
				if mirrorname in custommirrors:
					for cmirr in custommirrors[mirrorname]:
						filedict[myfile].append(
							cmirr.rstrip("/") + "/" + path)

				# now try the official mirrors
				if mirrorname in thirdpartymirrors:
					uris = [locmirr.rstrip("/") + "/" + path \
						for locmirr in thirdpartymirrors[mirrorname]]
					random.shuffle(uris)
					filedict[myfile].extend(uris)
					thirdpartymirror_uris.setdefault(myfile, []).extend(uris)

				if not filedict[myfile]:
					writemsg(_("No known mirror by the name: %s\n") % (mirrorname))
			else:
				writemsg(_("Invalid mirror definition in SRC_URI:\n"), noiselevel=-1)
				writemsg("  %s\n" % (myuri), noiselevel=-1)
		else:
			if restrict_fetch or force_mirror:
				# Only fetch from specific mirrors is allowed.
				continue
			primaryuris = primaryuri_dict.get(myfile)
			if primaryuris is None:
				primaryuris = []
				primaryuri_dict[myfile] = primaryuris
			primaryuris.append(myuri)

	# Order primaryuri_dict values to match that in SRC_URI.
	for uris in primaryuri_dict.values():
		uris.reverse()

	# Prefer thirdpartymirrors over normal mirrors in cases when
	# the file does not yet exist on the normal mirrors.
	for myfile, uris in thirdpartymirror_uris.items():
		primaryuri_dict.setdefault(myfile, []).extend(uris)

	# Now merge primaryuri values into filedict (includes mirrors
	# explicitly referenced in SRC_URI).
	if "primaryuri" in restrict:
		for myfile, uris in filedict.items():
			filedict[myfile] = primaryuri_dict.get(myfile, []) + uris
	else:
		for myfile in filedict:
			filedict[myfile] += primaryuri_dict.get(myfile, [])

	can_fetch=True

	if listonly:
		can_fetch = False

	if can_fetch and not fetch_to_ro:
		global _userpriv_test_write_file_cache
		dirmode  = 0o070
		filemode =   0o60
		modemask =    0o2
		dir_gid = portage_gid
		if "FAKED_MODE" in mysettings:
			# When inside fakeroot, directories with portage's gid appear
			# to have root's gid. Therefore, use root's gid instead of
			# portage's gid to avoid spurrious permissions adjustments
			# when inside fakeroot.
			dir_gid = 0
		distdir_dirs = [""]
		try:
			
			for x in distdir_dirs:
				mydir = os.path.join(mysettings["DISTDIR"], x)
				write_test_file = os.path.join(
					mydir, ".__portage_test_write__")

				try:
					st = os.stat(mydir)
				except OSError:
					st = None

				if st is not None and stat.S_ISDIR(st.st_mode):
					if not (userfetch or userpriv):
						continue
					if _userpriv_test_write_file(mysettings, write_test_file):
						continue

				_userpriv_test_write_file_cache.pop(write_test_file, None)
				if ensure_dirs(mydir, gid=dir_gid, mode=dirmode, mask=modemask):
					if st is None:
						# The directory has just been created
						# and therefore it must be empty.
						continue
					writemsg(_("Adjusting permissions recursively: '%s'\n") % mydir,
						noiselevel=-1)
					def onerror(e):
						raise # bail out on the first error that occurs during recursion
					if not apply_recursive_permissions(mydir,
						gid=dir_gid, dirmode=dirmode, dirmask=modemask,
						filemode=filemode, filemask=modemask, onerror=onerror):
						raise OperationNotPermitted(
							_("Failed to apply recursive permissions for the portage group."))
		except PortageException as e:
			if not os.path.isdir(mysettings["DISTDIR"]):
				writemsg("!!! %s\n" % str(e), noiselevel=-1)
				writemsg(_("!!! Directory Not Found: DISTDIR='%s'\n") % mysettings["DISTDIR"], noiselevel=-1)
				writemsg(_("!!! Fetching will fail!\n"), noiselevel=-1)

	if can_fetch and \
		not fetch_to_ro and \
		not os.access(mysettings["DISTDIR"], os.W_OK):
		writemsg(_("!!! No write access to '%s'\n") % mysettings["DISTDIR"],
			noiselevel=-1)
		can_fetch = False

	distdir_writable = can_fetch and not fetch_to_ro
	failed_files = set()
	restrict_fetch_msg = False

	for myfile in filedict:
		"""
		fetched  status
		0        nonexistent
		1        partially downloaded
		2        completely downloaded
		"""
		fetched = 0

		orig_digests = mydigests.get(myfile, {})

		if not (allow_missing_digests or listonly):
			verifiable_hash_types = set(orig_digests).intersection(hashfunc_map)
			verifiable_hash_types.discard("size")
			if not verifiable_hash_types:
				expected = set(hashfunc_map)
				expected.discard("size")
				expected = " ".join(sorted(expected))
				got = set(orig_digests)
				got.discard("size")
				got = " ".join(sorted(got))
				reason = (_("Insufficient data for checksum verification"),
					got, expected)
				writemsg(_("!!! Fetched file: %s VERIFY FAILED!\n") % myfile,
					noiselevel=-1)
				writemsg(_("!!! Reason: %s\n") % reason[0],
					noiselevel=-1)
				writemsg(_("!!! Got:      %s\n!!! Expected: %s\n") % \
					(reason[1], reason[2]), noiselevel=-1)

				if fetchonly:
					failed_files.add(myfile)
					continue
				else:
					return 0

		size = orig_digests.get("size")
		if size == 0:
			# Zero-byte distfiles are always invalid, so discard their digests.
			del mydigests[myfile]
			orig_digests.clear()
			size = None
		pruned_digests = orig_digests
		if parallel_fetchonly:
			pruned_digests = {}
			if size is not None:
				pruned_digests["size"] = size

		myfile_path = os.path.join(mysettings["DISTDIR"], myfile)
		has_space = True
		has_space_superuser = True
		file_lock = None
		if listonly:
			writemsg_stdout("\n", noiselevel=-1)
		else:
			# check if there is enough space in DISTDIR to completely store myfile
			# overestimate the filesize so we aren't bitten by FS overhead
			vfs_stat = None
			if size is not None and hasattr(os, "statvfs"):
				try:
					vfs_stat = os.statvfs(mysettings["DISTDIR"])
				except OSError as e:
					writemsg_level("!!! statvfs('%s'): %s\n" %
						(mysettings["DISTDIR"], e),
						noiselevel=-1, level=logging.ERROR)
					del e

			if vfs_stat is not None:
				try:
					mysize = os.stat(myfile_path).st_size
				except OSError as e:
					if e.errno not in (errno.ENOENT, errno.ESTALE):
						raise
					del e
					mysize = 0
				if (size - mysize + vfs_stat.f_bsize) >= \
					(vfs_stat.f_bsize * vfs_stat.f_bavail):

					if (size - mysize + vfs_stat.f_bsize) >= \
						(vfs_stat.f_bsize * vfs_stat.f_bfree):
						has_space_superuser = False

					if not has_space_superuser:
						has_space = False
					elif secpass < 2:
						has_space = False
					elif userfetch:
						has_space = False

			if distdir_writable and use_locks:

				lock_kwargs = {}
				if fetchonly:
					lock_kwargs["flags"] = os.O_NONBLOCK

				try:
					file_lock = lockfile(myfile_path,
						wantnewlockfile=1, **lock_kwargs)
				except TryAgain:
					writemsg(_(">>> File '%s' is already locked by "
						"another fetcher. Continuing...\n") % myfile,
						noiselevel=-1)
					continue
		try:
			if not listonly:

				eout = EOutput()
				eout.quiet = mysettings.get("PORTAGE_QUIET") == "1"
				match, mystat = _check_distfile(
					myfile_path, pruned_digests, eout, hash_filter=hash_filter)
				if match:
					# Skip permission adjustment for symlinks, since we don't
					# want to modify anything outside of the primary DISTDIR,
					# and symlinks typically point to PORTAGE_RO_DISTDIRS.
					if distdir_writable and not os.path.islink(myfile_path):
						try:
							apply_secpass_permissions(myfile_path,
								gid=portage_gid, mode=0o664, mask=0o2,
								stat_cached=mystat)
						except PortageException as e:
							if not os.access(myfile_path, os.R_OK):
								writemsg(_("!!! Failed to adjust permissions:"
									" %s\n") % str(e), noiselevel=-1)
							del e
					continue

				if distdir_writable and mystat is None:
					# Remove broken symlinks if necessary.
					try:
						os.unlink(myfile_path)
					except OSError:
						pass

				if mystat is not None:
					if stat.S_ISDIR(mystat.st_mode):
						writemsg_level(
							_("!!! Unable to fetch file since "
							"a directory is in the way: \n"
							"!!!   %s\n") % myfile_path,
							level=logging.ERROR, noiselevel=-1)
						return 0

					if mystat.st_size == 0:
						if distdir_writable:
							try:
								os.unlink(myfile_path)
							except OSError:
								pass
					elif distdir_writable:
						if mystat.st_size < fetch_resume_size and \
							mystat.st_size < size:
							# If the file already exists and the size does not
							# match the existing digests, it may be that the
							# user is attempting to update the digest. In this
							# case, the digestgen() function will advise the
							# user to use `ebuild --force foo.ebuild manifest`
							# in order to force the old digests to be replaced.
							# Since the user may want to keep this file, rename
							# it instead of deleting it.
							writemsg(_(">>> Renaming distfile with size "
								"%d (smaller than " "PORTAGE_FETCH_RESU"
								"ME_MIN_SIZE)\n") % mystat.st_size)
							temp_filename = \
								_checksum_failure_temp_file(
								mysettings["DISTDIR"], myfile)
							writemsg_stdout(_("Refetching... "
								"File renamed to '%s'\n\n") % \
								temp_filename, noiselevel=-1)
						elif mystat.st_size >= size:
							temp_filename = \
								_checksum_failure_temp_file(
								mysettings["DISTDIR"], myfile)
							writemsg_stdout(_("Refetching... "
								"File renamed to '%s'\n\n") % \
								temp_filename, noiselevel=-1)

				if distdir_writable and ro_distdirs:
					readonly_file = None
					for x in ro_distdirs:
						filename = os.path.join(x, myfile)
						match, mystat = _check_distfile(
							filename, pruned_digests, eout, hash_filter=hash_filter)
						if match:
							readonly_file = filename
							break
					if readonly_file is not None:
						try:
							os.unlink(myfile_path)
						except OSError as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e
						os.symlink(readonly_file, myfile_path)
						continue

				# this message is shown only after we know that
				# the file is not already fetched
				if not has_space:
					writemsg(_("!!! Insufficient space to store %s in %s\n") % \
						(myfile, mysettings["DISTDIR"]), noiselevel=-1)

					if has_space_superuser:
						writemsg(_("!!! Insufficient privileges to use "
							"remaining space.\n"), noiselevel=-1)
						if userfetch:
							writemsg(_("!!! You may set FEATURES=\"-userfetch\""
								" in /etc/make.conf in order to fetch with\n"
								"!!! superuser privileges.\n"), noiselevel=-1)

				if fsmirrors and not os.path.exists(myfile_path) and has_space:
					for mydir in fsmirrors:
						mirror_file = os.path.join(mydir, myfile)
						try:
							shutil.copyfile(mirror_file, myfile_path)
							writemsg(_("Local mirror has file: %s\n") % myfile)
							break
						except (IOError, OSError) as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e

				try:
					mystat = os.stat(myfile_path)
				except OSError as e:
					if e.errno not in (errno.ENOENT, errno.ESTALE):
						raise
					del e
				else:
					# Skip permission adjustment for symlinks, since we don't
					# want to modify anything outside of the primary DISTDIR,
					# and symlinks typically point to PORTAGE_RO_DISTDIRS.
					if not os.path.islink(myfile_path):
						try:
							apply_secpass_permissions(myfile_path,
								gid=portage_gid, mode=0o664, mask=0o2,
								stat_cached=mystat)
						except PortageException as e:
							if not os.access(myfile_path, os.R_OK):
								writemsg(_("!!! Failed to adjust permissions:"
									" %s\n") % (e,), noiselevel=-1)

					# If the file is empty then it's obviously invalid. Remove
					# the empty file and try to download if possible.
					if mystat.st_size == 0:
						if distdir_writable:
							try:
								os.unlink(myfile_path)
							except EnvironmentError:
								pass
					elif myfile not in mydigests:
						# We don't have a digest, but the file exists.  We must
						# assume that it is fully downloaded.
						continue
					else:
						if mystat.st_size < mydigests[myfile]["size"] and \
							not restrict_fetch:
							fetched = 1 # Try to resume this download.
						elif parallel_fetchonly and \
							mystat.st_size == mydigests[myfile]["size"]:
							eout = EOutput()
							eout.quiet = \
								mysettings.get("PORTAGE_QUIET") == "1"
							eout.ebegin(
								"%s size ;-)" % (myfile, ))
							eout.eend(0)
							continue
						else:
							digests = _filter_unaccelarated_hashes(mydigests[myfile])
							if hash_filter is not None:
								digests = _apply_hash_filter(digests, hash_filter)
							verified_ok, reason = verify_all(myfile_path, digests)
							if not verified_ok:
								writemsg(_("!!! Previously fetched"
									" file: '%s'\n") % myfile, noiselevel=-1)
								writemsg(_("!!! Reason: %s\n") % reason[0],
									noiselevel=-1)
								writemsg(_("!!! Got:      %s\n"
									"!!! Expected: %s\n") % \
									(reason[1], reason[2]), noiselevel=-1)
								if reason[0] == _("Insufficient data for checksum verification"):
									return 0
								if distdir_writable:
									temp_filename = \
										_checksum_failure_temp_file(
										mysettings["DISTDIR"], myfile)
									writemsg_stdout(_("Refetching... "
										"File renamed to '%s'\n\n") % \
										temp_filename, noiselevel=-1)
							else:
								eout = EOutput()
								eout.quiet = \
									mysettings.get("PORTAGE_QUIET", None) == "1"
								if digests:
									digests = list(digests)
									digests.sort()
									eout.ebegin(
										"%s %s ;-)" % (myfile, " ".join(digests)))
									eout.eend(0)
								continue # fetch any remaining files

			# Create a reversed list since that is optimal for list.pop().
			uri_list = filedict[myfile][:]
			uri_list.reverse()
			checksum_failure_count = 0
			tried_locations = set()
			while uri_list:
				loc = uri_list.pop()
				# Eliminate duplicates here in case we've switched to
				# "primaryuri" mode on the fly due to a checksum failure.
				if loc in tried_locations:
					continue
				tried_locations.add(loc)
				if listonly:
					writemsg_stdout(loc+" ", noiselevel=-1)
					continue
				# allow different fetchcommands per protocol
				protocol = loc[0:loc.find("://")]

				global_config_path = GLOBAL_CONFIG_PATH
				if mysettings['EPREFIX']:
					global_config_path = os.path.join(mysettings['EPREFIX'],
							GLOBAL_CONFIG_PATH.lstrip(os.sep))

				missing_file_param = False
				fetchcommand_var = "FETCHCOMMAND_" + protocol.upper()
				fetchcommand = mysettings.get(fetchcommand_var)
				if fetchcommand is None:
					fetchcommand_var = "FETCHCOMMAND"
					fetchcommand = mysettings.get(fetchcommand_var)
					if fetchcommand is None:
						writemsg_level(
							_("!!! %s is unset. It should "
							"have been defined in\n!!! %s/make.globals.\n") \
							% (fetchcommand_var, global_config_path),
							level=logging.ERROR, noiselevel=-1)
						return 0
				if "${FILE}" not in fetchcommand:
					writemsg_level(
						_("!!! %s does not contain the required ${FILE}"
						" parameter.\n") % fetchcommand_var,
						level=logging.ERROR, noiselevel=-1)
					missing_file_param = True

				resumecommand_var = "RESUMECOMMAND_" + protocol.upper()
				resumecommand = mysettings.get(resumecommand_var)
				if resumecommand is None:
					resumecommand_var = "RESUMECOMMAND"
					resumecommand = mysettings.get(resumecommand_var)
					if resumecommand is None:
						writemsg_level(
							_("!!! %s is unset. It should "
							"have been defined in\n!!! %s/make.globals.\n") \
							% (resumecommand_var, global_config_path),
							level=logging.ERROR, noiselevel=-1)
						return 0
				if "${FILE}" not in resumecommand:
					writemsg_level(
						_("!!! %s does not contain the required ${FILE}"
						" parameter.\n") % resumecommand_var,
						level=logging.ERROR, noiselevel=-1)
					missing_file_param = True

				if missing_file_param:
					writemsg_level(
						_("!!! Refer to the make.conf(5) man page for "
						"information about how to\n!!! correctly specify "
						"FETCHCOMMAND and RESUMECOMMAND.\n"),
						level=logging.ERROR, noiselevel=-1)
					if myfile != os.path.basename(loc):
						return 0

				if not can_fetch:
					if fetched != 2:
						try:
							mysize = os.stat(myfile_path).st_size
						except OSError as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e
							mysize = 0

						if mysize == 0:
							writemsg(_("!!! File %s isn't fetched but unable to get it.\n") % myfile,
								noiselevel=-1)
						elif size is None or size > mysize:
							writemsg(_("!!! File %s isn't fully fetched, but unable to complete it\n") % myfile,
								noiselevel=-1)
						else:
							writemsg(_("!!! File %s is incorrect size, "
								"but unable to retry.\n") % myfile, noiselevel=-1)
						return 0
					else:
						continue

				if fetched != 2 and has_space:
					#we either need to resume or start the download
					if fetched == 1:
						try:
							mystat = os.stat(myfile_path)
						except OSError as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e
							fetched = 0
						else:
							if mystat.st_size < fetch_resume_size:
								writemsg(_(">>> Deleting distfile with size "
									"%d (smaller than " "PORTAGE_FETCH_RESU"
									"ME_MIN_SIZE)\n") % mystat.st_size)
								try:
									os.unlink(myfile_path)
								except OSError as e:
									if e.errno not in \
										(errno.ENOENT, errno.ESTALE):
										raise
									del e
								fetched = 0
					if fetched == 1:
						#resume mode:
						writemsg(_(">>> Resuming download...\n"))
						locfetch=resumecommand
						command_var = resumecommand_var
					else:
						#normal mode:
						locfetch=fetchcommand
						command_var = fetchcommand_var
					writemsg_stdout(_(">>> Downloading '%s'\n") % \
						_hide_url_passwd(loc))
					variables = {
						"DISTDIR": mysettings["DISTDIR"],
						"URI":     loc,
						"FILE":    myfile
					}

					myfetch = shlex_split(locfetch)
					myfetch = [varexpand(x, mydict=variables) for x in myfetch]
					myret = -1
					try:

						myret = _spawn_fetch(mysettings, myfetch)

					finally:
						try:
							apply_secpass_permissions(myfile_path,
								gid=portage_gid, mode=0o664, mask=0o2)
						except FileNotFound:
							pass
						except PortageException as e:
							if not os.access(myfile_path, os.R_OK):
								writemsg(_("!!! Failed to adjust permissions:"
									" %s\n") % str(e), noiselevel=-1)
							del e

					# If the file is empty then it's obviously invalid.  Don't
					# trust the return value from the fetcher.  Remove the
					# empty file and try to download again.
					try:
						if os.stat(myfile_path).st_size == 0:
							os.unlink(myfile_path)
							fetched = 0
							continue
					except EnvironmentError:
						pass

					if mydigests is not None and myfile in mydigests:
						try:
							mystat = os.stat(myfile_path)
						except OSError as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e
							fetched = 0
						else:

							if stat.S_ISDIR(mystat.st_mode):
								# This can happen if FETCHCOMMAND erroneously
								# contains wget's -P option where it should
								# instead have -O.
								writemsg_level(
									_("!!! The command specified in the "
									"%s variable appears to have\n!!! "
									"created a directory instead of a "
									"normal file.\n") % command_var,
									level=logging.ERROR, noiselevel=-1)
								writemsg_level(
									_("!!! Refer to the make.conf(5) "
									"man page for information about how "
									"to\n!!! correctly specify "
									"FETCHCOMMAND and RESUMECOMMAND.\n"),
									level=logging.ERROR, noiselevel=-1)
								return 0

							# no exception?  file exists. let digestcheck() report
							# an appropriately for size or checksum errors

							# If the fetcher reported success and the file is
							# too small, it's probably because the digest is
							# bad (upstream changed the distfile).  In this
							# case we don't want to attempt to resume. Show a
							# digest verification failure to that the user gets
							# a clue about what just happened.
							if myret != os.EX_OK and \
								mystat.st_size < mydigests[myfile]["size"]:
								# Fetch failed... Try the next one... Kill 404 files though.
								if (mystat[stat.ST_SIZE]<100000) and (len(myfile)>4) and not ((myfile[-5:]==".html") or (myfile[-4:]==".htm")):
									html404=re.compile("<title>.*(not found|404).*</title>",re.I|re.M)
									with io.open(
										_unicode_encode(myfile_path,
										encoding=_encodings['fs'], errors='strict'),
										mode='r', encoding=_encodings['content'], errors='replace'
										) as f:
										if html404.search(f.read()):
											try:
												os.unlink(mysettings["DISTDIR"]+"/"+myfile)
												writemsg(_(">>> Deleting invalid distfile. (Improper 404 redirect from server.)\n"))
												fetched = 0
												continue
											except (IOError, OSError):
												pass
								fetched = 1
								continue
							if True:
								# File is the correct size--check the checksums for the fetched
								# file NOW, for those users who don't have a stable/continuous
								# net connection. This way we have a chance to try to download
								# from another mirror...
								digests = _filter_unaccelarated_hashes(mydigests[myfile])
								if hash_filter is not None:
									digests = _apply_hash_filter(digests, hash_filter)
								verified_ok, reason = verify_all(myfile_path, digests)
								if not verified_ok:
									writemsg(_("!!! Fetched file: %s VERIFY FAILED!\n") % myfile,
										noiselevel=-1)
									writemsg(_("!!! Reason: %s\n") % reason[0],
										noiselevel=-1)
									writemsg(_("!!! Got:      %s\n!!! Expected: %s\n") % \
										(reason[1], reason[2]), noiselevel=-1)
									if reason[0] == _("Insufficient data for checksum verification"):
										return 0
									temp_filename = \
										_checksum_failure_temp_file(
										mysettings["DISTDIR"], myfile)
									writemsg_stdout(_("Refetching... "
										"File renamed to '%s'\n\n") % \
										temp_filename, noiselevel=-1)
									fetched=0
									checksum_failure_count += 1
									if checksum_failure_count == \
										checksum_failure_primaryuri:
										# Switch to "primaryuri" mode in order
										# to increase the probablility of
										# of success.
										primaryuris = \
											primaryuri_dict.get(myfile)
										if primaryuris:
											uri_list.extend(
												reversed(primaryuris))
									if checksum_failure_count >= \
										checksum_failure_max_tries:
										break
								else:
									eout = EOutput()
									eout.quiet = mysettings.get("PORTAGE_QUIET", None) == "1"
									if digests:
										eout.ebegin("%s %s ;-)" % \
											(myfile, " ".join(sorted(digests))))
										eout.eend(0)
									fetched=2
									break
					else:
						if not myret:
							fetched=2
							break
						elif mydigests!=None:
							writemsg(_("No digest file available and download failed.\n\n"),
								noiselevel=-1)
		finally:
			if use_locks and file_lock:
				unlockfile(file_lock)
				file_lock = None

		if listonly:
			writemsg_stdout("\n", noiselevel=-1)
		if fetched != 2:
			if restrict_fetch and not restrict_fetch_msg:
				restrict_fetch_msg = True
				msg = _("\n!!! %s/%s"
					" has fetch restriction turned on.\n"
					"!!! This probably means that this "
					"ebuild's files must be downloaded\n"
					"!!! manually.  See the comments in"
					" the ebuild for more information.\n\n") % \
					(mysettings["CATEGORY"], mysettings["PF"])
				writemsg_level(msg,
					level=logging.ERROR, noiselevel=-1)
			elif restrict_fetch:
				pass
			elif listonly:
				pass
			elif not filedict[myfile]:
				writemsg(_("Warning: No mirrors available for file"
					" '%s'\n") % (myfile), noiselevel=-1)
			else:
				writemsg(_("!!! Couldn't download '%s'. Aborting.\n") % myfile,
					noiselevel=-1)

			if listonly:
				failed_files.add(myfile)
				continue
			elif fetchonly:
				failed_files.add(myfile)
				continue
			return 0
	if failed_files:
		return 0
	return 1
コード例 #14
0
    def _create_profile(self, ebuilds, eclasses, installed, profile,
                        repo_configs, user_config, sets):

        user_config_dir = os.path.join(self.eroot, USER_CONFIG_PATH)

        try:
            os.makedirs(user_config_dir)
        except os.error:
            pass

        for repo in self._repositories:
            if repo == "DEFAULT":
                continue

            repo_dir = self._get_repo_dir(repo)
            profile_dir = os.path.join(repo_dir, "profiles")
            metadata_dir = os.path.join(repo_dir, "metadata")
            os.makedirs(metadata_dir)

            # Create $REPO/profiles/categories
            categories = set()
            for cpv in ebuilds:
                ebuilds_repo = Atom("=" + cpv, allow_repo=True).repo
                if ebuilds_repo is None:
                    ebuilds_repo = "test_repo"
                if ebuilds_repo == repo:
                    categories.add(catsplit(cpv)[0])

            categories_file = os.path.join(profile_dir, "categories")
            with open(categories_file, "w") as f:
                for cat in categories:
                    f.write(cat + "\n")

            # Create $REPO/profiles/license_groups
            license_file = os.path.join(profile_dir, "license_groups")
            with open(license_file, "w") as f:
                f.write("EULA TEST\n")

            repo_config = repo_configs.get(repo)
            if repo_config:
                for config_file, lines in repo_config.items():
                    if config_file not in self.config_files and not any(
                            fnmatch.fnmatch(config_file, os.path.join(x, "*"))
                            for x in self.config_files):
                        raise ValueError("Unknown config file: '%s'" %
                                         config_file)

                    if config_file in ("layout.conf", ):
                        file_name = os.path.join(repo_dir, "metadata",
                                                 config_file)
                    else:
                        file_name = os.path.join(profile_dir, config_file)
                        if "/" in config_file and not os.path.isdir(
                                os.path.dirname(file_name)):
                            os.makedirs(os.path.dirname(file_name))
                    with open(file_name, "w") as f:
                        for line in lines:
                            f.write("%s\n" % line)
                        # Temporarily write empty value of masters until it becomes default.
                        # TODO: Delete all references to "# use implicit masters" when empty value becomes default.
                        if config_file == "layout.conf" and not any(
                                line.startswith(("masters =",
                                                 "# use implicit masters"))
                                for line in lines):
                            f.write("masters =\n")

            # Create $profile_dir/eclass (we fail to digest the ebuilds if it's not there)
            eclass_dir = os.path.join(repo_dir, "eclass")
            os.makedirs(eclass_dir)

            for eclass_name, eclass_content in eclasses.items():
                with open(
                        os.path.join(eclass_dir,
                                     "{}.eclass".format(eclass_name)),
                        "wt") as f:
                    if isinstance(eclass_content, str):
                        eclass_content = [eclass_content]
                    for line in eclass_content:
                        f.write("{}\n".format(line))

            # Temporarily write empty value of masters until it becomes default.
            if not repo_config or "layout.conf" not in repo_config:
                layout_conf_path = os.path.join(repo_dir, "metadata",
                                                "layout.conf")
                with open(layout_conf_path, "w") as f:
                    f.write("masters =\n")

            if repo == "test_repo":
                # Create a minimal profile in /var/db/repos/gentoo
                sub_profile_dir = os.path.join(profile_dir, "default", "linux",
                                               "x86", "test_profile")
                os.makedirs(sub_profile_dir)

                if not (profile and "eapi" in profile):
                    eapi_file = os.path.join(sub_profile_dir, "eapi")
                    with open(eapi_file, "w") as f:
                        f.write("0\n")

                make_defaults_file = os.path.join(sub_profile_dir,
                                                  "make.defaults")
                with open(make_defaults_file, "w") as f:
                    f.write('ARCH="x86"\n')
                    f.write('ACCEPT_KEYWORDS="x86"\n')

                use_force_file = os.path.join(sub_profile_dir, "use.force")
                with open(use_force_file, "w") as f:
                    f.write("x86\n")

                parent_file = os.path.join(sub_profile_dir, "parent")
                with open(parent_file, "w") as f:
                    f.write("..\n")

                if profile:
                    for config_file, lines in profile.items():
                        if config_file not in self.config_files:
                            raise ValueError("Unknown config file: '%s'" %
                                             config_file)

                        file_name = os.path.join(sub_profile_dir, config_file)
                        with open(file_name, "w") as f:
                            for line in lines:
                                f.write("%s\n" % line)

                # Create profile symlink
                os.symlink(sub_profile_dir,
                           os.path.join(user_config_dir, "make.profile"))

        gpg_test_path = os.environ["PORTAGE_GNUPGHOME"]

        make_conf = {
            "ACCEPT_KEYWORDS": "x86",
            "BINPKG_GPG_SIGNING_BASE_COMMAND":
            f"flock {gpg_test_path}/portage-binpkg-gpg.lock /usr/bin/gpg --sign --armor --yes --pinentry-mode loopback --passphrase GentooTest [PORTAGE_CONFIG]",
            "BINPKG_GPG_SIGNING_GPG_HOME": gpg_test_path,
            "BINPKG_GPG_SIGNING_KEY": "0x5D90EA06352177F6",
            "BINPKG_GPG_VERIFY_GPG_HOME": gpg_test_path,
            "CLEAN_DELAY": "0",
            "DISTDIR": self.distdir,
            "EMERGE_WARNING_DELAY": "0",
            "FEATURES": "${FEATURES} binpkg-signing binpkg-request-signature "
            "gpg-keepalive",
            "PKGDIR": self.pkgdir,
            "PORTAGE_INST_GID": str(portage.data.portage_gid),
            "PORTAGE_INST_UID": str(portage.data.portage_uid),
            "PORTAGE_TMPDIR": os.path.join(self.eroot, "var/tmp"),
        }

        if os.environ.get("NOCOLOR"):
            make_conf["NOCOLOR"] = os.environ["NOCOLOR"]

        # Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
        # need to be inherited by ebuild subprocesses.
        if "PORTAGE_USERNAME" in os.environ:
            make_conf["PORTAGE_USERNAME"] = os.environ["PORTAGE_USERNAME"]
        if "PORTAGE_GRPNAME" in os.environ:
            make_conf["PORTAGE_GRPNAME"] = os.environ["PORTAGE_GRPNAME"]

        make_conf_lines = []
        for k_v in make_conf.items():
            make_conf_lines.append('%s="%s"' % k_v)

        if "make.conf" in user_config:
            make_conf_lines.extend(user_config["make.conf"])

        if not portage.process.sandbox_capable or os.environ.get(
                "SANDBOX_ON") == "1":
            # avoid problems from nested sandbox instances
            make_conf_lines.append(
                'FEATURES="${FEATURES} -sandbox -usersandbox"')

        configs = user_config.copy()
        configs["make.conf"] = make_conf_lines

        for config_file, lines in configs.items():
            if config_file not in self.config_files:
                raise ValueError("Unknown config file: '%s'" % config_file)

            file_name = os.path.join(user_config_dir, config_file)
            with open(file_name, "w") as f:
                for line in lines:
                    f.write("%s\n" % line)

        # Create /usr/share/portage/config/make.globals
        make_globals_path = os.path.join(self.eroot,
                                         GLOBAL_CONFIG_PATH.lstrip(os.sep),
                                         "make.globals")
        ensure_dirs(os.path.dirname(make_globals_path))
        os.symlink(os.path.join(cnf_path, "make.globals"), make_globals_path)

        # Create /usr/share/portage/config/sets/portage.conf
        default_sets_conf_dir = os.path.join(self.eroot,
                                             "usr/share/portage/config/sets")

        try:
            os.makedirs(default_sets_conf_dir)
        except os.error:
            pass

        provided_sets_portage_conf = os.path.join(cnf_path, "sets",
                                                  "portage.conf")
        os.symlink(
            provided_sets_portage_conf,
            os.path.join(default_sets_conf_dir, "portage.conf"),
        )

        set_config_dir = os.path.join(user_config_dir, "sets")

        try:
            os.makedirs(set_config_dir)
        except os.error:
            pass

        for sets_file, lines in sets.items():
            file_name = os.path.join(set_config_dir, sets_file)
            with open(file_name, "w") as f:
                for line in lines:
                    f.write("%s\n" % line)

        if cnf_path_repoman is not None:
            # Create /usr/share/repoman
            repoman_share_dir = os.path.join(self.eroot, "usr", "share",
                                             "repoman")
            os.symlink(cnf_path_repoman, repoman_share_dir)
コード例 #15
0
	def _create_profile(self, ebuilds, installed, profile, repo_configs, user_config, sets):

		user_config_dir = os.path.join(self.eroot, USER_CONFIG_PATH)

		try:
			os.makedirs(user_config_dir)
		except os.error:
			pass

		for repo in self.repo_dirs:
			repo_dir = self._get_repo_dir(repo)
			profile_dir = os.path.join(self._get_repo_dir(repo), "profiles")
			metadata_dir = os.path.join(repo_dir, "metadata")
			os.makedirs(metadata_dir)

			#Create $REPO/profiles/categories
			categories = set()
			for cpv in ebuilds:
				ebuilds_repo = Atom("="+cpv, allow_repo=True).repo
				if ebuilds_repo is None:
					ebuilds_repo = "test_repo"
				if ebuilds_repo == repo:
					categories.add(catsplit(cpv)[0])

			categories_file = os.path.join(profile_dir, "categories")
			f = open(categories_file, "w")
			for cat in categories:
				f.write(cat + "\n")
			f.close()
			
			#Create $REPO/profiles/license_groups
			license_file = os.path.join(profile_dir, "license_groups")
			f = open(license_file, "w")
			f.write("EULA TEST\n")
			f.close()

			repo_config = repo_configs.get(repo) 
			if repo_config:
				for config_file, lines in repo_config.items():
					if config_file not in self.config_files:
						raise ValueError("Unknown config file: '%s'" % config_file)

					if config_file in ("layout.conf",):
						file_name = os.path.join(repo_dir, "metadata", config_file)
					else:
						file_name = os.path.join(profile_dir, config_file)
					f = open(file_name, "w")
					for line in lines:
						f.write("%s\n" % line)
					f.close()

			#Create $profile_dir/eclass (we fail to digest the ebuilds if it's not there)
			os.makedirs(os.path.join(repo_dir, "eclass"))

			if repo == "test_repo":
				#Create a minimal profile in /usr/portage
				sub_profile_dir = os.path.join(profile_dir, "default", "linux", "x86", "test_profile")
				os.makedirs(sub_profile_dir)

				eapi_file = os.path.join(sub_profile_dir, "eapi")
				f = open(eapi_file, "w")
				f.write("0\n")
				f.close()

				make_defaults_file = os.path.join(sub_profile_dir, "make.defaults")
				f = open(make_defaults_file, "w")
				f.write("ARCH=\"x86\"\n")
				f.write("ACCEPT_KEYWORDS=\"x86\"\n")
				f.close()

				use_force_file = os.path.join(sub_profile_dir, "use.force")
				f = open(use_force_file, "w")
				f.write("x86\n")
				f.close()

				parent_file = os.path.join(sub_profile_dir, "parent")
				f = open(parent_file, "w")
				f.write("..\n")
				f.close()

				if profile:
					for config_file, lines in profile.items():
						if config_file not in self.config_files:
							raise ValueError("Unknown config file: '%s'" % config_file)

						file_name = os.path.join(sub_profile_dir, config_file)
						f = open(file_name, "w")
						for line in lines:
							f.write("%s\n" % line)
						f.close()

				#Create profile symlink
				os.symlink(sub_profile_dir, os.path.join(user_config_dir, "make.profile"))

				#Create minimal herds.xml
				herds_xml = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE herds SYSTEM "http://www.gentoo.org/dtd/herds.dtd">
<?xml-stylesheet href="/xsl/herds.xsl" type="text/xsl" ?>
<?xml-stylesheet href="/xsl/guide.xsl" type="text/xsl" ?>
<herds>
<herd>
  <name>base-system</name>
  <email>[email protected]</email>
  <description>Core system utilities and libraries.</description>
  <maintainer>
    <email>[email protected]</email>
    <name>Base System</name>
    <role>Base System Maintainer</role>
  </maintainer>
</herd>
</herds>
"""
				with open(os.path.join(metadata_dir, "metadata.xml"), 'w') as f:
					f.write(herds_xml)

		# Write empty entries for each repository, in order to exercise
		# RepoConfigLoader's repos.conf processing.
		repos_conf_file = os.path.join(user_config_dir, "repos.conf")		
		f = open(repos_conf_file, "w")
		for repo in sorted(self.repo_dirs.keys()):
			f.write("[%s]\n" % repo)
			f.write("\n")
		f.close()

		for config_file, lines in user_config.items():
			if config_file not in self.config_files:
				raise ValueError("Unknown config file: '%s'" % config_file)

			file_name = os.path.join(user_config_dir, config_file)
			f = open(file_name, "w")
			for line in lines:
				f.write("%s\n" % line)
			f.close()

		#Create /usr/share/portage/config/make.globals
		make_globals_path = os.path.join(self.eroot,
			GLOBAL_CONFIG_PATH.lstrip(os.sep), "make.globals")
		ensure_dirs(os.path.dirname(make_globals_path))
		os.symlink(os.path.join(PORTAGE_BASE_PATH, "cnf", "make.globals"),
			make_globals_path)

		#Create /usr/share/portage/config/sets/portage.conf
		default_sets_conf_dir = os.path.join(self.eroot, "usr/share/portage/config/sets")
		
		try:
			os.makedirs(default_sets_conf_dir)
		except os.error:
			pass

		provided_sets_portage_conf = \
			os.path.join(PORTAGE_BASE_PATH, "cnf/sets/portage.conf")
		os.symlink(provided_sets_portage_conf, os.path.join(default_sets_conf_dir, "portage.conf"))

		set_config_dir = os.path.join(user_config_dir, "sets")

		try:
			os.makedirs(set_config_dir)
		except os.error:
			pass

		for sets_file, lines in sets.items():
			file_name = os.path.join(set_config_dir, sets_file)
			f = open(file_name, "w")
			for line in lines:
				f.write("%s\n" % line)
			f.close()

		user_config_dir = os.path.join(self.eroot, "etc", "portage")

		try:
			os.makedirs(user_config_dir)
		except os.error:
			pass

		for config_file, lines in user_config.items():
			if config_file not in self.config_files:
				raise ValueError("Unknown config file: '%s'" % config_file)

			file_name = os.path.join(user_config_dir, config_file)
			f = open(file_name, "w")
			for line in lines:
				f.write("%s\n" % line)
			f.close()
コード例 #16
0
	def _create_profile(self, ebuilds, installed, profile, repo_configs, user_config, sets):

		user_config_dir = os.path.join(self.eroot, USER_CONFIG_PATH)

		try:
			os.makedirs(user_config_dir)
		except os.error:
			pass

		for repo in self._repositories:
			if repo == "DEFAULT":
				continue

			repo_dir = self._get_repo_dir(repo)
			profile_dir = os.path.join(repo_dir, "profiles")
			metadata_dir = os.path.join(repo_dir, "metadata")
			os.makedirs(metadata_dir)

			#Create $REPO/profiles/categories
			categories = set()
			for cpv in ebuilds:
				ebuilds_repo = Atom("="+cpv, allow_repo=True).repo
				if ebuilds_repo is None:
					ebuilds_repo = "test_repo"
				if ebuilds_repo == repo:
					categories.add(catsplit(cpv)[0])

			categories_file = os.path.join(profile_dir, "categories")
			f = open(categories_file, "w")
			for cat in categories:
				f.write(cat + "\n")
			f.close()

			#Create $REPO/profiles/license_groups
			license_file = os.path.join(profile_dir, "license_groups")
			f = open(license_file, "w")
			f.write("EULA TEST\n")
			f.close()

			repo_config = repo_configs.get(repo)
			if repo_config:
				for config_file, lines in repo_config.items():
					if config_file not in self.config_files and not any(fnmatch.fnmatch(config_file, os.path.join(x, "*")) for x in self.config_files):
						raise ValueError("Unknown config file: '%s'" % config_file)

					if config_file in ("layout.conf",):
						file_name = os.path.join(repo_dir, "metadata", config_file)
					else:
						file_name = os.path.join(profile_dir, config_file)
						if "/" in config_file and not os.path.isdir(os.path.dirname(file_name)):
							os.makedirs(os.path.dirname(file_name))
					f = open(file_name, "w")
					for line in lines:
						f.write("%s\n" % line)
					f.close()

			#Create $profile_dir/eclass (we fail to digest the ebuilds if it's not there)
			os.makedirs(os.path.join(repo_dir, "eclass"))

			if repo == "test_repo":
				#Create a minimal profile in /usr/portage
				sub_profile_dir = os.path.join(profile_dir, "default", "linux", "x86", "test_profile")
				os.makedirs(sub_profile_dir)

				if not (profile and "eapi" in profile):
					eapi_file = os.path.join(sub_profile_dir, "eapi")
					f = open(eapi_file, "w")
					f.write("0\n")
					f.close()

				make_defaults_file = os.path.join(sub_profile_dir, "make.defaults")
				f = open(make_defaults_file, "w")
				f.write("ARCH=\"x86\"\n")
				f.write("ACCEPT_KEYWORDS=\"x86\"\n")
				f.close()

				use_force_file = os.path.join(sub_profile_dir, "use.force")
				f = open(use_force_file, "w")
				f.write("x86\n")
				f.close()

				parent_file = os.path.join(sub_profile_dir, "parent")
				f = open(parent_file, "w")
				f.write("..\n")
				f.close()

				if profile:
					for config_file, lines in profile.items():
						if config_file not in self.config_files:
							raise ValueError("Unknown config file: '%s'" % config_file)

						file_name = os.path.join(sub_profile_dir, config_file)
						f = open(file_name, "w")
						for line in lines:
							f.write("%s\n" % line)
						f.close()

				#Create profile symlink
				os.symlink(sub_profile_dir, os.path.join(user_config_dir, "make.profile"))

				#Create minimal herds.xml
				herds_xml = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE herds SYSTEM "http://www.gentoo.org/dtd/herds.dtd">
<?xml-stylesheet href="/xsl/herds.xsl" type="text/xsl" ?>
<?xml-stylesheet href="/xsl/guide.xsl" type="text/xsl" ?>
<herds>
<herd>
  <name>base-system</name>
  <email>[email protected]</email>
  <description>Core system utilities and libraries.</description>
  <maintainer>
    <email>[email protected]</email>
    <name>Base System</name>
    <role>Base System Maintainer</role>
  </maintainer>
</herd>
</herds>
"""
				with open(os.path.join(metadata_dir, "metadata.xml"), 'w') as f:
					f.write(herds_xml)

		make_conf = {
			"ACCEPT_KEYWORDS": "x86",
			"CLEAN_DELAY": "0",
			"DISTDIR" : self.distdir,
			"EMERGE_WARNING_DELAY": "0",
			"PKGDIR": self.pkgdir,
			"PORTAGE_INST_GID": str(portage.data.portage_gid),
			"PORTAGE_INST_UID": str(portage.data.portage_uid),
			"PORTAGE_TMPDIR": os.path.join(self.eroot, 'var/tmp'),
		}

		if os.environ.get("NOCOLOR"):
			make_conf["NOCOLOR"] = os.environ["NOCOLOR"]

		# Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
		# need to be inherited by ebuild subprocesses.
		if 'PORTAGE_USERNAME' in os.environ:
			make_conf['PORTAGE_USERNAME'] = os.environ['PORTAGE_USERNAME']
		if 'PORTAGE_GRPNAME' in os.environ:
			make_conf['PORTAGE_GRPNAME'] = os.environ['PORTAGE_GRPNAME']

		make_conf_lines = []
		for k_v in make_conf.items():
			make_conf_lines.append('%s="%s"' % k_v)

		if "make.conf" in user_config:
			make_conf_lines.extend(user_config["make.conf"])

		if not portage.process.sandbox_capable or \
			os.environ.get("SANDBOX_ON") == "1":
			# avoid problems from nested sandbox instances
			make_conf_lines.append('FEATURES="${FEATURES} -sandbox -usersandbox"')

		configs = user_config.copy()
		configs["make.conf"] = make_conf_lines

		for config_file, lines in configs.items():
			if config_file not in self.config_files:
				raise ValueError("Unknown config file: '%s'" % config_file)

			file_name = os.path.join(user_config_dir, config_file)
			f = open(file_name, "w")
			for line in lines:
				f.write("%s\n" % line)
			f.close()

		#Create /usr/share/portage/config/make.globals
		make_globals_path = os.path.join(self.eroot,
			GLOBAL_CONFIG_PATH.lstrip(os.sep), "make.globals")
		ensure_dirs(os.path.dirname(make_globals_path))
		os.symlink(os.path.join(PORTAGE_BASE_PATH, "cnf", "make.globals"),
			make_globals_path)

		#Create /usr/share/portage/config/sets/portage.conf
		default_sets_conf_dir = os.path.join(self.eroot, "usr/share/portage/config/sets")

		try:
			os.makedirs(default_sets_conf_dir)
		except os.error:
			pass

		provided_sets_portage_conf = \
			os.path.join(PORTAGE_BASE_PATH, "cnf/sets/portage.conf")
		os.symlink(provided_sets_portage_conf, os.path.join(default_sets_conf_dir, "portage.conf"))

		set_config_dir = os.path.join(user_config_dir, "sets")

		try:
			os.makedirs(set_config_dir)
		except os.error:
			pass

		for sets_file, lines in sets.items():
			file_name = os.path.join(set_config_dir, sets_file)
			f = open(file_name, "w")
			for line in lines:
				f.write("%s\n" % line)
			f.close()
コード例 #17
0
	def _create_profile(self, ebuilds, installed, profile, repo_configs, user_config, sets):

		user_config_dir = os.path.join(self.eroot, USER_CONFIG_PATH)

		try:
			os.makedirs(user_config_dir)
		except os.error:
			pass

		for repo in self._repositories:
			if repo == "DEFAULT":
				continue

			repo_dir = self._get_repo_dir(repo)
			profile_dir = os.path.join(repo_dir, "profiles")
			metadata_dir = os.path.join(repo_dir, "metadata")
			os.makedirs(metadata_dir)

			#Create $REPO/profiles/categories
			categories = set()
			for cpv in ebuilds:
				ebuilds_repo = Atom("="+cpv, allow_repo=True).repo
				if ebuilds_repo is None:
					ebuilds_repo = "test_repo"
				if ebuilds_repo == repo:
					categories.add(catsplit(cpv)[0])

			categories_file = os.path.join(profile_dir, "categories")
			with open(categories_file, "w") as f:
				for cat in categories:
					f.write(cat + "\n")

			#Create $REPO/profiles/license_groups
			license_file = os.path.join(profile_dir, "license_groups")
			with open(license_file, "w") as f:
				f.write("EULA TEST\n")

			repo_config = repo_configs.get(repo)
			if repo_config:
				for config_file, lines in repo_config.items():
					if config_file not in self.config_files and not any(fnmatch.fnmatch(config_file, os.path.join(x, "*")) for x in self.config_files):
						raise ValueError("Unknown config file: '%s'" % config_file)

					if config_file in ("layout.conf",):
						file_name = os.path.join(repo_dir, "metadata", config_file)
					else:
						file_name = os.path.join(profile_dir, config_file)
						if "/" in config_file and not os.path.isdir(os.path.dirname(file_name)):
							os.makedirs(os.path.dirname(file_name))
					with open(file_name, "w") as f:
						for line in lines:
							f.write("%s\n" % line)
						# Temporarily write empty value of masters until it becomes default.
						# TODO: Delete all references to "# use implicit masters" when empty value becomes default.
						if config_file == "layout.conf" and not any(line.startswith(("masters =", "# use implicit masters")) for line in lines):
							f.write("masters =\n")

			#Create $profile_dir/eclass (we fail to digest the ebuilds if it's not there)
			os.makedirs(os.path.join(repo_dir, "eclass"))

			# Temporarily write empty value of masters until it becomes default.
			if not repo_config or "layout.conf" not in repo_config:
				layout_conf_path = os.path.join(repo_dir, "metadata", "layout.conf")
				with open(layout_conf_path, "w") as f:
					f.write("masters =\n")

			if repo == "test_repo":
				#Create a minimal profile in /usr/portage
				sub_profile_dir = os.path.join(profile_dir, "default", "linux", "x86", "test_profile")
				os.makedirs(sub_profile_dir)

				if not (profile and "eapi" in profile):
					eapi_file = os.path.join(sub_profile_dir, "eapi")
					with open(eapi_file, "w") as f:
						f.write("0\n")

				make_defaults_file = os.path.join(sub_profile_dir, "make.defaults")
				with open(make_defaults_file, "w") as f:
					f.write("ARCH=\"x86\"\n")
					f.write("ACCEPT_KEYWORDS=\"x86\"\n")

				use_force_file = os.path.join(sub_profile_dir, "use.force")
				with open(use_force_file, "w") as f:
					f.write("x86\n")

				parent_file = os.path.join(sub_profile_dir, "parent")
				with open(parent_file, "w") as f:
					f.write("..\n")

				if profile:
					for config_file, lines in profile.items():
						if config_file not in self.config_files:
							raise ValueError("Unknown config file: '%s'" % config_file)

						file_name = os.path.join(sub_profile_dir, config_file)
						with open(file_name, "w") as f:
							for line in lines:
								f.write("%s\n" % line)

				#Create profile symlink
				os.symlink(sub_profile_dir, os.path.join(user_config_dir, "make.profile"))

		make_conf = {
			"ACCEPT_KEYWORDS": "x86",
			"CLEAN_DELAY": "0",
			"DISTDIR" : self.distdir,
			"EMERGE_WARNING_DELAY": "0",
			"PKGDIR": self.pkgdir,
			"PORTAGE_INST_GID": str(portage.data.portage_gid),
			"PORTAGE_INST_UID": str(portage.data.portage_uid),
			"PORTAGE_TMPDIR": os.path.join(self.eroot, 'var/tmp'),
		}

		if os.environ.get("NOCOLOR"):
			make_conf["NOCOLOR"] = os.environ["NOCOLOR"]

		# Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
		# need to be inherited by ebuild subprocesses.
		if 'PORTAGE_USERNAME' in os.environ:
			make_conf['PORTAGE_USERNAME'] = os.environ['PORTAGE_USERNAME']
		if 'PORTAGE_GRPNAME' in os.environ:
			make_conf['PORTAGE_GRPNAME'] = os.environ['PORTAGE_GRPNAME']

		make_conf_lines = []
		for k_v in make_conf.items():
			make_conf_lines.append('%s="%s"' % k_v)

		if "make.conf" in user_config:
			make_conf_lines.extend(user_config["make.conf"])

		if not portage.process.sandbox_capable or \
			os.environ.get("SANDBOX_ON") == "1":
			# avoid problems from nested sandbox instances
			make_conf_lines.append('FEATURES="${FEATURES} -sandbox -usersandbox"')

		configs = user_config.copy()
		configs["make.conf"] = make_conf_lines

		for config_file, lines in configs.items():
			if config_file not in self.config_files:
				raise ValueError("Unknown config file: '%s'" % config_file)

			file_name = os.path.join(user_config_dir, config_file)
			with open(file_name, "w") as f:
				for line in lines:
					f.write("%s\n" % line)

		#Create /usr/share/portage/config/make.globals
		make_globals_path = os.path.join(self.eroot,
			GLOBAL_CONFIG_PATH.lstrip(os.sep), "make.globals")
		ensure_dirs(os.path.dirname(make_globals_path))
		os.symlink(os.path.join(cnf_path, "make.globals"),
			make_globals_path)

		#Create /usr/share/portage/config/sets/portage.conf
		default_sets_conf_dir = os.path.join(self.eroot, "usr/share/portage/config/sets")

		try:
			os.makedirs(default_sets_conf_dir)
		except os.error:
			pass

		provided_sets_portage_conf = (
			os.path.join(cnf_path, "sets", "portage.conf"))
		os.symlink(provided_sets_portage_conf, os.path.join(default_sets_conf_dir, "portage.conf"))

		set_config_dir = os.path.join(user_config_dir, "sets")

		try:
			os.makedirs(set_config_dir)
		except os.error:
			pass

		for sets_file, lines in sets.items():
			file_name = os.path.join(set_config_dir, sets_file)
			with open(file_name, "w") as f:
				for line in lines:
					f.write("%s\n" % line)
コード例 #18
0
def fetch(myuris, mysettings, listonly=0, fetchonly=0,
	locks_in_subdir=".locks", use_locks=1, try_mirrors=1, digests=None,
	allow_missing_digests=True, force=False):
	"""
	Fetch files to DISTDIR and also verify digests if they are available.

	@param myuris: Maps each file name to a tuple of available fetch URIs.
	@type myuris: dict
	@param mysettings: Portage config instance.
	@type mysettings: portage.config
	@param listonly: Only print URIs and do not actually fetch them.
	@type listonly: bool
	@param fetchonly: Do not block for files that are locked by a
		concurrent fetcher process. This means that the function can
		return successfully *before* all files have been successfully
		fetched!
	@type fetchonly: bool
	@param use_locks: Enable locks. This parameter is ineffective if
		FEATURES=distlocks is disabled in the portage config!
	@type use_locks: bool
	@param digests: Maps each file name to a dict of digest types and values.
	@type digests: dict
	@param allow_missing_digests: Enable fetch even if there are no digests
		available for verification.
	@type allow_missing_digests: bool
	@param force: Force download, even when a file already exists in
		DISTDIR. This is most useful when there are no digests available,
		since otherwise download will be automatically forced if the
		existing file does not match the available digests. Also, this
		avoids the need to remove the existing file in advance, which
		makes it possible to atomically replace the file and avoid
		interference with concurrent processes.
	@type force: bool
	@rtype: int
	@return: 1 if successful, 0 otherwise.
	"""

	if force and digests:
		# Since the force parameter can trigger unnecessary fetch when the
		# digests match, do not allow force=True when digests are provided.
		raise PortageException(_('fetch: force=True is not allowed when digests are provided'))

	if not myuris:
		return 1

	features = mysettings.features
	restrict = mysettings.get("PORTAGE_RESTRICT","").split()
	userfetch = portage.data.secpass >= 2 and "userfetch" in features

	# 'nomirror' is bad/negative logic. You Restrict mirroring, not no-mirroring.
	restrict_mirror = "mirror" in restrict or "nomirror" in restrict
	if restrict_mirror:
		if ("mirror" in features) and ("lmirror" not in features):
			# lmirror should allow you to bypass mirror restrictions.
			# XXX: This is not a good thing, and is temporary at best.
			print(_(">>> \"mirror\" mode desired and \"mirror\" restriction found; skipping fetch."))
			return 1

	# Generally, downloading the same file repeatedly from
	# every single available mirror is a waste of bandwidth
	# and time, so there needs to be a cap.
	checksum_failure_max_tries = 5
	v = checksum_failure_max_tries
	try:
		v = int(mysettings.get("PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS",
			checksum_failure_max_tries))
	except (ValueError, OverflowError):
		writemsg(_("!!! Variable PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS"
			" contains non-integer value: '%s'\n") % \
			mysettings["PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS"], noiselevel=-1)
		writemsg(_("!!! Using PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS "
			"default value: %s\n") % checksum_failure_max_tries,
			noiselevel=-1)
		v = checksum_failure_max_tries
	if v < 1:
		writemsg(_("!!! Variable PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS"
			" contains value less than 1: '%s'\n") % v, noiselevel=-1)
		writemsg(_("!!! Using PORTAGE_FETCH_CHECKSUM_TRY_MIRRORS "
			"default value: %s\n") % checksum_failure_max_tries,
			noiselevel=-1)
		v = checksum_failure_max_tries
	checksum_failure_max_tries = v
	del v

	fetch_resume_size_default = "350K"
	fetch_resume_size = mysettings.get("PORTAGE_FETCH_RESUME_MIN_SIZE")
	if fetch_resume_size is not None:
		fetch_resume_size = "".join(fetch_resume_size.split())
		if not fetch_resume_size:
			# If it's undefined or empty, silently use the default.
			fetch_resume_size = fetch_resume_size_default
		match = _fetch_resume_size_re.match(fetch_resume_size)
		if match is None or \
			(match.group(2).upper() not in _size_suffix_map):
			writemsg(_("!!! Variable PORTAGE_FETCH_RESUME_MIN_SIZE"
				" contains an unrecognized format: '%s'\n") % \
				mysettings["PORTAGE_FETCH_RESUME_MIN_SIZE"], noiselevel=-1)
			writemsg(_("!!! Using PORTAGE_FETCH_RESUME_MIN_SIZE "
				"default value: %s\n") % fetch_resume_size_default,
				noiselevel=-1)
			fetch_resume_size = None
	if fetch_resume_size is None:
		fetch_resume_size = fetch_resume_size_default
		match = _fetch_resume_size_re.match(fetch_resume_size)
	fetch_resume_size = int(match.group(1)) * \
		2 ** _size_suffix_map[match.group(2).upper()]

	# Behave like the package has RESTRICT="primaryuri" after a
	# couple of checksum failures, to increase the probablility
	# of success before checksum_failure_max_tries is reached.
	checksum_failure_primaryuri = 2
	thirdpartymirrors = mysettings.thirdpartymirrors()

	# In the background parallel-fetch process, it's safe to skip checksum
	# verification of pre-existing files in $DISTDIR that have the correct
	# file size. The parent process will verify their checksums prior to
	# the unpack phase.

	parallel_fetchonly = "PORTAGE_PARALLEL_FETCHONLY" in mysettings
	if parallel_fetchonly:
		fetchonly = 1

	check_config_instance(mysettings)

	custommirrors = grabdict(os.path.join(mysettings["PORTAGE_CONFIGROOT"],
		CUSTOM_MIRRORS_FILE), recursive=1)

	mymirrors=[]

	if listonly or ("distlocks" not in features):
		use_locks = 0

	distdir_writable = os.access(mysettings["DISTDIR"], os.W_OK)
	fetch_to_ro = 0
	if "skiprocheck" in features:
		fetch_to_ro = 1

	if not distdir_writable and fetch_to_ro:
		if use_locks:
			writemsg(colorize("BAD",
				_("!!! For fetching to a read-only filesystem, "
				"locking should be turned off.\n")), noiselevel=-1)
			writemsg(_("!!! This can be done by adding -distlocks to "
				"FEATURES in /etc/portage/make.conf\n"), noiselevel=-1)
#			use_locks = 0

	# local mirrors are always added
	if try_mirrors and "local" in custommirrors:
		mymirrors += custommirrors["local"]

	if restrict_mirror:
		# We don't add any mirrors.
		pass
	else:
		if try_mirrors:
			mymirrors += [x.rstrip("/") for x in mysettings["GENTOO_MIRRORS"].split() if x]

	hash_filter = _hash_filter(mysettings.get("PORTAGE_CHECKSUM_FILTER", ""))
	if hash_filter.transparent:
		hash_filter = None
	skip_manifest = mysettings.get("EBUILD_SKIP_MANIFEST") == "1"
	if skip_manifest:
		allow_missing_digests = True
	pkgdir = mysettings.get("O")
	if digests is None and not (pkgdir is None or skip_manifest):
		mydigests = mysettings.repositories.get_repo_for_location(
			os.path.dirname(os.path.dirname(pkgdir))).load_manifest(
			pkgdir, mysettings["DISTDIR"]).getTypeDigests("DIST")
	elif digests is None or skip_manifest:
		# no digests because fetch was not called for a specific package
		mydigests = {}
	else:
		mydigests = digests

	ro_distdirs = [x for x in \
		shlex_split(mysettings.get("PORTAGE_RO_DISTDIRS", "")) \
		if os.path.isdir(x)]

	fsmirrors = []
	for x in range(len(mymirrors)-1,-1,-1):
		if mymirrors[x] and mymirrors[x][0]=='/':
			fsmirrors += [mymirrors[x]]
			del mymirrors[x]

	restrict_fetch = "fetch" in restrict
	force_mirror = "force-mirror" in features and not restrict_mirror
	custom_local_mirrors = custommirrors.get("local", [])
	if restrict_fetch:
		# With fetch restriction, a normal uri may only be fetched from
		# custom local mirrors (if available).  A mirror:// uri may also
		# be fetched from specific mirrors (effectively overriding fetch
		# restriction, but only for specific mirrors).
		locations = custom_local_mirrors
	else:
		locations = mymirrors

	file_uri_tuples = []
	# Check for 'items' attribute since OrderedDict is not a dict.
	if hasattr(myuris, 'items'):
		for myfile, uri_set in myuris.items():
			for myuri in uri_set:
				file_uri_tuples.append((myfile, myuri))
			if not uri_set:
				file_uri_tuples.append((myfile, None))
	else:
		for myuri in myuris:
			if urlparse(myuri).scheme:
				file_uri_tuples.append((os.path.basename(myuri), myuri))
			else:
				file_uri_tuples.append((os.path.basename(myuri), None))

	filedict = OrderedDict()
	primaryuri_dict = {}
	thirdpartymirror_uris = {}
	for myfile, myuri in file_uri_tuples:
		if myfile not in filedict:
			filedict[myfile]=[]
			if distdir_writable:
				mirror_cache = os.path.join(mysettings["DISTDIR"],
						".mirror-cache.json")
			else:
				mirror_cache = None
			for l in locations:
				filedict[myfile].append(functools.partial(
					get_mirror_url, l, myfile, mysettings, mirror_cache))
		if myuri is None:
			continue
		if myuri[:9]=="mirror://":
			eidx = myuri.find("/", 9)
			if eidx != -1:
				mirrorname = myuri[9:eidx]
				path = myuri[eidx+1:]

				# Try user-defined mirrors first
				if mirrorname in custommirrors:
					for cmirr in custommirrors[mirrorname]:
						filedict[myfile].append(
							cmirr.rstrip("/") + "/" + path)

				# now try the official mirrors
				if mirrorname in thirdpartymirrors:
					uris = [locmirr.rstrip("/") + "/" + path \
						for locmirr in thirdpartymirrors[mirrorname]]
					random.shuffle(uris)
					filedict[myfile].extend(uris)
					thirdpartymirror_uris.setdefault(myfile, []).extend(uris)

				if mirrorname not in custommirrors and \
					mirrorname not in thirdpartymirrors:
					writemsg(_("!!! No known mirror by the name: %s\n") % (mirrorname))
			else:
				writemsg(_("Invalid mirror definition in SRC_URI:\n"), noiselevel=-1)
				writemsg("  %s\n" % (myuri), noiselevel=-1)
		else:
			if restrict_fetch or force_mirror:
				# Only fetch from specific mirrors is allowed.
				continue
			primaryuris = primaryuri_dict.get(myfile)
			if primaryuris is None:
				primaryuris = []
				primaryuri_dict[myfile] = primaryuris
			primaryuris.append(myuri)

	# Order primaryuri_dict values to match that in SRC_URI.
	for uris in primaryuri_dict.values():
		uris.reverse()

	# Prefer thirdpartymirrors over normal mirrors in cases when
	# the file does not yet exist on the normal mirrors.
	for myfile, uris in thirdpartymirror_uris.items():
		primaryuri_dict.setdefault(myfile, []).extend(uris)

	# Now merge primaryuri values into filedict (includes mirrors
	# explicitly referenced in SRC_URI).
	if "primaryuri" in restrict:
		for myfile, uris in filedict.items():
			filedict[myfile] = primaryuri_dict.get(myfile, []) + uris
	else:
		for myfile in filedict:
			filedict[myfile] += primaryuri_dict.get(myfile, [])

	can_fetch=True

	if listonly:
		can_fetch = False

	if can_fetch and not fetch_to_ro:
		try:
			_ensure_distdir(mysettings, mysettings["DISTDIR"])
		except PortageException as e:
			if not os.path.isdir(mysettings["DISTDIR"]):
				writemsg("!!! %s\n" % str(e), noiselevel=-1)
				writemsg(_("!!! Directory Not Found: DISTDIR='%s'\n") % mysettings["DISTDIR"], noiselevel=-1)
				writemsg(_("!!! Fetching will fail!\n"), noiselevel=-1)

	if can_fetch and \
		not fetch_to_ro and \
		not os.access(mysettings["DISTDIR"], os.W_OK):
		writemsg(_("!!! No write access to '%s'\n") % mysettings["DISTDIR"],
			noiselevel=-1)
		can_fetch = False

	distdir_writable = can_fetch and not fetch_to_ro
	failed_files = set()
	restrict_fetch_msg = False
	valid_hashes = set(get_valid_checksum_keys())
	valid_hashes.discard("size")

	for myfile in filedict:
		"""
		fetched  status
		0        nonexistent
		1        partially downloaded
		2        completely downloaded
		"""
		fetched = 0

		orig_digests = mydigests.get(myfile, {})

		if not (allow_missing_digests or listonly):
			verifiable_hash_types = set(orig_digests).intersection(valid_hashes)
			if not verifiable_hash_types:
				expected = " ".join(sorted(valid_hashes))
				got = set(orig_digests)
				got.discard("size")
				got = " ".join(sorted(got))
				reason = (_("Insufficient data for checksum verification"),
					got, expected)
				writemsg(_("!!! Fetched file: %s VERIFY FAILED!\n") % myfile,
					noiselevel=-1)
				writemsg(_("!!! Reason: %s\n") % reason[0],
					noiselevel=-1)
				writemsg(_("!!! Got:      %s\n!!! Expected: %s\n") % \
					(reason[1], reason[2]), noiselevel=-1)

				if fetchonly:
					failed_files.add(myfile)
					continue
				else:
					return 0

		size = orig_digests.get("size")
		if size == 0:
			# Zero-byte distfiles are always invalid, so discard their digests.
			del mydigests[myfile]
			orig_digests.clear()
			size = None
		pruned_digests = orig_digests
		if parallel_fetchonly:
			pruned_digests = {}
			if size is not None:
				pruned_digests["size"] = size

		myfile_path = os.path.join(mysettings["DISTDIR"], myfile)
		download_path = myfile_path if fetch_to_ro else myfile_path + _download_suffix
		has_space = True
		has_space_superuser = True
		file_lock = None
		if listonly:
			writemsg_stdout("\n", noiselevel=-1)
		else:
			# check if there is enough space in DISTDIR to completely store myfile
			# overestimate the filesize so we aren't bitten by FS overhead
			vfs_stat = None
			if size is not None and hasattr(os, "statvfs"):
				try:
					vfs_stat = os.statvfs(mysettings["DISTDIR"])
				except OSError as e:
					writemsg_level("!!! statvfs('%s'): %s\n" %
						(mysettings["DISTDIR"], e),
						noiselevel=-1, level=logging.ERROR)
					del e

			if vfs_stat is not None:
				try:
					mysize = os.stat(myfile_path).st_size
				except OSError as e:
					if e.errno not in (errno.ENOENT, errno.ESTALE):
						raise
					del e
					mysize = 0
				if (size - mysize + vfs_stat.f_bsize) >= \
					(vfs_stat.f_bsize * vfs_stat.f_bavail):

					if (size - mysize + vfs_stat.f_bsize) >= \
						(vfs_stat.f_bsize * vfs_stat.f_bfree):
						has_space_superuser = False

					if not has_space_superuser:
						has_space = False
					elif portage.data.secpass < 2:
						has_space = False
					elif userfetch:
						has_space = False

			if distdir_writable and use_locks:

				lock_kwargs = {}
				if fetchonly:
					lock_kwargs["flags"] = os.O_NONBLOCK

				try:
					file_lock = lockfile(myfile_path,
						wantnewlockfile=1, **lock_kwargs)
				except TryAgain:
					writemsg(_(">>> File '%s' is already locked by "
						"another fetcher. Continuing...\n") % myfile,
						noiselevel=-1)
					continue
		try:
			if not listonly:

				eout = EOutput()
				eout.quiet = mysettings.get("PORTAGE_QUIET") == "1"
				match, mystat = _check_distfile(
					myfile_path, pruned_digests, eout, hash_filter=hash_filter)
				if match and not force:
					# Skip permission adjustment for symlinks, since we don't
					# want to modify anything outside of the primary DISTDIR,
					# and symlinks typically point to PORTAGE_RO_DISTDIRS.
					if distdir_writable and not os.path.islink(myfile_path):
						try:
							apply_secpass_permissions(myfile_path,
								gid=portage_gid, mode=0o664, mask=0o2,
								stat_cached=mystat)
						except PortageException as e:
							if not os.access(myfile_path, os.R_OK):
								writemsg(_("!!! Failed to adjust permissions:"
									" %s\n") % str(e), noiselevel=-1)
							del e
					continue

				# Remove broken symlinks or symlinks to files which
				# _check_distfile did not match above.
				if distdir_writable and mystat is None or os.path.islink(myfile_path):
					try:
						os.unlink(myfile_path)
					except OSError as e:
						if e.errno not in (errno.ENOENT, errno.ESTALE):
							raise
					mystat = None

				if mystat is not None:
					if stat.S_ISDIR(mystat.st_mode):
						writemsg_level(
							_("!!! Unable to fetch file since "
							"a directory is in the way: \n"
							"!!!   %s\n") % myfile_path,
							level=logging.ERROR, noiselevel=-1)
						return 0

					if distdir_writable and not force:
						# Since _check_distfile did not match above, the file
						# is either corrupt or its identity has changed since
						# the last time it was fetched, so rename it.
						temp_filename = _checksum_failure_temp_file(
							mysettings, mysettings["DISTDIR"], myfile)
						writemsg_stdout(_("Refetching... "
							"File renamed to '%s'\n\n") % \
							temp_filename, noiselevel=-1)

				# Stat the temporary download file for comparison with
				# fetch_resume_size.
				try:
					mystat = os.stat(download_path)
				except OSError as e:
					if e.errno not in (errno.ENOENT, errno.ESTALE):
						raise
					mystat = None

				if mystat is not None:
					if mystat.st_size == 0:
						if distdir_writable:
							try:
								os.unlink(download_path)
							except OSError:
								pass
					elif distdir_writable and size is not None:
						if mystat.st_size < fetch_resume_size and \
							mystat.st_size < size:
							# If the file already exists and the size does not
							# match the existing digests, it may be that the
							# user is attempting to update the digest. In this
							# case, the digestgen() function will advise the
							# user to use `ebuild --force foo.ebuild manifest`
							# in order to force the old digests to be replaced.
							# Since the user may want to keep this file, rename
							# it instead of deleting it.
							writemsg(_(">>> Renaming distfile with size "
								"%d (smaller than " "PORTAGE_FETCH_RESU"
								"ME_MIN_SIZE)\n") % mystat.st_size)
							temp_filename = \
								_checksum_failure_temp_file(
									mysettings, mysettings["DISTDIR"],
									os.path.basename(download_path))
							writemsg_stdout(_("Refetching... "
								"File renamed to '%s'\n\n") % \
								temp_filename, noiselevel=-1)
						elif mystat.st_size >= size:
							temp_filename = \
								_checksum_failure_temp_file(
									mysettings, mysettings["DISTDIR"],
									os.path.basename(download_path))
							writemsg_stdout(_("Refetching... "
								"File renamed to '%s'\n\n") % \
								temp_filename, noiselevel=-1)

				if distdir_writable and ro_distdirs:
					readonly_file = None
					for x in ro_distdirs:
						filename = os.path.join(x, myfile)
						match, mystat = _check_distfile(
							filename, pruned_digests, eout, hash_filter=hash_filter)
						if match:
							readonly_file = filename
							break
					if readonly_file is not None:
						try:
							os.unlink(myfile_path)
						except OSError as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e
						os.symlink(readonly_file, myfile_path)
						continue

				# this message is shown only after we know that
				# the file is not already fetched
				if not has_space:
					writemsg(_("!!! Insufficient space to store %s in %s\n") % \
						(myfile, mysettings["DISTDIR"]), noiselevel=-1)

					if has_space_superuser:
						writemsg(_("!!! Insufficient privileges to use "
							"remaining space.\n"), noiselevel=-1)
						if userfetch:
							writemsg(_("!!! You may set FEATURES=\"-userfetch\""
								" in /etc/portage/make.conf in order to fetch with\n"
								"!!! superuser privileges.\n"), noiselevel=-1)

				if fsmirrors and not os.path.exists(myfile_path) and has_space:
					for mydir in fsmirrors:
						mirror_file = os.path.join(mydir, myfile)
						try:
							shutil.copyfile(mirror_file, download_path)
							writemsg(_("Local mirror has file: %s\n") % myfile)
							break
						except (IOError, OSError) as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e

				try:
					mystat = os.stat(download_path)
				except OSError as e:
					if e.errno not in (errno.ENOENT, errno.ESTALE):
						raise
					del e
				else:
					# Skip permission adjustment for symlinks, since we don't
					# want to modify anything outside of the primary DISTDIR,
					# and symlinks typically point to PORTAGE_RO_DISTDIRS.
					if not os.path.islink(download_path):
						try:
							apply_secpass_permissions(download_path,
								gid=portage_gid, mode=0o664, mask=0o2,
								stat_cached=mystat)
						except PortageException as e:
							if not os.access(download_path, os.R_OK):
								writemsg(_("!!! Failed to adjust permissions:"
									" %s\n") % (e,), noiselevel=-1)

					# If the file is empty then it's obviously invalid. Remove
					# the empty file and try to download if possible.
					if mystat.st_size == 0:
						if distdir_writable:
							try:
								os.unlink(download_path)
							except EnvironmentError:
								pass
					elif not orig_digests:
						# We don't have a digest, but the file exists.  We must
						# assume that it is fully downloaded.
						if not force:
							continue
					else:
						if (mydigests[myfile].get("size") is not None
								and mystat.st_size < mydigests[myfile]["size"]
								and not restrict_fetch):
							fetched = 1 # Try to resume this download.
						elif parallel_fetchonly and \
							mystat.st_size == mydigests[myfile]["size"]:
							eout = EOutput()
							eout.quiet = \
								mysettings.get("PORTAGE_QUIET") == "1"
							eout.ebegin(
								"%s size ;-)" % (myfile, ))
							eout.eend(0)
							continue
						else:
							digests = _filter_unaccelarated_hashes(mydigests[myfile])
							if hash_filter is not None:
								digests = _apply_hash_filter(digests, hash_filter)
							verified_ok, reason = verify_all(download_path, digests)
							if not verified_ok:
								writemsg(_("!!! Previously fetched"
									" file: '%s'\n") % myfile, noiselevel=-1)
								writemsg(_("!!! Reason: %s\n") % reason[0],
									noiselevel=-1)
								writemsg(_("!!! Got:      %s\n"
									"!!! Expected: %s\n") % \
									(reason[1], reason[2]), noiselevel=-1)
								if reason[0] == _("Insufficient data for checksum verification"):
									return 0
								if distdir_writable:
									temp_filename = \
										_checksum_failure_temp_file(
											mysettings, mysettings["DISTDIR"],
											os.path.basename(download_path))
									writemsg_stdout(_("Refetching... "
										"File renamed to '%s'\n\n") % \
										temp_filename, noiselevel=-1)
							else:
								if not fetch_to_ro:
									_movefile(download_path, myfile_path, mysettings=mysettings)
								eout = EOutput()
								eout.quiet = \
									mysettings.get("PORTAGE_QUIET", None) == "1"
								if digests:
									digests = list(digests)
									digests.sort()
									eout.ebegin(
										"%s %s ;-)" % (myfile, " ".join(digests)))
									eout.eend(0)
								continue # fetch any remaining files

			# Create a reversed list since that is optimal for list.pop().
			uri_list = filedict[myfile][:]
			uri_list.reverse()
			checksum_failure_count = 0
			tried_locations = set()
			while uri_list:
				loc = uri_list.pop()
				if isinstance(loc, functools.partial):
					loc = loc()
				# Eliminate duplicates here in case we've switched to
				# "primaryuri" mode on the fly due to a checksum failure.
				if loc in tried_locations:
					continue
				tried_locations.add(loc)
				if listonly:
					writemsg_stdout(loc+" ", noiselevel=-1)
					continue
				# allow different fetchcommands per protocol
				protocol = loc[0:loc.find("://")]

				global_config_path = GLOBAL_CONFIG_PATH
				if portage.const.EPREFIX:
					global_config_path = os.path.join(portage.const.EPREFIX,
							GLOBAL_CONFIG_PATH.lstrip(os.sep))

				missing_file_param = False
				fetchcommand_var = "FETCHCOMMAND_" + protocol.upper()
				fetchcommand = mysettings.get(fetchcommand_var)
				if fetchcommand is None:
					fetchcommand_var = "FETCHCOMMAND"
					fetchcommand = mysettings.get(fetchcommand_var)
					if fetchcommand is None:
						writemsg_level(
							_("!!! %s is unset. It should "
							"have been defined in\n!!! %s/make.globals.\n") \
							% (fetchcommand_var, global_config_path),
							level=logging.ERROR, noiselevel=-1)
						return 0
				if "${FILE}" not in fetchcommand:
					writemsg_level(
						_("!!! %s does not contain the required ${FILE}"
						" parameter.\n") % fetchcommand_var,
						level=logging.ERROR, noiselevel=-1)
					missing_file_param = True

				resumecommand_var = "RESUMECOMMAND_" + protocol.upper()
				resumecommand = mysettings.get(resumecommand_var)
				if resumecommand is None:
					resumecommand_var = "RESUMECOMMAND"
					resumecommand = mysettings.get(resumecommand_var)
					if resumecommand is None:
						writemsg_level(
							_("!!! %s is unset. It should "
							"have been defined in\n!!! %s/make.globals.\n") \
							% (resumecommand_var, global_config_path),
							level=logging.ERROR, noiselevel=-1)
						return 0
				if "${FILE}" not in resumecommand:
					writemsg_level(
						_("!!! %s does not contain the required ${FILE}"
						" parameter.\n") % resumecommand_var,
						level=logging.ERROR, noiselevel=-1)
					missing_file_param = True

				if missing_file_param:
					writemsg_level(
						_("!!! Refer to the make.conf(5) man page for "
						"information about how to\n!!! correctly specify "
						"FETCHCOMMAND and RESUMECOMMAND.\n"),
						level=logging.ERROR, noiselevel=-1)
					if myfile != os.path.basename(loc):
						return 0

				if not can_fetch:
					if fetched != 2:
						try:
							mysize = os.stat(download_path).st_size
						except OSError as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e
							mysize = 0

						if mysize == 0:
							writemsg(_("!!! File %s isn't fetched but unable to get it.\n") % myfile,
								noiselevel=-1)
						elif size is None or size > mysize:
							writemsg(_("!!! File %s isn't fully fetched, but unable to complete it\n") % myfile,
								noiselevel=-1)
						else:
							writemsg(_("!!! File %s is incorrect size, "
								"but unable to retry.\n") % myfile, noiselevel=-1)
						return 0
					else:
						continue

				if fetched != 2 and has_space:
					#we either need to resume or start the download
					if fetched == 1:
						try:
							mystat = os.stat(download_path)
						except OSError as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e
							fetched = 0
						else:
							if distdir_writable and mystat.st_size < fetch_resume_size:
								writemsg(_(">>> Deleting distfile with size "
									"%d (smaller than " "PORTAGE_FETCH_RESU"
									"ME_MIN_SIZE)\n") % mystat.st_size)
								try:
									os.unlink(download_path)
								except OSError as e:
									if e.errno not in \
										(errno.ENOENT, errno.ESTALE):
										raise
									del e
								fetched = 0
					if fetched == 1:
						#resume mode:
						writemsg(_(">>> Resuming download...\n"))
						locfetch=resumecommand
						command_var = resumecommand_var
					else:
						#normal mode:
						locfetch=fetchcommand
						command_var = fetchcommand_var
					writemsg_stdout(_(">>> Downloading '%s'\n") % \
						_hide_url_passwd(loc))
					variables = {
						"URI":     loc,
						"FILE":    os.path.basename(download_path)
					}

					for k in ("DISTDIR", "PORTAGE_SSH_OPTS"):
						v = mysettings.get(k)
						if v is not None:
							variables[k] = v

					myfetch = shlex_split(locfetch)
					myfetch = [varexpand(x, mydict=variables) for x in myfetch]
					myret = -1
					try:

						myret = _spawn_fetch(mysettings, myfetch)

					finally:
						try:
							apply_secpass_permissions(download_path,
								gid=portage_gid, mode=0o664, mask=0o2)
						except FileNotFound:
							pass
						except PortageException as e:
							if not os.access(download_path, os.R_OK):
								writemsg(_("!!! Failed to adjust permissions:"
									" %s\n") % str(e), noiselevel=-1)
							del e

					# If the file is empty then it's obviously invalid.  Don't
					# trust the return value from the fetcher.  Remove the
					# empty file and try to download again.
					try:
						mystat = os.lstat(download_path)
						if mystat.st_size == 0 or (stat.S_ISLNK(mystat.st_mode) and not os.path.exists(download_path)):
							os.unlink(download_path)
							fetched = 0
							continue
					except EnvironmentError:
						pass

					if mydigests is not None and myfile in mydigests:
						try:
							mystat = os.stat(download_path)
						except OSError as e:
							if e.errno not in (errno.ENOENT, errno.ESTALE):
								raise
							del e
							fetched = 0
						else:

							if stat.S_ISDIR(mystat.st_mode):
								# This can happen if FETCHCOMMAND erroneously
								# contains wget's -P option where it should
								# instead have -O.
								writemsg_level(
									_("!!! The command specified in the "
									"%s variable appears to have\n!!! "
									"created a directory instead of a "
									"normal file.\n") % command_var,
									level=logging.ERROR, noiselevel=-1)
								writemsg_level(
									_("!!! Refer to the make.conf(5) "
									"man page for information about how "
									"to\n!!! correctly specify "
									"FETCHCOMMAND and RESUMECOMMAND.\n"),
									level=logging.ERROR, noiselevel=-1)
								return 0

							# no exception?  file exists. let digestcheck() report
							# an appropriately for size or checksum errors

							# If the fetcher reported success and the file is
							# too small, it's probably because the digest is
							# bad (upstream changed the distfile).  In this
							# case we don't want to attempt to resume. Show a
							# digest verification failure to that the user gets
							# a clue about what just happened.
							if myret != os.EX_OK and \
								mystat.st_size < mydigests[myfile]["size"]:
								# Fetch failed... Try the next one... Kill 404 files though.
								if (mystat[stat.ST_SIZE]<100000) and (len(myfile)>4) and not ((myfile[-5:]==".html") or (myfile[-4:]==".htm")):
									html404=re.compile("<title>.*(not found|404).*</title>",re.I|re.M)
									with io.open(
										_unicode_encode(download_path,
										encoding=_encodings['fs'], errors='strict'),
										mode='r', encoding=_encodings['content'], errors='replace'
										) as f:
										if html404.search(f.read()):
											try:
												os.unlink(download_path)
												writemsg(_(">>> Deleting invalid distfile. (Improper 404 redirect from server.)\n"))
												fetched = 0
												continue
											except (IOError, OSError):
												pass
								fetched = 1
								continue
							if True:
								# File is the correct size--check the checksums for the fetched
								# file NOW, for those users who don't have a stable/continuous
								# net connection. This way we have a chance to try to download
								# from another mirror...
								digests = _filter_unaccelarated_hashes(mydigests[myfile])
								if hash_filter is not None:
									digests = _apply_hash_filter(digests, hash_filter)
								verified_ok, reason = verify_all(download_path, digests)
								if not verified_ok:
									writemsg(_("!!! Fetched file: %s VERIFY FAILED!\n") % myfile,
										noiselevel=-1)
									writemsg(_("!!! Reason: %s\n") % reason[0],
										noiselevel=-1)
									writemsg(_("!!! Got:      %s\n!!! Expected: %s\n") % \
										(reason[1], reason[2]), noiselevel=-1)
									if reason[0] == _("Insufficient data for checksum verification"):
										return 0
									if distdir_writable:
										temp_filename = \
											_checksum_failure_temp_file(
												mysettings, mysettings["DISTDIR"],
												os.path.basename(download_path))
										writemsg_stdout(_("Refetching... "
											"File renamed to '%s'\n\n") % \
											temp_filename, noiselevel=-1)
									fetched=0
									checksum_failure_count += 1
									if checksum_failure_count == \
										checksum_failure_primaryuri:
										# Switch to "primaryuri" mode in order
										# to increase the probablility of
										# of success.
										primaryuris = \
											primaryuri_dict.get(myfile)
										if primaryuris:
											uri_list.extend(
												reversed(primaryuris))
									if checksum_failure_count >= \
										checksum_failure_max_tries:
										break
								else:
									if not fetch_to_ro:
										_movefile(download_path, myfile_path, mysettings=mysettings)
									eout = EOutput()
									eout.quiet = mysettings.get("PORTAGE_QUIET", None) == "1"
									if digests:
										eout.ebegin("%s %s ;-)" % \
											(myfile, " ".join(sorted(digests))))
										eout.eend(0)
									fetched=2
									break
					else: # no digests available
						if not myret:
							if not fetch_to_ro:
								_movefile(download_path, myfile_path, mysettings=mysettings)
							fetched=2
							break
						elif mydigests!=None:
							writemsg(_("No digest file available and download failed.\n\n"),
								noiselevel=-1)
		finally:
			if use_locks and file_lock:
				unlockfile(file_lock)
				file_lock = None

		if listonly:
			writemsg_stdout("\n", noiselevel=-1)
		if fetched != 2:
			if restrict_fetch and not restrict_fetch_msg:
				restrict_fetch_msg = True
				msg = _("\n!!! %s/%s"
					" has fetch restriction turned on.\n"
					"!!! This probably means that this "
					"ebuild's files must be downloaded\n"
					"!!! manually.  See the comments in"
					" the ebuild for more information.\n\n") % \
					(mysettings["CATEGORY"], mysettings["PF"])
				writemsg_level(msg,
					level=logging.ERROR, noiselevel=-1)
			elif restrict_fetch:
				pass
			elif listonly:
				pass
			elif not filedict[myfile]:
				writemsg(_("Warning: No mirrors available for file"
					" '%s'\n") % (myfile), noiselevel=-1)
			else:
				writemsg(_("!!! Couldn't download '%s'. Aborting.\n") % myfile,
					noiselevel=-1)

			if listonly:
				failed_files.add(myfile)
				continue
			elif fetchonly:
				failed_files.add(myfile)
				continue
			return 0
	if failed_files:
		return 0
	return 1
コード例 #19
0
def main():
    """
    If the current installation is still configured to use any of the
    legacy default /usr/portage locations, then patch make.globals and
    repos.conf inside ${ED} to maintain compatible defaults. This is
    intended to be called from the ebuild as follows:

    pkg_preinst() {
            python_setup
            python_export PYTHON_SITEDIR
            env -u DISTDIR \
                    -u PORTAGE_OVERRIDE_EPREFIX \
                    -u PORTAGE_REPOSITORIES \
                    -u PORTDIR \
                    -u PORTDIR_OVERLAY \
                    PYTHONPATH="${ED%/}${PYTHON_SITEDIR}${PYTHONPATH:+:${PYTHONPATH}}" \
                    "${PYTHON}" -m portage._compat_upgrade.default_locations || die
    }
    """
    out = portage.output.EOutput()
    config = portage.settings

    compat_distdir = os.path.join(portage.const.EPREFIX or "/", COMPAT_DISTDIR)
    try:
        do_distdir = os.path.samefile(config["DISTDIR"], compat_distdir)
    except OSError:
        do_distdir = False

    compat_pkgdir = os.path.join(portage.const.EPREFIX or "/", COMPAT_PKGDIR)
    try:
        do_pkgdir = os.path.samefile(config["PKGDIR"], compat_pkgdir)
    except OSError:
        do_pkgdir = False

    compat_rpmdir = os.path.join(portage.const.EPREFIX or "/", COMPAT_RPMDIR)
    try:
        do_rpmdir = os.path.samefile(config["RPMDIR"], compat_rpmdir)
    except OSError:
        do_rpmdir = False

    compat_main_repo = os.path.join(portage.const.EPREFIX or "/",
                                    COMPAT_MAIN_REPO)
    try:
        do_main_repo = os.path.samefile(config.repositories.mainRepoLocation(),
                                        compat_main_repo)
    except OSError:
        do_main_repo = False

    if do_distdir or do_pkgdir or do_rpmdir:
        config_path = os.path.join(os.environ["ED"],
                                   GLOBAL_CONFIG_PATH.lstrip(os.sep),
                                   "make.globals")
        with open(config_path) as f:
            content = f.read()
            if do_distdir:
                compat_setting = 'DISTDIR="{}"'.format(compat_distdir)
                out.einfo(
                    "Setting make.globals default {} for backward compatibility"
                    .format(compat_setting))
                content = re.sub("^DISTDIR=.*$",
                                 compat_setting,
                                 content,
                                 flags=re.MULTILINE)
            if do_pkgdir:
                compat_setting = 'PKGDIR="{}"'.format(compat_pkgdir)
                out.einfo(
                    "Setting make.globals default {} for backward compatibility"
                    .format(compat_setting))
                content = re.sub("^PKGDIR=.*$",
                                 compat_setting,
                                 content,
                                 flags=re.MULTILINE)
            if do_rpmdir:
                compat_setting = 'RPMDIR="{}"'.format(compat_rpmdir)
                out.einfo(
                    "Setting make.globals default {} for backward compatibility"
                    .format(compat_setting))
                content = re.sub("^RPMDIR=.*$",
                                 compat_setting,
                                 content,
                                 flags=re.MULTILINE)
        with open(config_path, "wt") as f:
            f.write(content)

    if do_main_repo:
        config_path = os.path.join(os.environ["ED"],
                                   GLOBAL_CONFIG_PATH.lstrip(os.sep),
                                   "repos.conf")
        with open(config_path) as f:
            content = f.read()
            compat_setting = "location = {}".format(compat_main_repo)
            out.einfo(
                "Setting repos.conf default {} for backward compatibility".
                format(compat_setting))
            content = re.sub("^location =.*$",
                             compat_setting,
                             content,
                             flags=re.MULTILINE)
        with open(config_path, "wt") as f:
            f.write(content)
コード例 #20
0
    def _create_profile(self, ebuilds, installed, profile, repo_configs,
                        user_config, sets):

        user_config_dir = os.path.join(self.eroot, USER_CONFIG_PATH)

        try:
            os.makedirs(user_config_dir)
        except os.error:
            pass

        for repo in self.repo_dirs:
            repo_dir = self._get_repo_dir(repo)
            profile_dir = os.path.join(self._get_repo_dir(repo), "profiles")
            metadata_dir = os.path.join(repo_dir, "metadata")
            os.makedirs(metadata_dir)

            #Create $REPO/profiles/categories
            categories = set()
            for cpv in ebuilds:
                ebuilds_repo = Atom("=" + cpv, allow_repo=True).repo
                if ebuilds_repo is None:
                    ebuilds_repo = "test_repo"
                if ebuilds_repo == repo:
                    categories.add(catsplit(cpv)[0])

            categories_file = os.path.join(profile_dir, "categories")
            f = open(categories_file, "w")
            for cat in categories:
                f.write(cat + "\n")
            f.close()

            #Create $REPO/profiles/license_groups
            license_file = os.path.join(profile_dir, "license_groups")
            f = open(license_file, "w")
            f.write("EULA TEST\n")
            f.close()

            repo_config = repo_configs.get(repo)
            if repo_config:
                for config_file, lines in repo_config.items():
                    if config_file not in self.config_files:
                        raise ValueError("Unknown config file: '%s'" %
                                         config_file)

                    if config_file in ("layout.conf", ):
                        file_name = os.path.join(repo_dir, "metadata",
                                                 config_file)
                    else:
                        file_name = os.path.join(profile_dir, config_file)
                    f = open(file_name, "w")
                    for line in lines:
                        f.write("%s\n" % line)
                    f.close()

            #Create $profile_dir/eclass (we fail to digest the ebuilds if it's not there)
            os.makedirs(os.path.join(repo_dir, "eclass"))

            if repo == "test_repo":
                #Create a minimal profile in /usr/portage
                sub_profile_dir = os.path.join(profile_dir, "default", "linux",
                                               "x86", "test_profile")
                os.makedirs(sub_profile_dir)

                eapi_file = os.path.join(sub_profile_dir, "eapi")
                f = open(eapi_file, "w")
                f.write("0\n")
                f.close()

                make_defaults_file = os.path.join(sub_profile_dir,
                                                  "make.defaults")
                f = open(make_defaults_file, "w")
                f.write("ARCH=\"x86\"\n")
                f.write("ACCEPT_KEYWORDS=\"x86\"\n")
                f.close()

                use_force_file = os.path.join(sub_profile_dir, "use.force")
                f = open(use_force_file, "w")
                f.write("x86\n")
                f.close()

                parent_file = os.path.join(sub_profile_dir, "parent")
                f = open(parent_file, "w")
                f.write("..\n")
                f.close()

                if profile:
                    for config_file, lines in profile.items():
                        if config_file not in self.config_files:
                            raise ValueError("Unknown config file: '%s'" %
                                             config_file)

                        file_name = os.path.join(sub_profile_dir, config_file)
                        f = open(file_name, "w")
                        for line in lines:
                            f.write("%s\n" % line)
                        f.close()

                #Create profile symlink
                os.symlink(sub_profile_dir,
                           os.path.join(user_config_dir, "make.profile"))

                #Create minimal herds.xml
                herds_xml = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE herds SYSTEM "http://www.gentoo.org/dtd/herds.dtd">
<?xml-stylesheet href="/xsl/herds.xsl" type="text/xsl" ?>
<?xml-stylesheet href="/xsl/guide.xsl" type="text/xsl" ?>
<herds>
<herd>
  <name>base-system</name>
  <email>[email protected]</email>
  <description>Core system utilities and libraries.</description>
  <maintainer>
    <email>[email protected]</email>
    <name>Base System</name>
    <role>Base System Maintainer</role>
  </maintainer>
</herd>
</herds>
"""
                with open(os.path.join(metadata_dir, "metadata.xml"),
                          'w') as f:
                    f.write(herds_xml)

        # Write empty entries for each repository, in order to exercise
        # RepoConfigLoader's repos.conf processing.
        repos_conf_file = os.path.join(user_config_dir, "repos.conf")
        f = open(repos_conf_file, "w")
        for repo in sorted(self.repo_dirs.keys()):
            f.write("[%s]\n" % repo)
            f.write("\n")
        f.close()

        for config_file, lines in user_config.items():
            if config_file not in self.config_files:
                raise ValueError("Unknown config file: '%s'" % config_file)

            file_name = os.path.join(user_config_dir, config_file)
            f = open(file_name, "w")
            for line in lines:
                f.write("%s\n" % line)
            f.close()

        #Create /usr/share/portage/config/make.globals
        make_globals_path = os.path.join(self.eroot,
                                         GLOBAL_CONFIG_PATH.lstrip(os.sep),
                                         "make.globals")
        ensure_dirs(os.path.dirname(make_globals_path))
        os.symlink(os.path.join(PORTAGE_BASE_PATH, "cnf", "make.globals"),
                   make_globals_path)

        #Create /usr/share/portage/config/sets/portage.conf
        default_sets_conf_dir = os.path.join(self.eroot,
                                             "usr/share/portage/config/sets")

        try:
            os.makedirs(default_sets_conf_dir)
        except os.error:
            pass

        provided_sets_portage_conf = \
         os.path.join(PORTAGE_BASE_PATH, "cnf/sets/portage.conf")
        os.symlink(provided_sets_portage_conf,
                   os.path.join(default_sets_conf_dir, "portage.conf"))

        set_config_dir = os.path.join(user_config_dir, "sets")

        try:
            os.makedirs(set_config_dir)
        except os.error:
            pass

        for sets_file, lines in sets.items():
            file_name = os.path.join(set_config_dir, sets_file)
            f = open(file_name, "w")
            for line in lines:
                f.write("%s\n" % line)
            f.close()

        user_config_dir = os.path.join(self.eroot, "etc", "portage")

        try:
            os.makedirs(user_config_dir)
        except os.error:
            pass

        for config_file, lines in user_config.items():
            if config_file not in self.config_files:
                raise ValueError("Unknown config file: '%s'" % config_file)

            file_name = os.path.join(user_config_dir, config_file)
            f = open(file_name, "w")
            for line in lines:
                f.write("%s\n" % line)
            f.close()
コード例 #21
0
    def _create_profile(self, ebuilds, installed, profile, repo_configs,
                        user_config, sets):

        user_config_dir = os.path.join(self.eroot, USER_CONFIG_PATH)

        try:
            os.makedirs(user_config_dir)
        except os.error:
            pass

        for repo in self._repositories:
            if repo == "DEFAULT":
                continue

            repo_dir = self._get_repo_dir(repo)
            profile_dir = os.path.join(repo_dir, "profiles")
            metadata_dir = os.path.join(repo_dir, "metadata")
            os.makedirs(metadata_dir)

            #Create $REPO/profiles/categories
            categories = set()
            for cpv in ebuilds:
                ebuilds_repo = Atom("=" + cpv, allow_repo=True).repo
                if ebuilds_repo is None:
                    ebuilds_repo = "test_repo"
                if ebuilds_repo == repo:
                    categories.add(catsplit(cpv)[0])

            categories_file = os.path.join(profile_dir, "categories")
            with open(categories_file, "w") as f:
                for cat in categories:
                    f.write(cat + "\n")

            #Create $REPO/profiles/license_groups
            license_file = os.path.join(profile_dir, "license_groups")
            with open(license_file, "w") as f:
                f.write("EULA TEST\n")

            repo_config = repo_configs.get(repo)
            if repo_config:
                for config_file, lines in repo_config.items():
                    if config_file not in self.config_files and not any(
                            fnmatch.fnmatch(config_file, os.path.join(x, "*"))
                            for x in self.config_files):
                        raise ValueError("Unknown config file: '%s'" %
                                         config_file)

                    if config_file in ("layout.conf", ):
                        file_name = os.path.join(repo_dir, "metadata",
                                                 config_file)
                    else:
                        file_name = os.path.join(profile_dir, config_file)
                        if "/" in config_file and not os.path.isdir(
                                os.path.dirname(file_name)):
                            os.makedirs(os.path.dirname(file_name))
                    with open(file_name, "w") as f:
                        for line in lines:
                            f.write("%s\n" % line)
                        # Temporarily write empty value of masters until it becomes default.
                        # TODO: Delete all references to "# use implicit masters" when empty value becomes default.
                        if config_file == "layout.conf" and not any(
                                line.startswith(("masters =",
                                                 "# use implicit masters"))
                                for line in lines):
                            f.write("masters =\n")

            #Create $profile_dir/eclass (we fail to digest the ebuilds if it's not there)
            os.makedirs(os.path.join(repo_dir, "eclass"))

            # Temporarily write empty value of masters until it becomes default.
            if not repo_config or "layout.conf" not in repo_config:
                layout_conf_path = os.path.join(repo_dir, "metadata",
                                                "layout.conf")
                with open(layout_conf_path, "w") as f:
                    f.write("masters =\n")

            if repo == "test_repo":
                #Create a minimal profile in /usr/portage
                sub_profile_dir = os.path.join(profile_dir, "default", "linux",
                                               "x86", "test_profile")
                os.makedirs(sub_profile_dir)

                if not (profile and "eapi" in profile):
                    eapi_file = os.path.join(sub_profile_dir, "eapi")
                    with open(eapi_file, "w") as f:
                        f.write("0\n")

                make_defaults_file = os.path.join(sub_profile_dir,
                                                  "make.defaults")
                with open(make_defaults_file, "w") as f:
                    f.write("ARCH=\"x86\"\n")
                    f.write("ACCEPT_KEYWORDS=\"x86\"\n")

                use_force_file = os.path.join(sub_profile_dir, "use.force")
                with open(use_force_file, "w") as f:
                    f.write("x86\n")

                parent_file = os.path.join(sub_profile_dir, "parent")
                with open(parent_file, "w") as f:
                    f.write("..\n")

                if profile:
                    for config_file, lines in profile.items():
                        if config_file not in self.config_files:
                            raise ValueError("Unknown config file: '%s'" %
                                             config_file)

                        file_name = os.path.join(sub_profile_dir, config_file)
                        with open(file_name, "w") as f:
                            for line in lines:
                                f.write("%s\n" % line)

                #Create profile symlink
                os.symlink(sub_profile_dir,
                           os.path.join(user_config_dir, "make.profile"))

                #Create minimal herds.xml
                herds_xml = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE herds SYSTEM "http://www.gentoo.org/dtd/herds.dtd">
<?xml-stylesheet href="/xsl/herds.xsl" type="text/xsl" ?>
<?xml-stylesheet href="/xsl/guide.xsl" type="text/xsl" ?>
<herds>
<herd>
  <name>base-system</name>
  <email>[email protected]</email>
  <description>Core system utilities and libraries.</description>
  <maintainer>
    <email>[email protected]</email>
    <name>Base System</name>
    <role>Base System Maintainer</role>
  </maintainer>
</herd>
</herds>
"""
                with open(os.path.join(metadata_dir, "metadata.xml"),
                          'w') as f:
                    f.write(herds_xml)

        make_conf = {
            "ACCEPT_KEYWORDS": "x86",
            "CLEAN_DELAY": "0",
            "DISTDIR": self.distdir,
            "EMERGE_WARNING_DELAY": "0",
            "PKGDIR": self.pkgdir,
            "PORTAGE_INST_GID": str(portage.data.portage_gid),
            "PORTAGE_INST_UID": str(portage.data.portage_uid),
            "PORTAGE_TMPDIR": os.path.join(self.eroot, 'var/tmp'),
        }

        if os.environ.get("NOCOLOR"):
            make_conf["NOCOLOR"] = os.environ["NOCOLOR"]

        # Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
        # need to be inherited by ebuild subprocesses.
        if 'PORTAGE_USERNAME' in os.environ:
            make_conf['PORTAGE_USERNAME'] = os.environ['PORTAGE_USERNAME']
        if 'PORTAGE_GRPNAME' in os.environ:
            make_conf['PORTAGE_GRPNAME'] = os.environ['PORTAGE_GRPNAME']

        make_conf_lines = []
        for k_v in make_conf.items():
            make_conf_lines.append('%s="%s"' % k_v)

        if "make.conf" in user_config:
            make_conf_lines.extend(user_config["make.conf"])

        if not portage.process.sandbox_capable or \
         os.environ.get("SANDBOX_ON") == "1":
            # avoid problems from nested sandbox instances
            make_conf_lines.append(
                'FEATURES="${FEATURES} -sandbox -usersandbox"')

        configs = user_config.copy()
        configs["make.conf"] = make_conf_lines

        for config_file, lines in configs.items():
            if config_file not in self.config_files:
                raise ValueError("Unknown config file: '%s'" % config_file)

            file_name = os.path.join(user_config_dir, config_file)
            with open(file_name, "w") as f:
                for line in lines:
                    f.write("%s\n" % line)

        #Create /usr/share/portage/config/make.globals
        make_globals_path = os.path.join(self.eroot,
                                         GLOBAL_CONFIG_PATH.lstrip(os.sep),
                                         "make.globals")
        ensure_dirs(os.path.dirname(make_globals_path))
        os.symlink(os.path.join(cnf_path, "make.globals"), make_globals_path)

        #Create /usr/share/portage/config/sets/portage.conf
        default_sets_conf_dir = os.path.join(self.eroot,
                                             "usr/share/portage/config/sets")

        try:
            os.makedirs(default_sets_conf_dir)
        except os.error:
            pass

        provided_sets_portage_conf = (os.path.join(cnf_path, "sets",
                                                   "portage.conf"))
        os.symlink(provided_sets_portage_conf,
                   os.path.join(default_sets_conf_dir, "portage.conf"))

        set_config_dir = os.path.join(user_config_dir, "sets")

        try:
            os.makedirs(set_config_dir)
        except os.error:
            pass

        for sets_file, lines in sets.items():
            file_name = os.path.join(set_config_dir, sets_file)
            with open(file_name, "w") as f:
                for line in lines:
                    f.write("%s\n" % line)