blob: ee8fbcb063b9f27c23e0cacab141c6234472007b [file] [log] [blame]
Contains all the patches committed to portage_tool on top of 2.2.12:
* make.defaults: negative incrementals in USE_EXPAND (530222)
* fs_template._ensure_dirs: handle EEXIST (529120)
* flat_hash: Fix race condition in _setitem.
* Add separatedebug feature
* package.bashrc: per profile, per-package bashrc mechanism
* Add profile-formats to profile_complex
* Refactor bashrc scripts sourcing
* Set "url" before marking the index as up to date.
* If a binhost file sets a TTL header, honor it.
* Make SYSROOT a portage variable
* Do not interrupt on SIGCONT
* Readonly detection logic should handle ROOT
* Remove repo_name warning
* Remove repos.conf
* Add a new portageq helper to reduce a string containing use conditionals
* re-order install hooks execution
* suppress splitdebug for .o files
* Commit fast-build patch to portage_tool repository.
* support suppressing env-update
* support fixing *.la
diff --git a/Makefile b/Makefile
index 92ea195..babbda2 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ INSMODE = 0644
EXEMODE = 0755
DIRMODE = 0755
SYSCONFDIR_FILES = etc-update.conf dispatch-conf.conf
-PORTAGE_CONFDIR_FILES = make.conf.example make.globals repos.conf
+PORTAGE_CONFDIR_FILES = make.conf.example make.globals
LOGROTATE_FILES = elog-save-summary
BINDIR_FILES = ebuild egencache emerge emerge-webrsync \
emirrordist portageq quickpkg repoman
diff --git a/bin/ebuild-helpers/prepstrip b/bin/ebuild-helpers/prepstrip
index 2ef8a1a..f37ddae 100755
--- a/bin/ebuild-helpers/prepstrip
+++ b/bin/ebuild-helpers/prepstrip
@@ -350,7 +350,12 @@ do
elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then
process_elf "${x}" "${inode_link}" ${PORTAGE_STRIP_FLAGS}
elif [[ ${f} == *"SB relocatable"* ]] ; then
+ # Disable splitdebug for object files as breakpad fails atm w/them.
+ # http://crosbug.com/204974
+ FEATURES_splitdebug_save=${FEATURES_splitdebug}
+ [[ ${x} != *.ko ]] && FEATURES_splitdebug=false
process_elf "${x}" "${inode_link}" ${SAFE_STRIP_FLAGS}
+ FEATURES_splitdebug=${FEATURES_splitdebug_save}
fi
if ${was_not_writable} ; then
diff --git a/bin/ebuild.sh b/bin/ebuild.sh
index be044e0..50909e1 100755
--- a/bin/ebuild.sh
+++ b/bin/ebuild.sh
@@ -368,46 +368,71 @@ __source_all_bashrcs() {
# source the existing profile.bashrcs.
save_IFS
IFS=$'\n'
- local path_array=($PROFILE_PATHS)
+ local bashenv_files=($PORTAGE_BASHRC_FILES)
restore_IFS
- for x in "${path_array[@]}" ; do
- [ -f "$x/profile.bashrc" ] && __qa_source "$x/profile.bashrc"
+ for x in "${bashenv_files[@]}" ; do
+ __try_source "${x}"
done
fi
- if [ -r "${PORTAGE_BASHRC}" ] ; then
- if [ "$PORTAGE_DEBUG" != "1" ] || [ "${-/x/}" != "$-" ]; then
- source "${PORTAGE_BASHRC}"
- else
- set -x
- source "${PORTAGE_BASHRC}"
- set +x
- fi
- fi
+ # The user's bashrc is the ONLY non-portage bit of code
+ # that can change shopts without a QA violation.
+ __try_source --no-qa "${PORTAGE_BASHRC}"
if [[ $EBUILD_PHASE != depend ]] ; then
- # The user's bashrc is the ONLY non-portage bit of code that can
- # change shopts without a QA violation.
- for x in "${PM_EBUILD_HOOK_DIR}"/${CATEGORY}/{${PN},${PN}:${SLOT%/*},${P},${PF}}; do
- if [ -r "${x}" ]; then
- # If $- contains x, then tracing has already been enabled
- # elsewhere for some reason. We preserve it's state so as
- # not to interfere.
- if [ "$PORTAGE_DEBUG" != "1" ] || [ "${-/x/}" != "$-" ]; then
- source "${x}"
- else
- set -x
- source "${x}"
- set +x
- fi
- fi
- done
+ __source_env_files --no-qa "${PM_EBUILD_HOOK_DIR}"
fi
[ ! -z "${OCC}" ] && export CC="${OCC}"
[ ! -z "${OCXX}" ] && export CXX="${OCXX}"
}
+# @FUNCTION: __source_env_files
+# @USAGE: [--no-qa] <ENV_DIRECTORY>
+# @DESCRIPTION:
+# Source the files relevant to the current package from the given path.
+# If --no-qa is specified, use source instead of __qa_source to source the
+# files.
+__source_env_files() {
+ local argument=()
+ if [[ $1 == --no-qa ]]; then
+ argument=( --no-qa )
+ shift
+ fi
+ for x in "${1}"/${CATEGORY}/{${PN},${PN}:${SLOT%/*},${P},${PF}}; do
+ __try_source "${argument[@]}" "${x}"
+ done
+}
+
+# @FUNCTION: __try_source
+# @USAGE: [--no-qa] <FILE>
+# @DESCRIPTION:
+# If the path given as argument exists, source the file while preserving
+# $-.
+# If --no-qa is specified, source the file with source instead of __qa_source.
+__try_source() {
+ local qa=true
+ if [[ $1 == --no-qa ]]; then
+ qa=false
+ shift
+ fi
+ if [[ -r "$1" ]]; then
+ local debug_on=false
+ if [[ "$PORTAGE_DEBUG" == "1" ]] && [[ "${-/x/}" == "$-" ]]; then
+ debug_on=true
+ fi
+ $debug_on && set -x
+ # If $- contains x, then tracing has already been enabled
+ # elsewhere for some reason. We preserve it's state so as
+ # not to interfere.
+ if [[ ${qa} ]]; then
+ source "${1}"
+ else
+ __qa_source "${1}"
+ fi
+ $debug_on && set +x
+ fi
+}
# === === === === === === === === === === === === === === === === === ===
# === === === === === functions end, main part begins === === === === ===
# === === === === === === === === === === === === === === === === === ===
diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh
index 961738f..b0d8b18 100755
--- a/bin/misc-functions.sh
+++ b/bin/misc-functions.sh
@@ -1215,6 +1215,17 @@ __dyn_package() {
[ -z "${PORTAGE_BINPKG_TMPFILE}" ] && \
die "PORTAGE_BINPKG_TMPFILE is unset"
mkdir -p "${PORTAGE_BINPKG_TMPFILE%/*}" || die "mkdir failed"
+
+ if has separatedebug ${FEATURES} && [[ -d "${PROOT%/}${EPREFIX}/usr/lib/debug" ]]; then
+ [[ -z "${PORTAGE_DEBUGSYMBOLS_TMPFILE}" ]] && \
+ die "PORTAGE_DEBUGSYMBOLS_TMPFILE is unset"
+ mkdir -p "${PORTAGE_DEBUGSYMBOLS_TMPFILE%/*}" || die "mkdir failed"
+ tar $tar_options -cf - $PORTAGE_BINPKG_TAR_OPTS \
+ -C "${PROOT}" ".${EPREFIX}/usr/lib/debug/" | \
+ $PORTAGE_BZIP2_COMMAND -c > "$PORTAGE_DEBUGSYMBOLS_TMPFILE"
+ tar_options+=" --anchored --exclude=.${EPREFIX}/usr/lib/debug"
+ fi
+
tar $tar_options -cf - $PORTAGE_BINPKG_TAR_OPTS -C "${PROOT}" . | \
$PORTAGE_BZIP2_COMMAND -c > "$PORTAGE_BINPKG_TMPFILE"
assert "failed to pack binary package: '$PORTAGE_BINPKG_TMPFILE'"
diff --git a/bin/phase-functions.sh b/bin/phase-functions.sh
index f39a024..5dff3bb 100644
--- a/bin/phase-functions.sh
+++ b/bin/phase-functions.sh
@@ -31,7 +31,7 @@ PORTAGE_READONLY_VARS="D EBUILD EBUILD_PHASE EBUILD_PHASE_FUNC \
PORTAGE_TMPDIR PORTAGE_UPDATE_ENV PORTAGE_USERNAME \
PORTAGE_VERBOSE PORTAGE_WORKDIR_MODE PORTAGE_XATTR_EXCLUDE \
PORTDIR \
- PROFILE_PATHS REPLACING_VERSIONS REPLACED_BY_VERSION T WORKDIR \
+ REPLACING_VERSIONS REPLACED_BY_VERSION T WORKDIR \
__PORTAGE_HELPER __PORTAGE_TEST_HARDLINK_LOCKS"
PORTAGE_SAVED_READONLY_VARS="A CATEGORY P PF PN PR PV PVR"
diff --git a/bin/portageq b/bin/portageq
index 79818f6..332122f 100755
--- a/bin/portageq
+++ b/bin/portageq
@@ -1117,6 +1117,17 @@ def pquery(parser, opts, args):
return os.EX_OK
+def use_reduce(argv):
+ """<depend_string>
+ Reduce a dependency string possibly containing use conditionals.
+ """
+
+ if len(argv) != 1:
+ print("ERROR: wrong number of arguments")
+ return 2
+ from portage.dep import use_reduce as use_internal
+ print(' '.join(use_internal(argv[0], uselist=os.environ['USE'].split(' '))))
+
#-----------------------------------------------------------------------------
#
# DO NOT CHANGE CODE BEYOND THIS POINT - IT'S NOT NEEDED!
diff --git a/bin/save-ebuild-env.sh b/bin/save-ebuild-env.sh
index 98cff83..8b32bc4 100644
--- a/bin/save-ebuild-env.sh
+++ b/bin/save-ebuild-env.sh
@@ -75,6 +75,7 @@ __save_ebuild_env() {
__ebuild_main __ebuild_phase __ebuild_phase_with_hooks \
__ebuild_arg_to_phase __ebuild_phase_funcs default \
__unpack_tar __unset_colors \
+ __source_env_files __try_source \
${QA_INTERCEPTORS}
___eapi_has_usex && unset -f usex
@@ -96,7 +97,7 @@ __save_ebuild_env() {
GOOD HILITE HOME \
LAST_E_CMD LAST_E_LEN LD_PRELOAD MISC_FUNCTIONS_ARGS MOPREFIX \
NOCOLOR NORMAL PKGDIR PKGUSE PKG_LOGDIR PKG_TMPDIR \
- PORTAGE_BASHRCS_SOURCED PORTAGE_COMPRESS \
+ PORTAGE_BASHRC_FILES PORTAGE_BASHRCS_SOURCED PORTAGE_COMPRESS \
PORTAGE_COMPRESS_EXCLUDE_SUFFIXES \
PORTAGE_DOHTML_UNWARNED_SKIPPED_EXTENSIONS \
PORTAGE_DOHTML_UNWARNED_SKIPPED_FILES \
@@ -106,7 +107,7 @@ __save_ebuild_env() {
PORTAGE_SANDBOX_READ PORTAGE_SANDBOX_WRITE PREROOTPATH \
QA_INTERCEPTORS \
RC_DEFAULT_INDENT RC_DOT_PATTERN RC_ENDCOL RC_INDENTATION \
- ROOT ROOTPATH RPMDIR TEMP TMP TMPDIR USE_EXPAND \
+ ROOT ROOTPATH RPMDIR SYSROOT TEMP TMP TMPDIR USE_EXPAND \
WARN XARGS _RC_GET_KV_CACHE
# user config variables
diff --git a/man/make.conf.5 b/man/make.conf.5
index 84e894b..9050ee7 100644
--- a/man/make.conf.5
+++ b/man/make.conf.5
@@ -506,6 +506,11 @@ Output a verbose trace of python execution to stderr when a command's
.B sandbox
Enable sandbox\-ing when running \fBemerge\fR(1) and \fBebuild\fR(1).
.TP
+.B separatedebug
+When splitdebug is enabled, produces a separate tarball containing the debug
+symbols in \fBPKGDIR\fR.
+The debug symbols tarball has the name ${CATEGORY}/${PF}.debug.tbz2.
+.TP
.B sesandbox
Enable SELinux sandbox\-ing. Do not toggle this \fBFEATURE\fR yourself.
.TP
diff --git a/man/portage.5 b/man/portage.5
index e399f0f..309e259 100644
--- a/man/portage.5
+++ b/man/portage.5
@@ -24,6 +24,7 @@ make.defaults
packages
packages.build
package.accept_keywords
+package.bashrc
package.keywords
package.mask
package.provided
@@ -358,6 +359,31 @@ a '\-'.
A list of packages (one per line) that make up a stage1 tarball. Really only
useful for stage builders.
.TP
+.BR package.bashrc
+Per-package bashrc mechanism. Contains a list of bashrc files to be sourced
+before emerging a given atom. The bashrc files must be stored in bashrc/, in
+the profile directory.
+
+.I Note:
+.nf
+\- The bashrc files will be sourced after profile.bashrc for the same profile.
+\- profile-formats in metadata/layout.conf must contain profile-bashrcs for this
+to be enabled.
+.fi
+
+.I Format:
+.nf
+\- comments begin with # (no inline comments).
+\- one atom per line with space-delimited list of bashrc files.
+.fi
+
+.I Example:
+.nf
+# By setting INSTALL_MASK in bashrc/nostandardconf.conf, we can avoid installing
+# the standard configuration and enable another package to install it.
+net-misc/dhcp nostardardconf.conf
+.fi
+.TP
.BR package.provided
A list of packages (one per line) that portage should assume have been
provided. Useful for porting to non-Linux systems. Basically, it's a
@@ -1047,11 +1073,13 @@ The default setting for repoman's --echangelog option.
The cache formats supported in the metadata tree. There is the old "pms" format
and the newer/faster "md5-dict" format. Default is to detect dirs.
.TP
-.BR profile\-formats " = [pms|portage-1|portage-2]"
+.BR profile\-formats " = [pms|portage-1|portage-2|profile-bashrcs]"
Control functionality available to profiles in this repo such as which files
may be dirs, or the syntax available in parent files. Use "portage-2" if you're
unsure. The default is "portage-1-compat" mode which is meant to be compatible
with old profiles, but is not allowed to be opted into directly.
+Setting profile-bashrcs will enable the per-profile bashrc mechanism
+\fBpackage.bashrc\fR.
.RE
.RE
diff --git a/pym/_emerge/EbuildBinpkg.py b/pym/_emerge/EbuildBinpkg.py
index 34a6aef..902639c 100644
--- a/pym/_emerge/EbuildBinpkg.py
+++ b/pym/_emerge/EbuildBinpkg.py
@@ -3,14 +3,14 @@
from _emerge.CompositeTask import CompositeTask
from _emerge.EbuildPhase import EbuildPhase
-from portage import os
+from portage import os, xpak
class EbuildBinpkg(CompositeTask):
"""
This assumes that src_install() has successfully completed.
"""
__slots__ = ('pkg', 'settings') + \
- ('_binpkg_tmpfile',)
+ ('_binpkg_tmpfile', '_symbols_tmpfile')
def _start(self):
pkg = self.pkg
@@ -24,6 +24,12 @@ class EbuildBinpkg(CompositeTask):
self._binpkg_tmpfile = binpkg_tmpfile
self.settings["PORTAGE_BINPKG_TMPFILE"] = self._binpkg_tmpfile
+ if 'separatedebug' in self.settings.features:
+ self._symbols_tmpfile = os.path.join(bintree.pkgdir, pkg.cpv \
+ + '.debug.tbz2')
+ self.settings["PORTAGE_DEBUGSYMBOLS_TMPFILE"] = \
+ self._symbols_tmpfile
+
package_phase = EbuildPhase(background=self.background,
phase='package', scheduler=self.scheduler,
settings=self.settings)
@@ -33,15 +39,25 @@ class EbuildBinpkg(CompositeTask):
def _package_phase_exit(self, package_phase):
self.settings.pop("PORTAGE_BINPKG_TMPFILE", None)
+ self.settings.pop("PORTAGE_DEBUGSYMBOLS_TMPFILE", None)
if self._default_exit(package_phase) != os.EX_OK:
try:
os.unlink(self._binpkg_tmpfile)
except OSError:
pass
+ try:
+ os.unlink(self._symbols_tmpfile)
+ except OSError:
+ pass
self.wait()
return
pkg = self.pkg
+ if self._symbols_tmpfile and os.path.isfile(self._symbols_tmpfile):
+ xpak_data = xpak.xpak_mem({ "CATEGORY": pkg.category,
+ "PF": pkg.pf + "-debug",
+ "SLOT": pkg._metadata['SLOT'] })
+ xpak.tbz2(self._symbols_tmpfile).recompose_mem(xpak_data)
bintree = pkg.root_config.trees["bintree"]
bintree.inject(pkg.cpv, filename=self._binpkg_tmpfile)
diff --git a/pym/_emerge/Scheduler.py b/pym/_emerge/Scheduler.py
index d6db311..6e3bf1a 100644
--- a/pym/_emerge/Scheduler.py
+++ b/pym/_emerge/Scheduler.py
@@ -1017,6 +1017,7 @@ class Scheduler(PollScheduler):
earlier_sigterm_handler = signal.signal(signal.SIGTERM, sighandler)
earlier_sigcont_handler = \
signal.signal(signal.SIGCONT, self._sigcont_handler)
+ signal.siginterrupt(signal.SIGCONT, False)
try:
rval = self._merge()
diff --git a/pym/portage/cache/flat_hash.py b/pym/portage/cache/flat_hash.py
index 5304296..4735c86 100644
--- a/pym/portage/cache/flat_hash.py
+++ b/pym/portage/cache/flat_hash.py
@@ -10,6 +10,7 @@ import errno
import io
import stat
import sys
+import tempfile
import os as _os
from portage import os
from portage import _encodings
@@ -66,48 +67,39 @@ class database(fs_template.FsBased):
raise cache_errors.CacheCorruption(cpv, e)
def _setitem(self, cpv, values):
- s = cpv.rfind("/")
- fp = os.path.join(self.location,cpv[:s],".update.%i.%s" % (os.getpid(), cpv[s+1:]))
- try:
- myf = io.open(_unicode_encode(fp,
- encoding=_encodings['fs'], errors='strict'),
- mode='w', encoding=_encodings['repo.content'],
- errors='backslashreplace')
- except (IOError, OSError) as e:
- if errno.ENOENT == e.errno:
+ with tempfile.NamedTemporaryFile(delete=False, dir=self.location,
+ prefix=cpv.replace('/', '_')) as temp:
+ temp.close()
+ try:
+ with io.open(temp.name, mode='w',
+ encoding=_encodings['repo.content'],
+ errors='backslashreplace') as myf:
+ for k in self._write_keys:
+ v = values.get(k)
+ if not v:
+ continue
+ # NOTE: This format string requires unicode_literals, so that
+ # k and v are coerced to unicode, in order to prevent TypeError
+ # when writing raw bytes to TextIOWrapper with Python 2.
+ myf.write("%s=%s\n" % (k, v))
+
+ self._ensure_access(temp.name)
+
+ # Update written, we can move it.
+ new_fp = os.path.join(self.location, cpv)
try:
- self._ensure_dirs(cpv)
- myf = io.open(_unicode_encode(fp,
- encoding=_encodings['fs'], errors='strict'),
- mode='w', encoding=_encodings['repo.content'],
- errors='backslashreplace')
- except (OSError, IOError) as e:
- raise cache_errors.CacheCorruption(cpv, e)
- else:
+ os.rename(temp.name, new_fp)
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ self._ensure_dirs(cpv)
+ os.rename(temp.name, new_fp)
+ else:
+ raise cache_errors.CacheCorruption(cpv, e)
+
+ except EnvironmentError as e:
+ os.remove(temp.name)
raise cache_errors.CacheCorruption(cpv, e)
- try:
- for k in self._write_keys:
- v = values.get(k)
- if not v:
- continue
- # NOTE: This format string requires unicode_literals, so that
- # k and v are coerced to unicode, in order to prevent TypeError
- # when writing raw bytes to TextIOWrapper with Python 2.
- myf.write("%s=%s\n" % (k, v))
- finally:
- myf.close()
- self._ensure_access(fp)
-
- #update written. now we move it.
-
- new_fp = os.path.join(self.location,cpv)
- try:
- os.rename(fp, new_fp)
- except (OSError, IOError) as e:
- os.remove(fp)
- raise cache_errors.CacheCorruption(cpv, e)
-
def _delitem(self, cpv):
# import pdb;pdb.set_trace()
try:
diff --git a/pym/portage/cache/fs_template.py b/pym/portage/cache/fs_template.py
index de4fe4b..fa44abc 100644
--- a/pym/portage/cache/fs_template.py
+++ b/pym/portage/cache/fs_template.py
@@ -10,7 +10,7 @@ from portage import os
from portage.proxy.lazyimport import lazyimport
lazyimport(globals(),
'portage.exception:PortageException',
- 'portage.util:apply_permissions',
+ 'portage.util:apply_permissions,ensure_dirs',
)
del lazyimport
@@ -61,20 +61,15 @@ class FsBased(template.database):
for dir in path.lstrip(os.path.sep).rstrip(os.path.sep).split(os.path.sep):
base = os.path.join(base,dir)
- if not os.path.exists(base):
- if self._perms != -1:
- um = os.umask(0)
- try:
- perms = self._perms
- if perms == -1:
- perms = 0
- perms |= 0o755
- os.mkdir(base, perms)
- if self._gid != -1:
- os.chown(base, -1, self._gid)
- finally:
- if self._perms != -1:
- os.umask(um)
+ if ensure_dirs(base):
+ # We only call apply_permissions if ensure_dirs created
+ # a new directory, so as not to interfere with
+ # permissions of existing directories.
+ mode = self._perms
+ if mode == -1:
+ mode = 0
+ mode |= 0o755
+ apply_permissions(base, mode=mode, gid=self._gid)
def _prune_empty_dirs(self):
all_dirs = []
diff --git a/pym/portage/const.py b/pym/portage/const.py
index aab6e8a..fa7bd66 100644
--- a/pym/portage/const.py
+++ b/pym/portage/const.py
@@ -157,6 +157,7 @@ SUPPORTED_FEATURES = frozenset([
"multilib-strict",
"network-sandbox",
"news",
+ "no-env-update",
"noauto",
"noclean",
"nodoc",
@@ -172,6 +173,7 @@ SUPPORTED_FEATURES = frozenset([
"python-trace",
"sandbox",
"selinux",
+ "separatedebug",
"sesandbox",
"sfperms",
"sign",
diff --git a/pym/portage/dbapi/bintree.py b/pym/portage/dbapi/bintree.py
index 229ce3b..844d015 100644
--- a/pym/portage/dbapi/bintree.py
+++ b/pym/portage/dbapi/bintree.py
@@ -43,6 +43,7 @@ import subprocess
import sys
import tempfile
import textwrap
+import time
import traceback
import warnings
from gzip import GzipFile
@@ -879,6 +880,7 @@ class binarytree(object):
if e.errno != errno.ENOENT:
raise
local_timestamp = pkgindex.header.get("TIMESTAMP", None)
+ download_timestamp = float(pkgindex.header.get("DOWNLOAD_TIMESTAMP", 0))
remote_timestamp = None
rmt_idx = self._new_pkgindex()
proc = None
@@ -890,6 +892,10 @@ class binarytree(object):
url = base_url.rstrip("/") + "/Packages"
f = None
+ ttl = float(pkgindex.header.get("TTL", 0))
+ if download_timestamp and ttl and download_timestamp + ttl > time.time():
+ raise UseCachedCopyOfRemoteIndex()
+
# Don't use urlopen for https, since it doesn't support
# certificate/hostname verification (bug #469888).
if parsed_url.scheme not in ('https',):
@@ -1022,6 +1028,7 @@ class binarytree(object):
pass
if pkgindex is rmt_idx:
pkgindex.modified = False # don't update the header
+ pkgindex.header["DOWNLOAD_TIMESTAMP"] = str(long(time.time()))
try:
ensure_dirs(os.path.dirname(pkgindex_file))
f = atomic_ofstream(pkgindex_file)
diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py
index 5b947dd..7b49b70 100644
--- a/pym/portage/dbapi/vartree.py
+++ b/pym/portage/dbapi/vartree.py
@@ -70,6 +70,7 @@ from _emerge.MiscFunctionsProcess import MiscFunctionsProcess
from _emerge.SpawnProcess import SpawnProcess
import errno
+import fileinput
import fnmatch
import gc
import grp
@@ -214,7 +215,7 @@ class vardbapi(dbapi):
"""
if self._lock_count:
self._lock_count += 1
- else:
+ elif os.environ.get("PORTAGE_LOCKS") != "false":
if self._lock is not None:
raise AssertionError("already locked")
# At least the parent needs to exist for the lock file.
@@ -230,7 +231,7 @@ class vardbapi(dbapi):
"""
if self._lock_count > 1:
self._lock_count -= 1
- else:
+ elif os.environ.get("PORTAGE_LOCKS") != "false":
if self._lock is None:
raise AssertionError("not locked")
self._lock_count = 0
@@ -3663,17 +3664,15 @@ class dblink(object):
max_dblnk = dblnk
self._installed_instance = max_dblnk
- if self.settings.get("INSTALL_MASK") or \
- "nodoc" in self.settings.features or \
- "noinfo" in self.settings.features or \
- "noman" in self.settings.features:
- # Apply INSTALL_MASK before collision-protect, since it may
- # be useful to avoid collisions in some scenarios.
- phase = MiscFunctionsProcess(background=False,
- commands=["preinst_mask"], phase="preinst",
- scheduler=self._scheduler, settings=self.settings)
- phase.start()
- phase.wait()
+ # Apply INSTALL_MASK before collision-protect, since it may
+ # be useful to avoid collisions in some scenarios.
+ # We cannot detect if this is needed or not here as INSTALL_MASK can be
+ # modified by bashrc files.
+ phase = MiscFunctionsProcess(background=False,
+ commands=["preinst_mask"], phase="preinst",
+ scheduler=self._scheduler, settings=self.settings)
+ phase.start()
+ phase.wait()
# We check for unicode encoding issues after src_install. However,
# the check must be repeated here for binary packages (it's
@@ -3723,7 +3722,7 @@ class dblink(object):
break
relative_path = parent[srcroot_len:]
- dirlist.append(os.path.join("/", relative_path))
+ dirlist.append(os.path.join(destroot, relative_path))
for fname in files:
try:
@@ -4301,6 +4300,19 @@ class dblink(object):
contents=contents, env=self.settings,
writemsg_level=self._display_merge, vardbapi=self.vartree.dbapi)
+ # Fix *.la files to point to libs in target_root, if they
+ # don't do so already.
+ re_root = self.settings["ROOT"].strip("/")
+ if re_root:
+ fix_files = []
+ for path in contents:
+ if path.endswith(".la"):
+ if os.path.exists(path): fix_files.append(path)
+ if fix_files:
+ pat = re.compile(r"([' =](?:-[IL])?/)(usr|lib|opt)")
+ for line in fileinput.input(fix_files, inplace=1):
+ sys.stdout.write(pat.sub(r"\1%s/\2" % re_root, line))
+
# For gcc upgrades, preserved libs have to be removed after the
# the library path has been updated.
self._prune_plib_registry()
diff --git a/pym/portage/package/ebuild/_config/LocationsManager.py b/pym/portage/package/ebuild/_config/LocationsManager.py
index 4427f1d..8bf321c 100644
--- a/pym/portage/package/ebuild/_config/LocationsManager.py
+++ b/pym/portage/package/ebuild/_config/LocationsManager.py
@@ -31,7 +31,7 @@ _PORTAGE1_DIRECTORIES = frozenset([
'use.mask', 'use.force'])
_profile_node = collections.namedtuple('_profile_node',
- 'location portage1_directories user_config')
+ 'location portage1_directories user_config profile_formats')
_allow_parent_colon = frozenset(
["portage-2"])
@@ -132,7 +132,7 @@ class LocationsManager(object):
self.user_profile_dir = custom_prof
self.profiles.append(custom_prof)
self.profiles_complex.append(
- _profile_node(custom_prof, True, True))
+ _profile_node(custom_prof, True, True, ()))
del custom_prof
self.profiles = tuple(self.profiles)
@@ -151,6 +151,7 @@ class LocationsManager(object):
allow_parent_colon = True
repo_loc = None
compat_mode = False
+ current_formats = ()
eapi_file = os.path.join(currentPath, "eapi")
eapi = "0"
@@ -183,6 +184,8 @@ class LocationsManager(object):
layout_data['profile-formats'] == ('portage-1-compat',)
allow_parent_colon = any(x in _allow_parent_colon
for x in layout_data['profile-formats'])
+ current_formats = tuple(layout_data['profile-formats'])
+
if compat_mode:
offenders = _PORTAGE1_DIRECTORIES.intersection(os.listdir(currentPath))
@@ -233,7 +236,8 @@ class LocationsManager(object):
self.profiles.append(currentPath)
self.profiles_complex.append(
- _profile_node(currentPath, allow_directories, False))
+ _profile_node(currentPath, allow_directories, False,
+ current_formats))
def _expand_parent_colon(self, parentsFile, parentPath,
repo_loc, repositories):
diff --git a/pym/portage/package/ebuild/_config/special_env_vars.py b/pym/portage/package/ebuild/_config/special_env_vars.py
index 74fedd6..55754d9 100644
--- a/pym/portage/package/ebuild/_config/special_env_vars.py
+++ b/pym/portage/package/ebuild/_config/special_env_vars.py
@@ -49,10 +49,10 @@ environ_whitelist += [
"FEATURES", "FILESDIR", "HOME", "MERGE_TYPE", "NOCOLOR", "PATH",
"PKGDIR",
"PKGUSE", "PKG_LOGDIR", "PKG_TMPDIR",
- "PORTAGE_ACTUAL_DISTDIR", "PORTAGE_ARCHLIST",
+ "PORTAGE_ACTUAL_DISTDIR", "PORTAGE_ARCHLIST", "PORTAGE_BASHRC_FILES",
"PORTAGE_BASHRC", "PM_EBUILD_HOOK_DIR",
"PORTAGE_BINPKG_FILE", "PORTAGE_BINPKG_TAR_OPTS",
- "PORTAGE_BINPKG_TMPFILE",
+ "PORTAGE_BINPKG_TMPFILE", "PORTAGE_DEBUGSYMBOLS_TMPFILE",
"PORTAGE_BIN_PATH",
"PORTAGE_BUILDDIR", "PORTAGE_BUILD_GROUP", "PORTAGE_BUILD_USER",
"PORTAGE_BUNZIP2_COMMAND", "PORTAGE_BZIP2_COMMAND",
@@ -74,9 +74,9 @@ environ_whitelist += [
"PORTAGE_SIGPIPE_STATUS",
"PORTAGE_TMPDIR", "PORTAGE_UPDATE_ENV", "PORTAGE_USERNAME",
"PORTAGE_VERBOSE", "PORTAGE_WORKDIR_MODE", "PORTAGE_XATTR_EXCLUDE",
- "PORTDIR", "PORTDIR_OVERLAY", "PREROOTPATH", "PROFILE_PATHS",
+ "PORTDIR", "PORTDIR_OVERLAY", "PREROOTPATH",
"REPLACING_VERSIONS", "REPLACED_BY_VERSION",
- "ROOT", "ROOTPATH", "T", "TMP", "TMPDIR",
+ "ROOT", "ROOTPATH", "SYSROOT", "T", "TMP", "TMPDIR",
"USE_EXPAND", "USE_ORDER", "WORKDIR",
"XARGS", "__PORTAGE_TEST_HARDLINK_LOCKS",
]
diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py
index f639e14..67f95de 100644
--- a/pym/portage/package/ebuild/config.py
+++ b/pym/portage/package/ebuild/config.py
@@ -254,6 +254,7 @@ class config(object):
self._iuse_implicit_match = clone._iuse_implicit_match
self._non_user_variables = clone._non_user_variables
self._env_d_blacklist = clone._env_d_blacklist
+ self._pbashrc = clone._pbashrc
self._repo_make_defaults = clone._repo_make_defaults
self.usemask = clone.usemask
self.useforce = clone.useforce
@@ -316,6 +317,7 @@ class config(object):
self._accept_restrict = copy.deepcopy(clone._accept_restrict)
self._paccept_restrict = copy.deepcopy(clone._paccept_restrict)
self._penvdict = copy.deepcopy(clone._penvdict)
+ self._pbashrcdict = copy.deepcopy(clone._pbashrcdict)
self._expand_map = copy.deepcopy(clone._expand_map)
else:
@@ -661,6 +663,8 @@ class config(object):
self._ppropertiesdict = portage.dep.ExtendedAtomDict(dict)
self._paccept_restrict = portage.dep.ExtendedAtomDict(dict)
self._penvdict = portage.dep.ExtendedAtomDict(dict)
+ self._pbashrcdict = {}
+ self._pbashrc = ()
self._repo_make_defaults = {}
for repo in self.repositories.repos_with_profiles():
@@ -742,6 +746,25 @@ class config(object):
for k, v in penvdict.items():
self._penvdict.setdefault(k.cp, {})[k] = v
+ # package.bashrc
+ for profile in profiles_complex:
+ if not 'profile-bashrcs' in profile.profile_formats:
+ continue
+ self._pbashrcdict[profile] = \
+ portage.dep.ExtendedAtomDict(dict)
+ bashrc = grabdict_package(os.path.join(profile.location,
+ "package.bashrc"), recursive=1, allow_wildcard=True,
+ allow_repo=True, verify_eapi=False)
+ if not bashrc:
+ continue
+
+ for k, v in bashrc.items():
+ envfiles = [os.path.join(profile.location,
+ "bashrc",
+ envname) for envname in v]
+ self._pbashrcdict[profile].setdefault(k.cp, {})\
+ .setdefault(k, []).extend(envfiles)
+
#getting categories from an external file now
self.categories = [grabfile(os.path.join(x, "categories")) \
for x in locations_manager.profile_and_user_locations]
@@ -1501,6 +1524,23 @@ class config(object):
for x in penv_matches:
self._penv.extend(x)
+ bashrc_files = []
+
+ for profile in self._locations_manager.profiles_complex:
+ profile_bashrc = os.path.join(profile.location,
+ 'profile.bashrc')
+ if os.path.exists(profile_bashrc):
+ bashrc_files.append(profile_bashrc)
+ if profile in self._pbashrcdict:
+ cpdict = self._pbashrcdict[profile].get(cp)
+ if cpdict:
+ bashrc_matches = \
+ ordered_by_atom_specificity(cpdict, cpv_slot)
+ for x in bashrc_matches:
+ bashrc_files.extend(x)
+
+ self._pbashrc = tuple(bashrc_files)
+
protected_pkg_keys = set(pkg_configdict)
protected_pkg_keys.discard('USE')
@@ -2273,22 +2313,22 @@ class config(object):
if v is None:
continue
prefix = k.lower() + '_'
- if k in myincrementals:
- for x in v.split():
- if x[:1] == '-':
- expand_use.append('-' + prefix + x[1:])
- else:
- expand_use.append(prefix + x)
- else:
- for x in v.split():
+ for x in v.split():
+ if x[:1] == '-':
+ expand_use.append('-' + prefix + x[1:])
+ else:
expand_use.append(prefix + x)
+
if expand_use:
expand_use.append(use)
use = ' '.join(expand_use)
self.make_defaults_use.append(use)
self.make_defaults_use = tuple(self.make_defaults_use)
+ # Preserve both positive and negative flags here, since
+ # negative flags may later interact with other flags pulled
+ # in via USE_ORDER.
configdict_defaults['USE'] = ' '.join(
- stack_lists([x.split() for x in self.make_defaults_use]))
+ filter(None, self.make_defaults_use))
# Set to None so this code only runs once.
self._make_defaults = None
diff --git a/pym/portage/package/ebuild/doebuild.py b/pym/portage/package/ebuild/doebuild.py
index 01707ae..98e5903 100644
--- a/pym/portage/package/ebuild/doebuild.py
+++ b/pym/portage/package/ebuild/doebuild.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
__all__ = ['doebuild', 'doebuild_environment', 'spawn', 'spawnebuild']
+import fileinput
import grp
import gzip
import errno
@@ -335,7 +336,8 @@ def doebuild_environment(myebuild, mydo, myroot=None, settings=None,
mysettings["ECLASSDIR"] = mysettings["PORTDIR"]+"/eclass"
mysettings["SANDBOX_LOG"] = mycpv.replace("/", "_-_")
- mysettings["PROFILE_PATHS"] = "\n".join(mysettings.profiles)
+ mysettings["PORTAGE_BASHRC_FILES"] = "\n".join(mysettings._pbashrc)
+
mysettings["P"] = mysplit[0]+"-"+mysplit[1]
mysettings["PN"] = mysplit[0]
mysettings["PV"] = mysplit[1]
@@ -1628,9 +1630,10 @@ def spawnebuild(mydo, actionmap, mysettings, debug, alwaysdep=0,
_post_phase_cmds = {
"install" : [
+ "install_hooks",
"install_qa_check",
"install_symlink_html_docs",
- "install_hooks"],
+ ],
"preinst" : [
"preinst_sfperms",
@@ -1949,6 +1952,7 @@ def _post_src_install_uid_fix(mysettings, out):
destdir = mysettings["D"]
ed_len = len(mysettings["ED"])
unicode_errors = []
+ fix_files = []
desktop_file_validate = \
portage.process.find_binary("desktop-file-validate") is not None
xdg_dirs = mysettings.get('XDG_DATA_DIRS', '/usr/share').split(':')
@@ -2075,10 +2079,12 @@ def _post_src_install_uid_fix(mysettings, out):
new_contents, mode='wb')
mystat = os.lstat(fpath)
- if stat.S_ISREG(mystat.st_mode) and \
- mystat.st_ino not in counted_inodes:
- counted_inodes.add(mystat.st_ino)
- size += mystat.st_size
+ if stat.S_ISREG(mystat.st_mode):
+ if fname.endswith(".la"):
+ fix_files.append(fpath)
+ if mystat.st_ino not in counted_inodes:
+ counted_inodes.add(mystat.st_ino)
+ size += mystat.st_size
if mystat.st_uid != portage_uid and \
mystat.st_gid != portage_gid:
continue
@@ -2119,6 +2125,14 @@ def _post_src_install_uid_fix(mysettings, out):
f.write('%d\n' % size)
f.close()
+ re_root = mysettings["ROOT"].strip("/")
+ if fix_files and re_root:
+ # Replace references to our sysroot with references to "/" in binpkg.
+ # Sysroot will be re-appended when the package is installed.
+ pat = re.compile(r"([' =](-[IL])?/)%s/" % re.escape(re_root))
+ for line in fileinput.input(fix_files, inplace=1):
+ sys.stdout.write(pat.sub(r"\1", line))
+
_reapply_bsdflags_to_image(mysettings)
def _reapply_bsdflags_to_image(mysettings):
diff --git a/pym/portage/repository/config.py b/pym/portage/repository/config.py
index 5e0d055..a3144b1 100644
--- a/pym/portage/repository/config.py
+++ b/pym/portage/repository/config.py
@@ -40,7 +40,7 @@ if sys.hexversion >= 0x3000000:
_invalid_path_char_re = re.compile(r'[^a-zA-Z0-9._\-+:/]')
_valid_profile_formats = frozenset(
- ['pms', 'portage-1', 'portage-2'])
+ ['pms', 'portage-1', 'portage-2', 'profile-bashrcs'])
_portage1_profiles_allow_directories = frozenset(
["portage-1-compat", "portage-1", 'portage-2'])
@@ -233,6 +233,7 @@ class RepoConfig(object):
# useful when having two copies of the same repo enabled
# to avoid modifying profiles/repo_name in one of them
self.name = layout_data['repo-name']
+ self.missing_repo_name = False
for value in ('allow-missing-manifest',
'allow-provide-virtual', 'cache-formats',
diff --git a/pym/portage/tests/ebuild/test_use_expand_incremental.py b/pym/portage/tests/ebuild/test_use_expand_incremental.py
new file mode 100644
index 0000000..a58f08c
--- /dev/null
+++ b/pym/portage/tests/ebuild/test_use_expand_incremental.py
@@ -0,0 +1,132 @@
+# Copyright 2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+from __future__ import unicode_literals
+
+import io
+
+from portage import os, _encodings
+from portage.dep import Atom
+from portage.package.ebuild.config import config
+from portage.tests import TestCase
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground
+from portage.util import ensure_dirs
+
+class UseExpandIncrementalTestCase(TestCase):
+
+ def testUseExpandIncremental(self):
+
+ profiles = (
+ (
+ 'base',
+ {
+ "eapi": ("5",),
+ "parent": ("..",),
+ "make.defaults": (
+ "INPUT_DEVICES=\"keyboard mouse\"",
+ "PYTHON_TARGETS=\"python2_7 python3_3\"",
+ ("USE_EXPAND=\"INPUT_DEVICES PYTHON_TARGETS "
+ "VIDEO_CARDS\""),
+ )
+ }
+ ),
+ (
+ 'default/linux',
+ {
+ "eapi": ("5",),
+ "make.defaults": (
+ "VIDEO_CARDS=\"dummy fbdev v4l\"",
+ )
+ }
+ ),
+ (
+ 'default/linux/x86',
+ {
+ "eapi": ("5",),
+ "make.defaults": (
+ # Test negative incremental for bug 530222.
+ "PYTHON_TARGETS=\"-python3_3\"",
+ ),
+ "parent": ("../../../base",
+ "../../../mixins/python/3.4",
+ ".."
+ )
+ }
+ ),
+ (
+ 'mixins/python/3.4',
+ {
+ "eapi": ("5",),
+ "make.defaults": (
+ "PYTHON_TARGETS=\"python3_4\"",
+ )
+ }
+ ),
+ )
+
+ # USE_EXPAND variable settings in make.conf will cause
+ # profile settings for the same variable to be discarded
+ # (non-incremental behavior). PMS does not govern make.conf
+ # behavior.
+ user_config = {
+ "make.conf" : (
+ "VIDEO_CARDS=\"intel\"",
+ )
+ }
+
+ ebuilds = {
+ "x11-base/xorg-drivers-1.15": {
+ "EAPI": "5",
+ "IUSE": ("input_devices_keyboard input_devices_mouse "
+ "videos_cards_dummy video_cards_fbdev "
+ "video_cards_v4l video_cards_intel")
+ },
+ "sys-apps/portage-2.2.14": {
+ "EAPI": "5",
+ "IUSE": ("python_targets_python2_7 "
+ "python_targets_python3_3 python_targets_python3_4")
+ },
+ }
+
+ package_expected_use = (
+ ("x11-base/xorg-drivers-1.15", ("input_devices_keyboard",
+ "input_devices_mouse", "video_cards_intel",)),
+ ("sys-apps/portage-2.2.14", ("python_targets_python2_7",
+ "python_targets_python3_4"))
+ )
+
+ playground = ResolverPlayground(debug=False,
+ ebuilds=ebuilds, user_config=user_config)
+ try:
+ repo_dir = (playground.settings.repositories.
+ get_location_for_name("test_repo"))
+ profile_root = os.path.join(repo_dir, "profiles")
+
+ for p, data in profiles:
+ prof_path = os.path.join(profile_root, p)
+ ensure_dirs(prof_path)
+ for k, v in data.items():
+ with io.open(os.path.join(prof_path, k), mode="w",
+ encoding=_encodings["repo.content"]) as f:
+ for line in v:
+ f.write("%s\n" % line)
+
+ # The config must be reloaded in order to account
+ # for the above profile customizations.
+ playground.reload_config()
+
+ depgraph = playground.run(
+ ["=x11-base/xorg-drivers-1.15"]).depgraph
+ settings = config(clone=playground.settings)
+
+ for cpv, expected_use in package_expected_use:
+ pkg, existing_node = depgraph._select_package(
+ playground.eroot, Atom("=" + cpv))
+ settings.setcpv(pkg)
+ expected = frozenset(expected_use)
+ got = frozenset(settings["PORTAGE_USE"].split())
+ self.assertEqual(got, expected,
+ "%s != %s" % (got, expected))
+
+ finally:
+ playground.cleanup()
diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
index 077e271..6fcef5c 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -99,6 +99,16 @@ class ResolverPlayground(object):
portage.util.noiselimit = 0
+ def reload_config(self):
+ """
+ Reload configuration from disk, which is useful if it has
+ been modified after the constructor has been called.
+ """
+ for eroot in self.trees:
+ portdb = self.trees[eroot]["porttree"].dbapi
+ portdb.close_caches()
+ self.settings, self.trees = self._load_config()
+
def _get_repo_dir(self, repo):
"""
Create the repo directory if needed.
diff --git a/pym/portage/util/env_update.py b/pym/portage/util/env_update.py
index c0a93a8..f4cccc9 100644
--- a/pym/portage/util/env_update.py
+++ b/pym/portage/util/env_update.py
@@ -43,6 +43,14 @@ def env_update(makelinks=1, target_root=None, prev_mtimes=None, contents=None,
defaults to portage.settings["ROOT"].
@type target_root: String (Path)
"""
+ settings = getattr(portage, 'settings', None)
+ if settings is None:
+ settings = config(config_root=target_root,
+ target_root=target_root)
+
+ if 'no-env-update' in settings.features:
+ return
+
if vardbapi is None:
if isinstance(env, config):
vardbapi = vartree(settings=env).dbapi