diff options
author | Fabian Groffen <grobian@gentoo.org> | 2017-10-29 15:51:23 +0100 |
---|---|---|
committer | Fabian Groffen <grobian@gentoo.org> | 2017-10-29 15:51:23 +0100 |
commit | d598b947524aaba3bda162fc0d2cc97a9e0dcef6 (patch) | |
tree | 13de6e9697f196bb4a06e93dbad1be8ca45b167c | |
parent | Merge remote-tracking branch 'overlays-gentoo-org/master' into prefix (diff) | |
parent | Updates for portage-2.3.13 release (diff) | |
download | portage-d598b947.tar.gz portage-d598b947.tar.bz2 portage-d598b947.zip |
Merge remote-tracking branch 'overlays-gentoo-org/master' into prefix
27 files changed, 435 insertions, 188 deletions
diff --git a/.travis.yml b/.travis.yml index 2ae85b1d3..b77c92ee1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,8 @@ install: # python3.6+ has sha3 built-in, for older versions install pysha3 # (except for pypy where pysha3 is broken) - "[[ ${TRAVIS_PYTHON_VERSION} == 3.[6789] || ${TRAVIS_PYTHON_VERSION} == pypy ]] || pip install pysha3" + # python3.6+ has blake2 built-in, for older versions install pyblake2 + - "[[ ${TRAVIS_PYTHON_VERSION} == 3.[6789] ]] || pip install pyblake2" # always install pygost for Streebog - pip install pygost @@ -1,5 +1,12 @@ News (mainly features/major bug fixes) +portage-2.3.12 +---------------- +* better_cache implemented to use less expensive os.listdir() instead of + os.stat() operations to scan for ebuilds. Avoids exhaustively scanning + overlays for all ebuilds which allows Portage to not slow down significantly + with lots of overlays enabled. (Daniel Robbins) + portage-2.3.7 ----------------- * eapply_user combines patch basenames from all matched directories into a diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 81c54e550..e457919f3 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,6 +1,27 @@ Release Notes; upgrade information mainly. Features/major bugfixes are listed in NEWS +portage-2.3.13 +================================== +* Bug Fixes: + - Bug 497596 fix PORTAGE_RSYNC_RETRIES + - Bug 635116 is_prelinkable_elf: fix for python3 + - Bug 635126 file_copy: use sendfile return value to measure bytes copied + - Bug 635474 postinst_qa_check: initialize preinst state + + +portage-2.3.12 +================================== +* Bug Fixes: + - Bug 455232 fix ignored LDFLAGS check, enabled by adding + "-Wl,--defsym=__gentoo_check_ldflags__=0" to LDFLAGS + - Bug 630132 remove trailer when decompressing binary packages + - Bug 633842 PORTAGE_LOG_FILE KeyError + - Bug 634210 optimize portdbapi performance to handle large numbers of + repositories (Daniel Robbins) + - Bug 634378 use debugedit from rpm if necessary + + portage-2.3.11 ================================== * Bug Fixes: diff --git a/bin/ebuild-helpers/prepstrip b/bin/ebuild-helpers/prepstrip index 768620e3c..62daf817e 100755 --- a/bin/ebuild-helpers/prepstrip +++ b/bin/ebuild-helpers/prepstrip @@ -84,7 +84,19 @@ esac prepstrip_sources_dir=${EPREFIX}/usr/src/debug/${CATEGORY}/${PF} -type -P debugedit >/dev/null && debugedit_found=true || debugedit_found=false +debugedit=$(type -P debugedit) +if [[ -z ${debugedit} ]]; then + debugedit_paths=( + "${EPREFIX}/usr/libexec/rpm/debugedit" + ) + for x in "${debugedit_paths[@]}"; do + if [[ -x ${x} ]]; then + debugedit=${x} + break + fi + done +fi +[[ ${debugedit} ]] && debugedit_found=true || debugedit_found=false debugedit_warned=false __multijob_init @@ -101,8 +113,8 @@ save_elf_sources() { if ! ${debugedit_found} ; then if ! ${debugedit_warned} ; then debugedit_warned=true - ewarn "FEATURES=installsources is enabled but the debugedit binary could not" - ewarn "be found. This feature will not work unless debugedit is installed!" + ewarn "FEATURES=installsources is enabled but the debugedit binary could not be" + ewarn "found. This feature will not work unless debugedit or rpm is installed!" fi return 0 fi @@ -112,7 +124,7 @@ save_elf_sources() { # since we're editing the ELF here, we should recompute the build-id # (the -i flag below). save that output so we don't need to recompute # it later on in the save_elf_debug step. - buildid=$(debugedit -i \ + buildid=$("${debugedit}" -i \ -b "${WORKDIR}" \ -d "${prepstrip_sources_dir}" \ -l "${tmpdir}/sources/${x##*/}.${BASHPID:-$(__bashpid)}" \ diff --git a/bin/install-qa-check.d/10ignored-flags b/bin/install-qa-check.d/10ignored-flags index 7aa9eb695..28aec6787 100644 --- a/bin/install-qa-check.d/10ignored-flags +++ b/bin/install-qa-check.d/10ignored-flags @@ -64,9 +64,10 @@ ignored_flag_check() { fi # Check for files built without respecting LDFLAGS - if [[ "${LDFLAGS}" == *,--hash-style=gnu* ]] && \ + if [[ "${LDFLAGS}" == *,--defsym=__gentoo_check_ldflags__* ]] && \ ! has binchecks ${RESTRICT} ; then - f=$(scanelf -qyRF '#k%p' -k .hash "${ED}") + f=$(LC_ALL=C comm -3 <(scanelf -qyRF '#k%p' -k .dynsym "${ED}" | LC_ALL=C sort) \ + <(scanelf -qyRF '#s%p' -s __gentoo_check_ldflags__ "${ED}" | LC_ALL=C sort)) if [[ -n ${f} ]] ; then echo "${f}" > "${T}"/scanelf-ignored-LDFLAGS.log if [ "${QA_STRICT_FLAGS_IGNORED-unset}" = unset ] ; then diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh index 20fd4eef8..702f1ff4a 100755 --- a/bin/misc-functions.sh +++ b/bin/misc-functions.sh @@ -680,8 +680,12 @@ install_qa_check_xcoff() { fi } +preinst_qa_check() { + postinst_qa_check preinst +} + postinst_qa_check() { - local d f paths qa_checks=() + local d f paths qa_checks=() PORTAGE_QA_PHASE=${1:-postinst} if ! ___eapi_has_prefix_variables; then local EPREFIX= EROOT=${ROOT} fi @@ -691,23 +695,23 @@ postinst_qa_check() { # Collect the paths for QA checks, highest prio first. paths=( # sysadmin overrides - "${PORTAGE_OVERRIDE_EPREFIX}"/usr/local/lib/postinst-qa-check.d + "${PORTAGE_OVERRIDE_EPREFIX}"/usr/local/lib/${PORTAGE_QA_PHASE}-qa-check.d # system-wide package installs - "${PORTAGE_OVERRIDE_EPREFIX}"/usr/lib/postinst-qa-check.d + "${PORTAGE_OVERRIDE_EPREFIX}"/usr/lib/${PORTAGE_QA_PHASE}-qa-check.d ) # Now repo-specific checks. # (yes, PORTAGE_ECLASS_LOCATIONS contains repo paths...) for d in "${PORTAGE_ECLASS_LOCATIONS[@]}"; do paths+=( - "${d}"/metadata/postinst-qa-check.d + "${d}"/metadata/${PORTAGE_QA_PHASE}-qa-check.d ) done paths+=( # Portage built-in checks - "${PORTAGE_OVERRIDE_EPREFIX}"/usr/lib/portage/postinst-qa-check.d - "${PORTAGE_BIN_PATH}"/postinst-qa-check.d + "${PORTAGE_OVERRIDE_EPREFIX}"/usr/lib/portage/${PORTAGE_QA_PHASE}-qa-check.d + "${PORTAGE_BIN_PATH}"/${PORTAGE_QA_PHASE}-qa-check.d ) # Collect file names of QA checks. We need them early to support @@ -732,7 +736,7 @@ postinst_qa_check() { # Allow inheriting eclasses. # XXX: we want this only in repository-wide checks. _IN_INSTALL_QA_CHECK=1 - source "${d}/${f}" || eerror "Post-postinst QA check ${f} failed to run" + source "${d}/${f}" || eerror "Post-${PORTAGE_QA_PHASE} QA check ${f} failed to run" ) done < <(printf "%s\0" "${qa_checks[@]}" | LC_ALL=C sort -u -z) } diff --git a/bin/postinst-qa-check.d/50gnome2-utils b/bin/postinst-qa-check.d/50gnome2-utils index 7f1b0b847..dacc19a43 100644 --- a/bin/postinst-qa-check.d/50gnome2-utils +++ b/bin/postinst-qa-check.d/50gnome2-utils @@ -33,6 +33,12 @@ gnome2_icon_cache_check() { fi done + # preinst initializes the baseline state for the posinst check + [[ ${PORTAGE_QA_PHASE} == preinst ]] && return + + # parallel-install makes it impossible to blame a specific package + has parallel-install ${FEATURES} && return + # The eqatag call is prohibitively expensive if the cache is # missing and there are a large number of files. if [[ -z ${missing} && ${all_files[@]} ]]; then diff --git a/bin/postinst-qa-check.d/50xdg-utils b/bin/postinst-qa-check.d/50xdg-utils index d1285caf4..7094e75a1 100644 --- a/bin/postinst-qa-check.d/50xdg-utils +++ b/bin/postinst-qa-check.d/50xdg-utils @@ -29,6 +29,12 @@ xdg_desktop_database_check() { fi done + # preinst initializes the baseline state for the posinst check + [[ ${PORTAGE_QA_PHASE} == preinst ]] && return + + # parallel-install makes it impossible to blame a specific package + has parallel-install ${FEATURES} && return + # The eqatag call is prohibitively expensive if the cache is # missing and there are a large number of files. if [[ -z ${missing} && ${all_files[@]} ]]; then @@ -66,6 +72,12 @@ xdg_mimeinfo_database_check() { fi done + # preinst initializes the baseline state for the posinst check + [[ ${PORTAGE_QA_PHASE} == preinst ]] && return + + # parallel-install makes it impossible to blame a specific package + has parallel-install ${FEATURES} && return + # The eqatag call is prohibitively expensive if the cache is # missing and there are a large number of files. if [[ -z ${missing} && ${all_files[@]} ]]; then diff --git a/bin/preinst-qa-check.d/50gnome2-utils b/bin/preinst-qa-check.d/50gnome2-utils new file mode 120000 index 000000000..ee57f814d --- /dev/null +++ b/bin/preinst-qa-check.d/50gnome2-utils @@ -0,0 +1 @@ +../postinst-qa-check.d/50gnome2-utils
\ No newline at end of file diff --git a/bin/preinst-qa-check.d/50xdg-utils b/bin/preinst-qa-check.d/50xdg-utils new file mode 120000 index 000000000..16f68a471 --- /dev/null +++ b/bin/preinst-qa-check.d/50xdg-utils @@ -0,0 +1 @@ +../postinst-qa-check.d/50xdg-utils
\ No newline at end of file diff --git a/doc/config/bashrc.docbook b/doc/config/bashrc.docbook index f36fec5e6..8f6573432 100644 --- a/doc/config/bashrc.docbook +++ b/doc/config/bashrc.docbook @@ -27,4 +27,19 @@ will be called after src_compile. </para> </sect1> + <sect1 id='config-bashrc-ebuild-die-hooks'> + <title>Ebuild Die Hooks</title> + <para> + The register_die_hook function registers one or more names of functions + to call when the ebuild fails for any reason, including file collisions + with other packages. + </para> + </sect1> + <sect1 id='config-bashrc-ebuild-success-hooks'> + <title>Ebuild Success Hooks</title> + <para> + The register_success_hook function registers one or more names of + functions to call when the ebuild builds and/or installs successfully. + </para> + </sect1> </chapter> diff --git a/man/ebuild.5 b/man/ebuild.5 index f5ee79364..a88db1a2f 100644 --- a/man/ebuild.5 +++ b/man/ebuild.5 @@ -1,4 +1,4 @@ -.TH "EBUILD" "5" "Nov 2014" "Portage VERSION" "Portage" +.TH "EBUILD" "5" "Oct 2017" "Portage VERSION" "Portage" .SH "NAME" ebuild \- the internal format, variables, and functions in an ebuild script @@ -730,7 +730,7 @@ allows for packages to depend on \fIvirtual/jdk\fR rather than on blackdown or sun specifically. The \fBPROVIDE\fR variable has been deprecated. See -\fIhttps://wiki.gentoo.org/wiki/GLEP:37\fR for details. +\fIhttps://www.gentoo.org/glep/glep-0037.html\fR for details. .TP .B DOCS @@ -1110,16 +1110,6 @@ Example: installed) .fi -.SS "Hooks:" -.TP -.B register_die_hook\fR \fI[list of function names] -Register one or more functions to call when the ebuild fails for any reason, -including file collisions with other packages. -.TP -.B register_success_hook\fR \fI[list of function names] -Register one or more functions to call when the ebuild builds and/or installs -successfully. - .SS "Output:" .TP .B einfo\fR \fI"disposable message" @@ -1231,70 +1221,6 @@ Please do \fBnot\fR use this in place of 'emake install DESTDIR=${D}'. That is the preferred way of installing make\-based packages. Also, do not utilize the \fIEXTRA_EINSTALL\fR variable since it is for users. -.PD 0 -.TP -.B prepall -.TP -.B prepalldocs -.TP -.B prepallinfo -.TP -.B prepallman -.TP -.B prepallstrip -.PD 1 -Useful for when a package installs into \fB${D}\fR via scripts -(i.e. makefiles). If you want to be sure that libraries are executable, -aclocal files are installed into the right place, doc/info/man files are -all compressed, and that executables are all stripped of debugging symbols, -then use these suite of functions. -.RS -.PD 0 -.TP -.B prepall: -Runs \fBprepallman\fR, \fBprepallinfo\fR, \fBprepallstrip\fR, sets -libraries +x, and then checks aclocal directories. Please note this -does \fI*not*\fR run \fBprepalldocs\fR. -.TP -.B prepalldocs: -Compresses all doc files in ${ED}/usr/share/doc. -.TP -.B prepallinfo: -Compresses all info files in ${ED}/usr/share/info. -.TP -.B prepallman: -Compresses all man files in ${ED}/usr/share/man. -.TP -.B prepallstrip: -Strips all executable files of debugging symboles. This includes libraries. -.RE - -.TP -.B prepinfo\fR \fI[dir] -.TP -.B prepman\fR \fI[dir] -.TP -.B prepstrip\fR \fI[dir] -.PD 1 -Similar to the \fBprepall\fR functions, these are subtle in their differences. -.RS -.PD 0 -.TP -.B prepinfo: -If a \fIdir\fR is not specified, then \fBprepinfo\fR will assume the dir -\fIusr\fR. \fBprepinfo\fR will then compress all the files in -${ED}/\fIdir\fR/info. -.TP -.B prepman: -If a \fIdir\fR is not specified, then \fBprepman\fR will assume the dir -\fIusr\fR. \fBprepman\fR will then compress all the files in -${ED}/\fIdir\fR/man/*/. -.TP -.B prepstrip: -All the files found in ${ED}/\fIdir\fR will be stripped. You may specify -multiple directories. -.RE -.PD 1 .TP .B docompress\fR \fI[\-x] <path> [list of more paths] .RS diff --git a/man/emerge.1 b/man/emerge.1 index 84b033bac..1f333530b 100644 --- a/man/emerge.1 +++ b/man/emerge.1 @@ -108,7 +108,7 @@ later updating. .BR \-\-check\-news Scan all repositories for relevant unread GLEP 42 news items, and display how many are found. See -\fIhttps://wiki.gentoo.org/wiki/GLEP:42\fR. +\fIhttps://www.gentoo.org/glep/glep-0042.html\fR. .TP .BR \-\-clean Cleans up the system by examining the installed packages and removing older diff --git a/man/make.conf.5 b/man/make.conf.5 index 653e8bc12..b9051830f 100644 --- a/man/make.conf.5 +++ b/man/make.conf.5 @@ -62,7 +62,7 @@ with the '@' symbol. License groups are defined in the \fIlicense_groups\fR file (see \fBportage\fR(5)). In addition to license and group names, the \fI*\fR and \fI-*\fR wildcard tokens are also supported. Refer to GLEP 23 for further information: -\fIhttps://wiki.gentoo.org/wiki/GLEP:23\fR. +\fIhttps://www.gentoo.org/glep/glep-0023.html\fR. .br Defaults to the value of * -@EULA. .br @@ -506,7 +506,7 @@ configures new enough distcc to use the proxy. .TP .B news Enable GLEP 42 news support. See -\fIhttps://wiki.gentoo.org/wiki/GLEP:42\fR. +\fIhttps://www.gentoo.org/glep/glep-0042.html\fR. .TP .B noauto When utilizing \fBebuild\fR(1), only run the function requested. Also, forces diff --git a/man/portage.5 b/man/portage.5 index 5f1f2bbb0..89dc8ce44 100644 --- a/man/portage.5 +++ b/man/portage.5 @@ -1296,7 +1296,7 @@ version is followed by a hyphen and an integer build\-id. .RS .I Example: .nf -# Specify the repository name (overriding profils/repo_name). +# Specify the repository name (overriding profiles/repo_name). repo\-name = foo-overlay # eclasses provided by java-overlay take precedence over identically named @@ -1310,7 +1310,7 @@ aliases = foo-overlay eapis\-banned = 0 1 # indicate that ebuilds with the specified EAPIs are deprecated -eapis\-deprecated = 2 3 +eapis\-deprecated = 2 3 4 # sign commits in this repo, which requires Git >=1.7.9, and # key configured by `git config user.signingkey key_id` @@ -1330,11 +1330,11 @@ use\-manifests = strict manifest\-hashes = SHA256 SHA512 WHIRLPOOL # indicate that this repo enables repoman's --echangelog=y option automatically -update\-changelog = true +update\-changelog = false -# indicate that this repo contains both md5-dict and pms cache formats, +# indicate that this repo contains the md5-dict cache format, # which may be generated by egencache(1) -cache\-formats = md5-dict pms +cache\-formats = md5-dict # indicate that this repo contains profiles that may use directories for # package.mask, package.provided, package.use, package.use.force, @@ -1408,7 +1408,7 @@ A list of all the variables which will be displayed when you run `emerge info`. This contains groups of licenses that may be specifed in the \fBACCEPT_LICENSE\fR variable (see \fBmake.conf\fR(5)). Refer to GLEP 23 for further information: -\fIhttps://wiki.gentoo.org/wiki/GLEP:23\fR. +\fIhttps://www.gentoo.org/glep/glep-0023.html\fR. .I Format: .nf @@ -1542,7 +1542,7 @@ All local USE flags are listed here along with the package and a description. This file is automatically generated from the metadata.xml files that are included with each individual package. Refer to GLEP 56 for further information: -\fIhttps://wiki.gentoo.org/wiki/GLEP:56\fR. +\fIhttps://www.gentoo.org/glep/glep-0056.html\fR. .nf .I Format: diff --git a/pym/_emerge/BinpkgExtractorAsync.py b/pym/_emerge/BinpkgExtractorAsync.py index e85f4ecac..07ba2a1b7 100644 --- a/pym/_emerge/BinpkgExtractorAsync.py +++ b/pym/_emerge/BinpkgExtractorAsync.py @@ -74,21 +74,27 @@ class BinpkgExtractorAsync(SpawnProcess): self._async_wait() return - # Add -q to decomp_cmd opts, in order to avoid "trailing garbage - # after EOF ignored" warning messages due to xpak trailer. + pkg_xpak = portage.xpak.tbz2(self.pkg_path) + pkg_xpak.scan() + # SIGPIPE handling (128 + SIGPIPE) should be compatible with # assert_sigpipe_ok() that's used by the ebuild unpack() helper. self.args = [self._shell_binary, "-c", - ("%s -cq -- %s | tar -xp %s -C %s -f - ; " + \ - "p=(${PIPESTATUS[@]}) ; " + \ - "if [[ ${p[0]} != 0 && ${p[0]} != %d ]] ; then " % (128 + signal.SIGPIPE) + \ - "echo bzip2 failed with status ${p[0]} ; exit ${p[0]} ; fi ; " + \ - "if [ ${p[1]} != 0 ] ; then " + \ - "echo tar failed with status ${p[1]} ; exit ${p[1]} ; fi ; " + \ + ("cmd0=(head -c-%d -- %s) cmd1=(%s) cmd2=(tar -xp %s -C %s -f -); " + \ + '"${cmd0[@]}" | "${cmd1[@]}" | "${cmd2[@]}"; ' + \ + "p=(${PIPESTATUS[@]}) ; for i in {0..2}; do " + \ + "if [[ ${p[$i]} != 0 && ${p[$i]} != %d ]] ; then " + \ + "echo command $(eval \"echo \\\"'\\${cmd$i[*]}'\\\"\") " + \ + "failed with status ${p[$i]} ; exit ${p[$i]} ; fi ; done; " + \ + "if [ ${p[$i]} != 0 ] ; then " + \ + "echo command $(eval \"echo \\\"'\\${cmd$i[*]}'\\\"\") " + \ + "failed with status ${p[$i]} ; exit ${p[$i]} ; fi ; " + \ "exit 0 ;") % \ - (decomp_cmd, + (pkg_xpak.xpaksize, portage._shell_quote(self.pkg_path), + decomp_cmd, tar_options, - portage._shell_quote(self.image_dir))] + portage._shell_quote(self.image_dir), + 128 + signal.SIGPIPE)] SpawnProcess._start(self) diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py index 16cf70d45..c37423f0c 100644 --- a/pym/_emerge/depgraph.py +++ b/pym/_emerge/depgraph.py @@ -357,6 +357,47 @@ class _rebuild_config(object): class _dynamic_depgraph_config(object): + """ + ``dynamic_depgraph_config`` is an object that is used to collect settings and important data structures that are + used in calculating Portage dependencies. Each depgraph created by the depgraph.py code gets its own + ``dynamic_depgraph_config``, whereas ``frozen_depgraph_config`` is shared among all depgraphs. + + **self.digraph** + + Of particular importance is the instance variable ``self.digraph``, which is an instance of + ``portage.util.digraph``, a directed graph data structure. ``portage.util.digraph`` is used for a variety of + purposes in the Portage codebase, but in this particular scenario as ``self.digraph``, it is used to create a + dependency tree of Portage packages. So for ``self.digraph``, each *node* of the directed graph is a ``Package``, + while *edges* connect nodes and each edge can have a Priority. The Priority setting is used to help resolve + circular dependencies, and should be interpreted in the direction of parent to child. + + Conceptually, think of ``self.digraph`` as containing user-specified packages or sets at the very top, with + dependencies hanging down as children, and dependencies of those children as children of children, etc. The depgraph + is intended to model dependency relationships, not the order that packages should be installed. + + **resolving the digraph** + + To convert a digraph to an ordered list of packages to merge in an order where all dependencies are properly + satisfied, we would first start by looking at leaf nodes, which are nodes that have no dependencies of their own. We + could then traverse the digraph upwards from the leaf nodes, towards the parents. Along the way, depending on emerge + options, we could make decisions what packages should be installed or rebuilt. This is how ``self.digraph`` is used + in the code. + + **digraph creation** + + The ``depgraph.py`` code creates the digraph by first adding emerge arguments to the digraph as the main parents, + so if ``@world`` is specified, then the world set is added as the main parents. Then, ``emerge`` will determine + the dependencies of these packages, and depending on what options are passed to ``emerge``, will look at installed + packages, binary packages and available ebuilds that could be merged to satisfy dependencies, and these will be + added as children in the digraph. Children of children will be added as dependencies as needed, depending on the + depth setting used by ``emerge``. + + As the digraph is created, it is perfectly fine for Packages to be added to the digraph that conflict with one + another. After the digraph has been fully populated to the necessary depth, code within ``depgraph.py`` will + identify any conflicts that are modeled within the digraph and determine the best way to handle them. + + """ + def __init__(self, depgraph, myparams, allow_backtracking, backtrack_parameters): self.myparams = myparams.copy() self._vdb_loaded = False @@ -4998,7 +5039,7 @@ class depgraph(object): if atom.soname: repo_list = [None] elif atom.repo is None and hasattr(db, "getRepositories"): - repo_list = db.getRepositories() + repo_list = db.getRepositories(catpkg=atom.cp) else: repo_list = [atom.repo] @@ -5449,7 +5490,7 @@ class depgraph(object): atom_set = InternalPackageSet(initial_atoms=(atom,), allow_repo=True) if atom.repo is None and hasattr(db, "getRepositories"): - repo_list = db.getRepositories() + repo_list = db.getRepositories(catpkg=atom_exp.cp) else: repo_list = [atom.repo] diff --git a/pym/_emerge/resolver/package_tracker.py b/pym/_emerge/resolver/package_tracker.py index 398d4cf46..ccb0b11cf 100644 --- a/pym/_emerge/resolver/package_tracker.py +++ b/pym/_emerge/resolver/package_tracker.py @@ -31,38 +31,89 @@ class PackageConflict(_PackageConflict): class PackageTracker(object): """ - This class tracks packages which are currently - installed and packages which have been pulled into - the dependency graph. + **Behavior** - It automatically tracks conflicts between packages. + This section is intended to give you a good conceptual overview of the ``PackageTracker`` class and its general + behavior -- how you can expect it to behave and how in turn expects to be used successfully by the programmer. - Possible conflicts: - 1) Packages that share the same SLOT. - 2) Packages with the same cpv. - Not yet implemented: - 3) Packages that block each other. + This class is used to model the behavior of a real Gentoo or other system using Portage for package management, + along with the installed and to-be-installed packages. The installed packages are ones that are already on the + system and recorded in ``/var/db/pkg``, while the to-be-installed packages are a group of packages that Portage is + considering installing on the system, based on the information in Portage's dependency graph. Multiple roots are + supported, so that situations can be modeled where ROOT is set to a non-default value (non-``/``). + + You can use the add_pkg() method to add a to-be-merged package to the PackageTracker, and ``add_installed_pkg()`` to + add an already-installed package to the package tracker. Typical use of the package tracker involves the + ``depgraph.py`` code populating the package tracker with calls to ``add_installed_pkg()`` to add all installed + packages on the system, and then it is initialized and ready for use. At that point, ``depgraph.py`` can use + ``add_pkg()`` to add to-be-installed packages to the system. + + It's worth mentioning that ``PackageTracker`` uses ``Package`` objects as arguments, and stores these objects + internally. There are parts of the code that ensure that a ``Package`` instance is added to the PackageTracker + only once. + + Note that when a to-be-merged package is added to the package tracker via ``add_pkg()``, it will "cover up" + (replace) any installed package that shares the same root-catpkg-slot or root-catpkg-version, meaning that calling + the ``all_pkgs()`` or ``match()`` method will not return the installed package in the list. And the code does + support the scenario where ``add_installed_pkg(pkg2)`` is called *after* a call to ``add_pkg(pkg1)`` -- in this + case, if ``pkg1`` would 'cover up' ``pkg2``, this will be identified and handled correctly. + + But the package tracker is designed to have an important behavior in this regard -- because PackageTracker has a + ``remove()`` method, these replaced/covered-up packages are not permanently removed -- so if you ``remove()`` a + to-be-installed package that was "replacing" an installed package, the installed package will "reappear". This + removal functionality is used by the slot conflict code in ``depgraph.py`` to modify the list of to-be-installed + packages as it addresses slot conflicts. + + One of the main purposes of the PackageTracker is to detect conflicts between packages. Conflicts are detected + on to-be-installed packages only. + + A slot conflict is a situation where a to-be-installed package is added to the package tracker via ``add_pkg()``, + and there is already a to-be-installed package added that has the same root, catpkg and slot. These cannot co-exist. + + A cpv conflict is a situation where a to-be-installed package is added to the package tracker via ``add_pkg()``, and + there is already a to-be-installed package add that has the same root, catpkg, and version+revision. These cannot + co-exist. + + The package tracker does not prevent slot and cpv conflicts from occurring. Instead, it allows them to be recorded + and the ``conflicts()`` and ``slot_conflicts()`` method will cause the package tracker to look at its internal data + structures and generate ``PackageConflict()`` objects for each conflict it finds. + + The ``match()`` method is used extensively by ``depgraph.py`` to find packages that match a particular dependency + atom. The code now also supports soname dependencies. + + **Future Functionality** + + The package tracker may be extended in the future to track additional useful information: + + * Packages that block one another. This information is not currently injected into the package tracker. + + * Sub-slot conflicts. It is possible to identify situations where a to-be-installed package is in a new sub-slot. + In this case, the depgraph can be queried for parents of this dependency, and these parents can be scheduled + to be rebuilt. + + :ivar _cp_pkg_map: The collection of to-be-installed (not yet merged) packages. We care about conflicts in these + packages. + :ivar _cp_vdb_pkg_map: The collection of already-installed packages. + :ivar _multi_pkgs: A list of keys in ``self._cp_pkg_map`` that have potential slot and cpv conflicts. + :ivar _replacing: The mechanism by which ``PackageTracker`` records to-be-installed packages that 'cover up' + already-installed packages. ``self._replacing[cp_key] = [ new_pkg_that_replaced_cp_key... ]``. + :ivar _replaced_by: ``self.replaced_by[cp_key] == [ replaced_pkg_1, replaced_pkg_2 ]`` """ def __init__(self, soname_deps=False): + """ - @param soname_deps: enable soname match support - @type soname_deps: bool + :param soname_deps bool: Determines whether support for soname deps should be enabled or not. """ - # Mapping from package keys to set of packages. + self._cp_pkg_map = collections.defaultdict(list) self._cp_vdb_pkg_map = collections.defaultdict(list) - # List of package keys that may contain conflicts. - # The insetation order must be preserved. self._multi_pkgs = [] # Cache for result of conflicts(). self._conflicts_cache = None - # Records for each pulled package which installed package - # are replaced. self._replacing = collections.defaultdict(list) - # Records which pulled packages replace this package. self._replaced_by = collections.defaultdict(list) self._match_cache = collections.defaultdict(dict) @@ -258,7 +309,7 @@ class PackageTracker(object): Iterates over present slot conflicts. This is only intended for consumers that haven't been updated to deal with other kinds of conflicts. - This funcion should be removed once all consumers are updated. + This function should be removed once all consumers are updated. """ return (conflict for conflict in self.conflicts() \ if conflict.description == "slot conflict") diff --git a/pym/portage/checksum.py b/pym/portage/checksum.py index ff132751b..5424ce56b 100644 --- a/pym/portage/checksum.py +++ b/pym/portage/checksum.py @@ -27,8 +27,8 @@ import tempfile # SHA512: hashlib # RMD160: hashlib, pycrypto, mhash # WHIRLPOOL: hashlib, mhash, bundled -# BLAKE2B (512): hashlib (3.6+), pycrypto -# BLAKE2S (512): hashlib (3.6+), pycrypto +# BLAKE2B (512): hashlib (3.6+), pyblake2, pycrypto +# BLAKE2S (512): hashlib (3.6+), pyblake2, pycrypto # SHA3_256: hashlib (3.6+), pysha3, pycrypto # SHA3_512: hashlib (3.6+), pysha3, pycrypto @@ -124,6 +124,17 @@ for local_name, hash_name in ( origin='hashlib') +# Support using pyblake2 as fallback for python<3.6 +if "BLAKE2B" not in hashfunc_map or "BLAKE2S" not in hashfunc_map: + try: + import pyblake2 + + _generate_hash_function("BLAKE2B", pyblake2.blake2b, origin="pyblake2") + _generate_hash_function("BLAKE2S", pyblake2.blake2s, origin="pyblake2") + except ImportError: + pass + + # Support using pysha3 as fallback for python<3.6 if "SHA3_256" not in hashfunc_map or "SHA3_512" not in hashfunc_map: try: @@ -304,7 +315,7 @@ def is_prelinkable_elf(filename): finally: f.close() return (len(magic) == 17 and magic.startswith(b'\x7fELF') and - magic[16] in (b'\x02', b'\x03')) # 2=ET_EXEC, 3=ET_DYN + magic[16:17] in (b'\x02', b'\x03')) # 2=ET_EXEC, 3=ET_DYN def perform_md5(x, calc_prelink=0): return perform_checksum(x, "MD5", calc_prelink)[0] diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py index a3254d017..f5979d2d0 100644 --- a/pym/portage/dbapi/porttree.py +++ b/pym/portage/dbapi/porttree.py @@ -16,7 +16,7 @@ portage.proxy.lazyimport.lazyimport(globals(), 'portage.package.ebuild.doebuild:doebuild', 'portage.util:ensure_dirs,shlex_split,writemsg,writemsg_level', 'portage.util.listdir:listdir', - 'portage.versions:best,catpkgsplit,_pkgsplit@pkgsplit,ver_regexp,_pkg_str', + 'portage.versions:best,catsplit,catpkgsplit,_pkgsplit@pkgsplit,ver_regexp,_pkg_str', ) from portage.cache import volatile @@ -43,6 +43,8 @@ import os as _os import sys import traceback import warnings +import errno +import collections try: from urllib.parse import urlparse @@ -101,6 +103,68 @@ class _dummy_list(list): except ValueError: pass + +class _better_cache(object): + + """ + The purpose of better_cache is to locate catpkgs in repositories using ``os.listdir()`` as much as possible, which + is less expensive IO-wise than exhaustively doing a stat on each repo for a particular catpkg. better_cache stores a + list of repos in which particular catpkgs appear. Various dbapi methods use better_cache to locate repositories of + interest related to particular catpkg rather than performing an exhaustive scan of all repos/overlays. + + Better_cache.items data may look like this:: + + { "sys-apps/portage" : [ repo1, repo2 ] } + + Without better_cache, Portage will get slower and slower (due to excessive IO) as more overlays are added. + + Also note that it is OK if this cache has some 'false positive' catpkgs in it. We use it to search for specific + catpkgs listed in ebuilds. The likelihood of a false positive catpkg in our cache causing a problem is extremely + low, because the user of our cache is passing us a catpkg that came from somewhere and has already undergone some + validation, and even then will further interrogate the short-list of repos we return to gather more information + on the catpkg. + + Thus, the code below is optimized for speed rather than painstaking correctness. I have added a note to + ``dbapi.getRepositories()`` to ensure that developers are aware of this just in case. + + The better_cache has been redesigned to perform on-demand scans -- it will only scan a category at a time, as + needed. This should further optimize IO performance by not scanning category directories that are not needed by + Portage. + """ + + def __init__(self, repositories): + self._items = collections.defaultdict(list) + self._scanned_cats = set() + + # ordered list of all portree locations we'll scan: + self._repo_list = [repo for repo in reversed(list(repositories)) + if repo.location is not None] + + def __getitem__(self, catpkg): + result = self._items.get(catpkg) + if result is not None: + return result + + cat, pkg = catsplit(catpkg) + if cat not in self._scanned_cats: + self._scan_cat(cat) + return self._items[catpkg] + + def _scan_cat(self, cat): + for repo in self._repo_list: + cat_dir = repo.location + "/" + cat + try: + pkg_list = os.listdir(cat_dir) + except OSError as e: + if e.errno not in (errno.ENOTDIR, errno.ENOENT, errno.ESTALE): + raise + continue + for p in pkg_list: + if os.path.isdir(cat_dir + "/" + p): + self._items[cat + "/" + p].append(repo) + self._scanned_cats.add(cat) + + class portdbapi(dbapi): """this tree will scan a portage directory located at root (passed to init)""" portdbapi_instances = _dummy_list() @@ -253,6 +317,7 @@ class portdbapi(dbapi): "RESTRICT", "SLOT", "DEFINED_PHASES", "REQUIRED_USE"]) self._aux_cache = {} + self._better_cache = None self._broken_ebuilds = set() @property @@ -342,12 +407,25 @@ class portdbapi(dbapi): except KeyError: return None - def getRepositories(self): + def getRepositories(self, catpkg=None): + """ - This function is required for GLEP 42 compliance; it will return a list of - repository IDs - TreeMap = {id: path} + With catpkg=None, this will return a complete list of repositories in this dbapi. With catpkg set to a value, + this method will return a short-list of repositories that contain this catpkg. Use this second approach if + possible, to avoid exhaustively searching all repos for a particular catpkg. It's faster for this method to + find the catpkg than for you do it yourself. When specifying catpkg, you should have reasonable assurance that + the category is valid and PMS-compliant as the caching mechanism we use does not perform validation checks for + categories. + + This function is required for GLEP 42 compliance. + + @param catpkg: catpkg for which we want a list of repositories; we'll get a list of all repos containing this + catpkg; if None, return a list of all Repositories that contain a particular catpkg. + @return: a list of repositories. """ + + if catpkg is not None and self._better_cache is not None: + return [repo.name for repo in self._better_cache[catpkg]] return self._ordered_repo_name_list def getMissingRepoNames(self): @@ -363,7 +441,7 @@ class portdbapi(dbapi): """ return self.settings.repositories.ignored_repos - def findname2(self, mycpv, mytree=None, myrepo = None): + def findname2(self, mycpv, mytree=None, myrepo=None): """ Returns the location of the CPV, and what overlay it was in. Searches overlays first, then PORTDIR; this allows us to return the first @@ -385,16 +463,33 @@ class portdbapi(dbapi): if psplit is None or len(mysplit) != 2: raise InvalidPackageName(mycpv) + try: + cp = mycpv.cp + except AttributeError: + cp = mysplit[0] + "/" + psplit[0] + + if self._better_cache is None: + if mytree: + mytrees = [mytree] + else: + mytrees = reversed(self.porttrees) + else: + try: + repos = self._better_cache[cp] + except KeyError: + return (None, 0) + + mytrees = [] + for repo in repos: + if mytree is not None and mytree != repo.location: + continue + mytrees.append(repo.location) + # For optimal performace in this hot spot, we do manual unicode # handling here instead of using the wrapped os module. encoding = _encodings['fs'] errors = 'strict' - if mytree: - mytrees = [mytree] - else: - mytrees = reversed(self.porttrees) - relative_path = mysplit[0] + _os.sep + psplit[0] + _os.sep + \ mysplit[1] + ".ebuild" @@ -764,8 +859,10 @@ class portdbapi(dbapi): else: # assume it's iterable mytrees = mytree - else: + elif self._better_cache is None: mytrees = self.porttrees + else: + mytrees = [repo.location for repo in self._better_cache[mycp]] for oroot in mytrees: try: file_list = os.listdir(os.path.join(oroot, mycp)) @@ -814,10 +911,12 @@ class portdbapi(dbapi): "minimum-all-ignore-profile", "minimum-visible"): self.xcache[x]={} self.frozen=1 + self._better_cache = _better_cache(self.repositories) def melt(self): self.xcache = {} self._aux_cache = {} + self._better_cache = None self.frozen = 0 def xmatch(self,level,origdep,mydep=None,mykey=None,mylist=None): diff --git a/pym/portage/elog/mod_echo.py b/pym/portage/elog/mod_echo.py index bb34a1e44..fb86547a4 100644 --- a/pym/portage/elog/mod_echo.py +++ b/pym/portage/elog/mod_echo.py @@ -19,7 +19,9 @@ def process(mysettings, key, logentries, fulltext): logfile = None # output logfile explicitly only if it isn't in tempdir, otherwise # it will be removed anyway - if "PORT_LOGDIR" in mysettings: + if (key == mysettings.mycpv and + "PORT_LOGDIR" in mysettings and + "PORTAGE_LOG_FILE" in mysettings): logfile = mysettings["PORTAGE_LOG_FILE"] _items.append((mysettings["ROOT"], key, logentries, logfile)) diff --git a/pym/portage/package/ebuild/doebuild.py b/pym/portage/package/ebuild/doebuild.py index a5adf2c92..4505dafeb 100644 --- a/pym/portage/package/ebuild/doebuild.py +++ b/pym/portage/package/ebuild/doebuild.py @@ -1814,6 +1814,7 @@ _post_phase_cmds = { "preinst_sfperms", "preinst_selinux_labels", "preinst_suid_scan", + "preinst_qa_check", ], "postinst" : [ diff --git a/pym/portage/sync/modules/rsync/rsync.py b/pym/portage/sync/modules/rsync/rsync.py index 45a70e7dd..01e4e5924 100644 --- a/pym/portage/sync/modules/rsync/rsync.py +++ b/pym/portage/sync/modules/rsync/rsync.py @@ -202,6 +202,7 @@ class RsyncSync(NewBase): # reverse, for use with pop() uris.reverse() + uris_orig = uris[:] effective_maxretries = maxretries if effective_maxretries < 0: @@ -210,10 +211,13 @@ class RsyncSync(NewBase): while (1): if uris: dosyncuri = uris.pop() - else: + elif maxretries < 0 or retries > maxretries: writemsg("!!! Exhausted addresses for %s\n" % _unicode_decode(hostname), noiselevel=-1) return (1, False) + else: + uris.extend(uris_orig) + dosyncuri = uris.pop() if (retries==0): if "--ask" in opts: diff --git a/repoman/RELEASE-NOTES b/repoman/RELEASE-NOTES index 07fd62353..ad347cf11 100644 --- a/repoman/RELEASE-NOTES +++ b/repoman/RELEASE-NOTES @@ -1,6 +1,11 @@ Release Notes; upgrade information mainly. Features/major bugfixes are listed in NEWS +repoman-2.3.4 +================================== +* Support two new options: --bug (-b) and --closes (-c) + + repoman-2.3.3 ================================== * Bug Fixes: diff --git a/repoman/setup.py b/repoman/setup.py index 4a1283ec5..9c4def929 100755 --- a/repoman/setup.py +++ b/repoman/setup.py @@ -447,7 +447,7 @@ def get_manpages(): setup( name = 'repoman', - version = '2.3.3', + version = '2.3.4', url = 'https://wiki.gentoo.org/wiki/Project:Portage', author = 'Gentoo Portage Development Team', author_email = 'dev-portage@gentoo.org', @@ -659,7 +659,7 @@ class build_ext(_build_ext): setup( name = 'portage', - version = '2.3.11', + version = '2.3.13', url = 'https://wiki.gentoo.org/wiki/Project:Portage', author = 'Gentoo Portage Development Team', author_email = 'dev-portage@gentoo.org', diff --git a/src/portage_util_file_copy_reflink_linux.c b/src/portage_util_file_copy_reflink_linux.c index 4be9e0568..c3ce26b2b 100644 --- a/src/portage_util_file_copy_reflink_linux.c +++ b/src/portage_util_file_copy_reflink_linux.c @@ -56,12 +56,18 @@ initreflink_linux(void) /** * cfr_wrapper - A copy_file_range syscall wrapper function, having a - * function signature that is compatible with sendfile. + * function signature that is compatible with sf_wrapper. * @fd_out: output file descriptor * @fd_in: input file descriptor - * @off_out: offset of the output file + * @off_out: must point to a buffer that specifies the starting offset + * where bytes will be copied to fd_out, and this buffer is adjusted by + * the number of bytes copied. * @len: number of bytes to copy between the file descriptors * + * Bytes are copied from fd_in starting from *off_out, and the file + * offset of fd_in is not changed. Effects on the file offset of + * fd_out are undefined. + * * Return: Number of bytes written to out_fd on success, -1 on failure * (errno is set appropriately). */ @@ -69,7 +75,8 @@ static ssize_t cfr_wrapper(int fd_out, int fd_in, off_t *off_out, size_t len) { #ifdef __NR_copy_file_range - return syscall(__NR_copy_file_range, fd_in, NULL, fd_out, + off_t off_in = *off_out; + return syscall(__NR_copy_file_range, fd_in, &off_in, fd_out, off_out, len, 0); #else /* This is how it fails at runtime when the syscall is not supported. */ @@ -79,18 +86,50 @@ cfr_wrapper(int fd_out, int fd_in, off_t *off_out, size_t len) } /** + * sf_wrapper - A sendfile wrapper function, having a function signature + * that is compatible with cfr_wrapper. + * @fd_out: output file descriptor + * @fd_in: input file descriptor + * @off_out: must point to a buffer that specifies the starting offset + * where bytes will be copied to fd_out, and this buffer is adjusted by + * the number of bytes copied. + * @len: number of bytes to copy between the file descriptors + * + * Bytes are copied from fd_in starting from *off_out, and the file + * offset of fd_in is not changed. Effects on the file offset of + * fd_out are undefined. + * + * Return: Number of bytes written to out_fd on success, -1 on failure + * (errno is set appropriately). + */ +static ssize_t +sf_wrapper(int fd_out, int fd_in, off_t *off_out, size_t len) +{ + ssize_t ret; + off_t off_in = *off_out; + /* The sendfile docs do not specify behavior of the output file + * offset, therefore it must be adjusted with lseek. + */ + if (lseek(fd_out, *off_out, SEEK_SET) < 0) + return -1; + ret = sendfile(fd_out, fd_in, &off_in, len); + if (ret > 0) + *off_out += ret; + return ret; +} + + +/** * do_lseek_data - Adjust file offsets to the next location containing * data, creating sparse empty blocks in the output file as needed. * @fd_in: input file descriptor * @fd_out: output file descriptor * @off_out: offset of the output file * - * Use lseek SEEK_DATA to adjust the fd_in file offset to the next - * location containing data, and adjust the fd_in file offset and - * off_out to the same location (creating sparse empty blocks as - * needed). On success, both fd_in and fd_out file offsets are - * guaranteed to be exactly equal to the value that off_out points to. - * + * Use lseek SEEK_DATA to adjust off_out to the next location from fd_in + * containing data (creates sparse empty blocks when appropriate). Effects + * on file offsets are undefined. + * * Return: On success, the number of bytes to copy before the next hole, * and -1 on failure (errno is set appropriately). Returns 0 when fd_in * reaches EOF. @@ -145,13 +184,6 @@ do_lseek_data(int fd_out, int fd_in, off_t *off_out) { return -1; } - /* Revert SEEK_HOLE offset change, since we're going - * to copy the data that comes before the hole. - */ - if (lseek(fd_in, offset_data, SEEK_SET) < 0) { - return -1; - } - return offset_hole - offset_data; #else /* This is how it fails at runtime when lseek SEEK_DATA is not supported. */ @@ -232,10 +264,6 @@ _reflink_linux_file_copy(PyObject *self, PyObject *args) break; } - /* For the copyfunc call, the fd_in file offset must be - * exactly equal to offset_out. The above do_lseek_data - * function guarantees correct state. - */ copyfunc_ret = copyfunc(fd_out, fd_in, &offset_out, @@ -250,7 +278,7 @@ _reflink_linux_file_copy(PyObject *self, PyObject *args) * syscall is not available (less than Linux 4.5). */ error = 0; - copyfunc = sendfile; + copyfunc = sf_wrapper; copyfunc_ret = copyfunc(fd_out, fd_in, &offset_out, @@ -284,27 +312,18 @@ _reflink_linux_file_copy(PyObject *self, PyObject *args) } else { stat_in_acquired = 1; - /* For the sendfile call, the fd_in file offset must be - * exactly equal to offset_out. Use lseek to ensure - * correct state, in case an EINTR retry caused it to - * get out of sync somewhow. - */ - if (lseek(fd_in, offset_out, SEEK_SET) < 0) { - error = errno; - } else { - while (offset_out < stat_in.st_size) { - copyfunc_ret = sendfile(fd_out, - fd_in, - &offset_out, - stat_in.st_size - offset_out); + while (offset_out < stat_in.st_size) { + copyfunc_ret = sf_wrapper(fd_out, + fd_in, + &offset_out, + stat_in.st_size - offset_out); - if (copyfunc_ret < 0) { - error = errno; - if (errno == EINVAL && !offset_out) { - sendfile_works = 0; - } - break; + if (copyfunc_ret < 0) { + error = errno; + if (errno == EINVAL && !offset_out) { + sendfile_works = 0; } + break; } } } |