From: "Brian Dolbec" <dolsen@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/portage:master commit in: pym/repoman/
Date: Mon, 21 Sep 2015 23:51:19 +0000 (UTC) [thread overview]
Message-ID: <1442878966.9f63c395ee23b00d77d00e667a28624de5baff49.dolsen@gentoo> (raw)
Message-ID: <20150921235119.hZor96SueDKTIvEAx5vdGtR_Rx7sm7FxU2ZTQMGgTUo@z> (raw)
commit: 9f63c395ee23b00d77d00e667a28624de5baff49
Author: Brian Dolbec <dolsen <AT> gentoo <DOT> org>
AuthorDate: Thu Sep 17 15:29:11 2015 +0000
Commit: Brian Dolbec <dolsen <AT> gentoo <DOT> org>
CommitDate: Mon Sep 21 23:42:46 2015 +0000
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=9f63c395
repoman: Move the primary checks loop to it's own class and file
Only minimal changes were done for this initial move.
The _scan_ebuilds() needs major hacking up into manageable chunks.
Clean out code separation demarcation lines
These lines were originally used to mark places where code was removed.
And replaced with a class instance and/or function call.
Signed-off-by: Brian Dolbec <dolsen <AT> gentoo.org>
pym/repoman/main.py | 756 ++-----------------------------------------------
pym/repoman/scanner.py | 715 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 743 insertions(+), 728 deletions(-)
diff --git a/pym/repoman/main.py b/pym/repoman/main.py
index e3d0472..2b2f91d 100755
--- a/pym/repoman/main.py
+++ b/pym/repoman/main.py
@@ -4,7 +4,6 @@
from __future__ import print_function, unicode_literals
-import copy
import errno
import io
import logging
@@ -15,7 +14,6 @@ import sys
import tempfile
import platform
from itertools import chain
-from pprint import pformat
from os import path as osp
if osp.isfile(osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), ".portage_not_installed")):
@@ -30,14 +28,12 @@ portage._disable_legacy_globals()
from portage import os
from portage import _encodings
from portage import _unicode_encode
-from _emerge.Package import Package
from _emerge.UserQuery import UserQuery
import portage.checksum
import portage.const
import portage.repository.config
-from portage import cvstree, normalize_path
+from portage import cvstree
from portage import util
-from portage.dep import Atom
from portage.process import find_binary, spawn
from portage.output import (
bold, create_color_func, green, nocolor, red)
@@ -47,40 +43,18 @@ from portage.util import writemsg_level
from portage.package.ebuild.digestgen import digestgen
from repoman.argparser import parse_args
-from repoman.checks.directories.files import FileChecks
-from repoman.checks.ebuilds.checks import run_checks, checks_init
-from repoman.checks.ebuilds.eclasses.live import LiveEclassChecks
-from repoman.checks.ebuilds.eclasses.ruby import RubyEclassChecks
-from repoman.checks.ebuilds.fetches import FetchChecks
-from repoman.checks.ebuilds.keywords import KeywordChecks
-from repoman.checks.ebuilds.isebuild import IsEbuild
-from repoman.checks.ebuilds.thirdpartymirrors import ThirdPartyMirrors
-from repoman.checks.ebuilds.manifests import Manifests
-from repoman.check_missingslot import check_missingslot
-from repoman.checks.ebuilds.misc import bad_split_check, pkg_invalid
-from repoman.checks.ebuilds.pkgmetadata import PkgMetadata
-from repoman.checks.ebuilds.use_flags import USEFlagChecks
-from repoman.checks.ebuilds.variables.description import DescriptionChecks
-from repoman.checks.ebuilds.variables.eapi import EAPIChecks
-from repoman.checks.ebuilds.variables.license import LicenseChecks
-from repoman.checks.ebuilds.variables.restrict import RestrictChecks
-from repoman.ebuild import Ebuild
+from repoman.checks.ebuilds.checks import checks_init
from repoman.errors import err
from repoman.gpg import gpgsign, need_signature
-from repoman.modules.commit import repochecks
-from repoman.profile import check_profiles, dev_profile_keywords, setup_profile
from repoman.qa_data import (
format_qa_output, format_qa_output_column, qahelp,
- qawarnings, qacats, missingvars,
- suspect_virtual, suspect_rdepend)
-from repoman.qa_tracker import QATracker
-from repoman.repos import RepoSettings, repo_metadata
-from repoman.scan import Changes, scan
+ qawarnings, qacats)
+from repoman.repos import RepoSettings
+from repoman.scanner import Scanner
from repoman._subprocess import repoman_popen, repoman_getstatusoutput
from repoman import utilities
from repoman.vcs.vcs import (
git_supports_gpg_sign, vcs_files_to_cps, VCSSettings)
-from repoman.vcs.vcsstatus import VCSStatus
if sys.hexversion >= 0x3000000:
@@ -90,21 +64,11 @@ util.initialize_logger()
bad = create_color_func("BAD")
-live_eclasses = portage.const.LIVE_ECLASSES
-non_ascii_re = re.compile(r'[^\x00-\x7f]')
-
# A sane umask is needed for files that portage creates.
os.umask(0o22)
-def sort_key(item):
- return item[2].sub_path
-
def repoman_main(argv):
- # Repoman sets it's own ACCEPT_KEYWORDS and we don't want it to
- # behave incrementally.
- repoman_incrementals = tuple(
- x for x in portage.const.INCREMENTALS if x != 'ACCEPT_KEYWORDS')
config_root = os.environ.get("PORTAGE_CONFIGROOT")
repoman_settings = portage.config(config_root=config_root, local_config=False)
@@ -142,30 +106,9 @@ def repoman_main(argv):
repo_settings = RepoSettings(
config_root, portdir, portdir_overlay,
repoman_settings, vcs_settings, options, qawarnings)
-
repoman_settings = repo_settings.repoman_settings
-
portdb = repo_settings.portdb
- if options.echangelog is None and repo_settings.repo_config.update_changelog:
- options.echangelog = 'y'
-
- if vcs_settings.vcs is None:
- options.echangelog = 'n'
-
- # The --echangelog option causes automatic ChangeLog generation,
- # which invalidates changelog.ebuildadded and changelog.missing
- # checks.
- # Note: Some don't use ChangeLogs in distributed SCMs.
- # It will be generated on server side from scm log,
- # before package moves to the rsync server.
- # This is needed because they try to avoid merge collisions.
- # Gentoo's Council decided to always use the ChangeLog file.
- # TODO: shouldn't this just be switched on the repo, iso the VCS?
- is_echangelog_enabled = options.echangelog in ('y', 'force')
- vcs_settings.vcs_is_cvs_or_svn = vcs_settings.vcs in ('cvs', 'svn')
- check_changelog = not is_echangelog_enabled and vcs_settings.vcs_is_cvs_or_svn
-
if 'digest' in repoman_settings.features and options.digest != 'n':
options.digest = 'y'
@@ -178,663 +121,16 @@ def repoman_main(argv):
env = os.environ.copy()
env['FEATURES'] = env.get('FEATURES', '') + ' -unknown-features-warn'
- categories = []
- for path in repo_settings.repo_config.eclass_db.porttrees:
- categories.extend(portage.util.grabfile(
- os.path.join(path, 'profiles', 'categories')))
- repoman_settings.categories = frozenset(
- portage.util.stack_lists([categories], incremental=1))
- categories = repoman_settings.categories
-
- portdb.settings = repoman_settings
- # We really only need to cache the metadata that's necessary for visibility
- # filtering. Anything else can be discarded to reduce memory consumption.
- portdb._aux_cache_keys.clear()
- portdb._aux_cache_keys.update(
- ["EAPI", "IUSE", "KEYWORDS", "repository", "SLOT"])
-
- reposplit = myreporoot.split(os.path.sep)
- repolevel = len(reposplit)
-
- ###################
- commitmessage = None
- if options.mode == 'commit':
- repochecks.commit_check(repolevel, reposplit)
- repochecks.conflict_check(vcs_settings, options)
-
- ###################
-
- # Make startdir relative to the canonical repodir, so that we can pass
- # it to digestgen and it won't have to be canonicalized again.
- if repolevel == 1:
- startdir = repo_settings.repodir
- else:
- startdir = normalize_path(mydir)
- startdir = os.path.join(
- repo_settings.repodir, *startdir.split(os.sep)[-2 - repolevel + 3:])
- ###################
-
-
- # get lists of valid keywords, licenses, and use
- new_data = repo_metadata(repo_settings.portdb, repoman_settings)
- kwlist, liclist, uselist, profile_list, \
- global_pmaskdict, liclist_deprecated = new_data
-
- repoman_settings['PORTAGE_ARCHLIST'] = ' '.join(sorted(kwlist))
- repoman_settings.backup_changes('PORTAGE_ARCHLIST')
-
- ####################
-
- profiles = setup_profile(profile_list)
-
- ####################
-
- check_profiles(profiles, repoman_settings.archlist())
-
- ####################
-
- scanlist = scan(repolevel, reposplit, startdir, categories, repo_settings)
-
- ####################
-
- dev_keywords = dev_profile_keywords(profiles)
-
- qatracker = QATracker()
-
-
- if options.mode == "manifest":
- pass
- elif options.pretend:
- print(green("\nRepoMan does a once-over of the neighborhood..."))
- else:
- print(green("\nRepoMan scours the neighborhood..."))
-
- #####################
-
- changed = Changes(options)
- changed.scan(vcs_settings)
-
- ######################
-
- have_pmasked = False
- have_dev_keywords = False
- dofail = 0
-
- # NOTE: match-all caches are not shared due to potential
- # differences between profiles in _get_implicit_iuse.
- arch_caches = {}
- arch_xmatch_caches = {}
- shared_xmatch_caches = {"cp-list": {}}
-
- include_arches = None
- if options.include_arches:
- include_arches = set()
- include_arches.update(*[x.split() for x in options.include_arches])
-
- # Disable the "ebuild.notadded" check when not in commit mode and
- # running `svn status` in every package dir will be too expensive.
-
- check_ebuild_notadded = not \
- (vcs_settings.vcs == "svn" and repolevel < 3 and options.mode != "commit")
-
- effective_scanlist = scanlist
- if options.if_modified == "y":
- effective_scanlist = sorted(vcs_files_to_cps(
- chain(changed.changed, changed.new, changed.removed),
- repolevel, reposplit, categories))
-
- ######################
- # initialize our checks classes here before the big xpkg loop
- manifester = Manifests(options, qatracker, repoman_settings)
- is_ebuild = IsEbuild(repoman_settings, repo_settings, portdb, qatracker)
- filescheck = FileChecks(
- qatracker, repoman_settings, repo_settings, portdb, vcs_settings)
- status_check = VCSStatus(vcs_settings, qatracker)
- fetchcheck = FetchChecks(
- qatracker, repoman_settings, repo_settings, portdb, vcs_settings)
- pkgmeta = PkgMetadata(options, qatracker, repoman_settings)
- thirdparty = ThirdPartyMirrors(repoman_settings, qatracker)
- use_flag_checks = USEFlagChecks(qatracker, uselist)
- keywordcheck = KeywordChecks(qatracker, options)
- liveeclasscheck = LiveEclassChecks(qatracker)
- rubyeclasscheck = RubyEclassChecks(qatracker)
- eapicheck = EAPIChecks(qatracker, repo_settings)
- descriptioncheck = DescriptionChecks(qatracker)
- licensecheck = LicenseChecks(qatracker, liclist, liclist_deprecated)
- restrictcheck = RestrictChecks(qatracker)
- ######################
-
- for xpkg in effective_scanlist:
- # ebuilds and digests added to cvs respectively.
- logging.info("checking package %s" % xpkg)
- # save memory by discarding xmatch caches from previous package(s)
- arch_xmatch_caches.clear()
- eadded = []
- catdir, pkgdir = xpkg.split("/")
- checkdir = repo_settings.repodir + "/" + xpkg
- checkdir_relative = ""
- if repolevel < 3:
- checkdir_relative = os.path.join(pkgdir, checkdir_relative)
- if repolevel < 2:
- checkdir_relative = os.path.join(catdir, checkdir_relative)
- checkdir_relative = os.path.join(".", checkdir_relative)
-
- #####################
- if manifester.run(checkdir, portdb):
- continue
- if not manifester.generated_manifest:
- manifester.digest_check(xpkg, checkdir)
- ######################
-
- if options.mode == 'manifest-check':
- continue
-
- checkdirlist = os.listdir(checkdir)
-
- ######################
- pkgs, allvalid = is_ebuild.check(checkdirlist, checkdir, xpkg)
- if is_ebuild.continue_:
- # If we can't access all the metadata then it's totally unsafe to
- # commit since there's no way to generate a correct Manifest.
- # Do not try to do any more QA checks on this package since missing
- # metadata leads to false positives for several checks, and false
- # positives confuse users.
- can_force = False
- continue
- ######################
-
- keywordcheck.prepare()
-
- # Sort ebuilds in ascending order for the KEYWORDS.dropped check.
- ebuildlist = sorted(pkgs.values())
- ebuildlist = [pkg.pf for pkg in ebuildlist]
- #######################
- filescheck.check(
- checkdir, checkdirlist, checkdir_relative, changed.changed, changed.new)
- #######################
- status_check.check(check_ebuild_notadded, checkdir, checkdir_relative, xpkg)
- eadded.extend(status_check.eadded)
-
- #################
- fetchcheck.check(
- xpkg, checkdir, checkdir_relative, changed.changed, changed.new)
- #################
-
- if check_changelog and "ChangeLog" not in checkdirlist:
- qatracker.add_error("changelog.missing", xpkg + "/ChangeLog")
- #################
- pkgmeta.check(xpkg, checkdir, checkdirlist, repolevel)
- muselist = frozenset(pkgmeta.musedict)
- #################
-
- changelog_path = os.path.join(checkdir_relative, "ChangeLog")
- changelog_modified = changelog_path in changed.changelogs
-
- # detect unused local USE-descriptions
- used_useflags = set()
-
- for y_ebuild in ebuildlist:
- ##################
- ebuild = Ebuild(
- repo_settings, repolevel, pkgdir, catdir, vcs_settings,
- xpkg, y_ebuild)
- ##################
-
- if check_changelog and not changelog_modified \
- and ebuild.ebuild_path in changed.new_ebuilds:
- qatracker.add_error('changelog.ebuildadded', ebuild.relative_path)
-
- if ebuild.untracked(check_ebuild_notadded, y_ebuild, eadded):
- # ebuild not added to vcs
- qatracker.add_error(
- "ebuild.notadded", xpkg + "/" + y_ebuild + ".ebuild")
-
- ##################
- if bad_split_check(xpkg, y_ebuild, pkgdir, qatracker):
- continue
- ###################
- pkg = pkgs[y_ebuild]
- if pkg_invalid(pkg, qatracker, ebuild):
- allvalid = False
- continue
-
- myaux = pkg._metadata
- eapi = myaux["EAPI"]
- inherited = pkg.inherited
- live_ebuild = live_eclasses.intersection(inherited)
-
- #######################
- eapicheck.check(pkg, ebuild)
- #######################
-
- for k, v in myaux.items():
- if not isinstance(v, basestring):
- continue
- m = non_ascii_re.search(v)
- if m is not None:
- qatracker.add_error(
- "variable.invalidchar",
- "%s: %s variable contains non-ASCII "
- "character at position %s" %
- (ebuild.relative_path, k, m.start() + 1))
-
- if not fetchcheck.src_uri_error:
- #######################
- thirdparty.check(myaux, ebuild.relative_path)
- #######################
- if myaux.get("PROVIDE"):
- qatracker.add_error("virtual.oldstyle", ebuild.relative_path)
-
- for pos, missing_var in enumerate(missingvars):
- if not myaux.get(missing_var):
- if catdir == "virtual" and \
- missing_var in ("HOMEPAGE", "LICENSE"):
- continue
- if live_ebuild and missing_var == "KEYWORDS":
- continue
- myqakey = missingvars[pos] + ".missing"
- qatracker.add_error(myqakey, xpkg + "/" + y_ebuild + ".ebuild")
-
- if catdir == "virtual":
- for var in ("HOMEPAGE", "LICENSE"):
- if myaux.get(var):
- myqakey = var + ".virtual"
- qatracker.add_error(myqakey, ebuild.relative_path)
-
- #######################
- descriptioncheck.check(pkg, ebuild)
- #######################
-
- keywords = myaux["KEYWORDS"].split()
-
- ebuild_archs = set(
- kw.lstrip("~") for kw in keywords if not kw.startswith("-"))
-
- #######################
- keywordcheck.check(
- pkg, xpkg, ebuild, y_ebuild, keywords, ebuild_archs, changed,
- live_ebuild, kwlist, profiles)
- #######################
-
- if live_ebuild and repo_settings.repo_config.name == "gentoo":
- #######################
- liveeclasscheck.check(
- pkg, xpkg, ebuild, y_ebuild, keywords, global_pmaskdict)
- #######################
-
- if options.ignore_arches:
- arches = [[
- repoman_settings["ARCH"], repoman_settings["ARCH"],
- repoman_settings["ACCEPT_KEYWORDS"].split()]]
- else:
- arches = set()
- for keyword in keywords:
- if keyword[0] == "-":
- continue
- elif keyword[0] == "~":
- arch = keyword[1:]
- if arch == "*":
- for expanded_arch in profiles:
- if expanded_arch == "**":
- continue
- arches.add(
- (keyword, expanded_arch, (
- expanded_arch, "~" + expanded_arch)))
- else:
- arches.add((keyword, arch, (arch, keyword)))
- else:
- if keyword == "*":
- for expanded_arch in profiles:
- if expanded_arch == "**":
- continue
- arches.add(
- (keyword, expanded_arch, (expanded_arch,)))
- else:
- arches.add((keyword, keyword, (keyword,)))
- if not arches:
- # Use an empty profile for checking dependencies of
- # packages that have empty KEYWORDS.
- arches.add(('**', '**', ('**',)))
-
- unknown_pkgs = set()
- baddepsyntax = False
- badlicsyntax = False
- badprovsyntax = False
- # catpkg = catdir + "/" + y_ebuild
-
- inherited_java_eclass = "java-pkg-2" in inherited or \
- "java-pkg-opt-2" in inherited
- inherited_wxwidgets_eclass = "wxwidgets" in inherited
- # operator_tokens = set(["||", "(", ")"])
- type_list, badsyntax = [], []
- for mytype in Package._dep_keys + ("LICENSE", "PROPERTIES", "PROVIDE"):
- mydepstr = myaux[mytype]
-
- buildtime = mytype in Package._buildtime_keys
- runtime = mytype in Package._runtime_keys
- token_class = None
- if mytype.endswith("DEPEND"):
- token_class = portage.dep.Atom
+ # Perform the main checks
+ scanner = Scanner(repo_settings, myreporoot, config_root, options,
+ vcs_settings, mydir, env)
+ qatracker, can_force = scanner.scan_pkgs(can_force)
- try:
- atoms = portage.dep.use_reduce(
- mydepstr, matchall=1, flat=True,
- is_valid_flag=pkg.iuse.is_valid_flag, token_class=token_class)
- except portage.exception.InvalidDependString as e:
- atoms = None
- badsyntax.append(str(e))
-
- if atoms and mytype.endswith("DEPEND"):
- if runtime and \
- "test?" in mydepstr.split():
- qatracker.add_error(
- mytype + '.suspect',
- "%s: 'test?' USE conditional in %s" %
- (ebuild.relative_path, mytype))
-
- for atom in atoms:
- if atom == "||":
- continue
-
- is_blocker = atom.blocker
-
- # Skip dependency.unknown for blockers, so that we
- # don't encourage people to remove necessary blockers,
- # as discussed in bug 382407. We use atom.without_use
- # due to bug 525376.
- if not is_blocker and \
- not portdb.xmatch("match-all", atom.without_use) and \
- not atom.cp.startswith("virtual/"):
- unknown_pkgs.add((mytype, atom.unevaluated_atom))
-
- if catdir != "virtual":
- if not is_blocker and \
- atom.cp in suspect_virtual:
- qatracker.add_error(
- 'virtual.suspect', ebuild.relative_path +
- ": %s: consider using '%s' instead of '%s'" %
- (mytype, suspect_virtual[atom.cp], atom))
- if not is_blocker and \
- atom.cp.startswith("perl-core/"):
- qatracker.add_error('dependency.perlcore',
- ebuild.relative_path +
- ": %s: please use '%s' instead of '%s'" %
- (mytype,
- atom.replace("perl-core/","virtual/perl-"),
- atom))
-
- if buildtime and \
- not is_blocker and \
- not inherited_java_eclass and \
- atom.cp == "virtual/jdk":
- qatracker.add_error(
- 'java.eclassesnotused', ebuild.relative_path)
- elif buildtime and \
- not is_blocker and \
- not inherited_wxwidgets_eclass and \
- atom.cp == "x11-libs/wxGTK":
- qatracker.add_error(
- 'wxwidgets.eclassnotused',
- "%s: %ss on x11-libs/wxGTK without inheriting"
- " wxwidgets.eclass" % (ebuild.relative_path, mytype))
- elif runtime:
- if not is_blocker and \
- atom.cp in suspect_rdepend:
- qatracker.add_error(
- mytype + '.suspect',
- ebuild.relative_path + ": '%s'" % atom)
-
- if atom.operator == "~" and \
- portage.versions.catpkgsplit(atom.cpv)[3] != "r0":
- qacat = 'dependency.badtilde'
- qatracker.add_error(
- qacat, "%s: %s uses the ~ operator"
- " with a non-zero revision: '%s'" %
- (ebuild.relative_path, mytype, atom))
-
- check_missingslot(atom, mytype, eapi, portdb, qatracker,
- ebuild.relative_path, myaux)
-
- type_list.extend([mytype] * (len(badsyntax) - len(type_list)))
-
- for m, b in zip(type_list, badsyntax):
- if m.endswith("DEPEND"):
- qacat = "dependency.syntax"
- else:
- qacat = m + ".syntax"
- qatracker.add_error(
- qacat, "%s: %s: %s" % (ebuild.relative_path, m, b))
-
- badlicsyntax = len([z for z in type_list if z == "LICENSE"])
- badprovsyntax = len([z for z in type_list if z == "PROVIDE"])
- baddepsyntax = len(type_list) != badlicsyntax + badprovsyntax
- badlicsyntax = badlicsyntax > 0
- badprovsyntax = badprovsyntax > 0
-
- #################
- use_flag_checks.check(pkg, xpkg, ebuild, y_ebuild, muselist)
-
- ebuild_used_useflags = use_flag_checks.getUsedUseFlags()
- used_useflags = used_useflags.union(ebuild_used_useflags)
- #################
- rubyeclasscheck.check(pkg, ebuild)
- #################
-
- # license checks
- if not badlicsyntax:
- #################
- licensecheck.check(pkg, xpkg, ebuild, y_ebuild)
- #################
-
- #################
- restrictcheck.check(pkg, xpkg, ebuild, y_ebuild)
- #################
-
- # Syntax Checks
-
- if not vcs_settings.vcs_preserves_mtime:
- if ebuild.ebuild_path not in changed.new_ebuilds and \
- ebuild.ebuild_path not in changed.ebuilds:
- pkg.mtime = None
- try:
- # All ebuilds should have utf_8 encoding.
- f = io.open(
- _unicode_encode(
- ebuild.full_path, encoding=_encodings['fs'], errors='strict'),
- mode='r', encoding=_encodings['repo.content'])
- try:
- for check_name, e in run_checks(f, pkg):
- qatracker.add_error(
- check_name, ebuild.relative_path + ': %s' % e)
- finally:
- f.close()
- except UnicodeDecodeError:
- # A file.UTF8 failure will have already been recorded above.
- pass
-
- if options.force:
- # The dep_check() calls are the most expensive QA test. If --force
- # is enabled, there's no point in wasting time on these since the
- # user is intent on forcing the commit anyway.
- continue
-
- relevant_profiles = []
- for keyword, arch, groups in arches:
- if arch not in profiles:
- # A missing profile will create an error further down
- # during the KEYWORDS verification.
- continue
-
- if include_arches is not None:
- if arch not in include_arches:
- continue
-
- relevant_profiles.extend(
- (keyword, groups, prof) for prof in profiles[arch])
-
- relevant_profiles.sort(key=sort_key)
-
- for keyword, groups, prof in relevant_profiles:
-
- is_stable_profile = prof.status == "stable"
- is_dev_profile = prof.status == "dev" and \
- options.include_dev
- is_exp_profile = prof.status == "exp" and \
- options.include_exp_profiles == 'y'
- if not (is_stable_profile or is_dev_profile or is_exp_profile):
- continue
+ commitmessage = None
- dep_settings = arch_caches.get(prof.sub_path)
- if dep_settings is None:
- dep_settings = portage.config(
- config_profile_path=prof.abs_path,
- config_incrementals=repoman_incrementals,
- config_root=config_root,
- local_config=False,
- _unmatched_removal=options.unmatched_removal,
- env=env, repositories=repoman_settings.repositories)
- dep_settings.categories = repoman_settings.categories
- if options.without_mask:
- dep_settings._mask_manager_obj = \
- copy.deepcopy(dep_settings._mask_manager)
- dep_settings._mask_manager._pmaskdict.clear()
- arch_caches[prof.sub_path] = dep_settings
-
- xmatch_cache_key = (prof.sub_path, tuple(groups))
- xcache = arch_xmatch_caches.get(xmatch_cache_key)
- if xcache is None:
- portdb.melt()
- portdb.freeze()
- xcache = portdb.xcache
- xcache.update(shared_xmatch_caches)
- arch_xmatch_caches[xmatch_cache_key] = xcache
-
- repo_settings.trees[repo_settings.root]["porttree"].settings = dep_settings
- portdb.settings = dep_settings
- portdb.xcache = xcache
-
- dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups)
- # just in case, prevent config.reset() from nuking these.
- dep_settings.backup_changes("ACCEPT_KEYWORDS")
-
- # This attribute is used in dbapi._match_use() to apply
- # use.stable.{mask,force} settings based on the stable
- # status of the parent package. This is required in order
- # for USE deps of unstable packages to be resolved correctly,
- # since otherwise use.stable.{mask,force} settings of
- # dependencies may conflict (see bug #456342).
- dep_settings._parent_stable = dep_settings._isStable(pkg)
-
- # Handle package.use*.{force,mask) calculation, for use
- # in dep_check.
- dep_settings.useforce = dep_settings._use_manager.getUseForce(
- pkg, stable=dep_settings._parent_stable)
- dep_settings.usemask = dep_settings._use_manager.getUseMask(
- pkg, stable=dep_settings._parent_stable)
-
- if not baddepsyntax:
- ismasked = not ebuild_archs or \
- pkg.cpv not in portdb.xmatch("match-visible",
- Atom("%s::%s" % (pkg.cp, repo_settings.repo_config.name)))
- if ismasked:
- if not have_pmasked:
- have_pmasked = bool(dep_settings._getMaskAtom(
- pkg.cpv, pkg._metadata))
- if options.ignore_masked:
- continue
- # we are testing deps for a masked package; give it some lee-way
- suffix = "masked"
- matchmode = "minimum-all"
- else:
- suffix = ""
- matchmode = "minimum-visible"
-
- if not have_dev_keywords:
- have_dev_keywords = \
- bool(dev_keywords.intersection(keywords))
-
- if prof.status == "dev":
- suffix = suffix + "indev"
-
- for mytype in Package._dep_keys:
-
- mykey = "dependency.bad" + suffix
- myvalue = myaux[mytype]
- if not myvalue:
- continue
-
- success, atoms = portage.dep_check(
- myvalue, portdb, dep_settings,
- use="all", mode=matchmode, trees=repo_settings.trees)
-
- if success:
- if atoms:
-
- # Don't bother with dependency.unknown for
- # cases in which *DEPEND.bad is triggered.
- for atom in atoms:
- # dep_check returns all blockers and they
- # aren't counted for *DEPEND.bad, so we
- # ignore them here.
- if not atom.blocker:
- unknown_pkgs.discard(
- (mytype, atom.unevaluated_atom))
-
- if not prof.sub_path:
- # old-style virtuals currently aren't
- # resolvable with empty profile, since
- # 'virtuals' mappings are unavailable
- # (it would be expensive to search
- # for PROVIDE in all ebuilds)
- atoms = [
- atom for atom in atoms if not (
- atom.cp.startswith('virtual/')
- and not portdb.cp_list(atom.cp))]
-
- # we have some unsolvable deps
- # remove ! deps, which always show up as unsatisfiable
- atoms = [
- str(atom.unevaluated_atom)
- for atom in atoms if not atom.blocker]
-
- # if we emptied out our list, continue:
- if not atoms:
- continue
- qatracker.add_error(mykey,
- "%s: %s: %s(%s)\n%s"
- % (ebuild.relative_path, mytype, keyword, prof,
- pformat(atoms, indent=6)))
- else:
- qatracker.add_error(mykey,
- "%s: %s: %s(%s)\n%s"
- % (ebuild.relative_path, mytype, keyword, prof,
- pformat(atoms, indent=6)))
-
- if not baddepsyntax and unknown_pkgs:
- type_map = {}
- for mytype, atom in unknown_pkgs:
- type_map.setdefault(mytype, set()).add(atom)
- for mytype, atoms in type_map.items():
- qatracker.add_error(
- "dependency.unknown", "%s: %s: %s"
- % (ebuild.relative_path, mytype, ", ".join(sorted(atoms))))
-
- # check if there are unused local USE-descriptions in metadata.xml
- # (unless there are any invalids, to avoid noise)
- if allvalid:
- for myflag in muselist.difference(used_useflags):
- qatracker.add_error(
- "metadata.warning",
- "%s/metadata.xml: unused local USE-description: '%s'"
- % (xpkg, myflag))
-
-
- if options.if_modified == "y" and len(effective_scanlist) < 1:
+ if options.if_modified == "y" and len(scanner.effective_scanlist) < 1:
logging.warning("--if-modified is enabled, but no modified packages were found!")
- if options.mode == "manifest":
- sys.exit(dofail)
-
# dofail will be true if we have failed in at least one non-warning category
dofail = 0
# dowarn will be true if we tripped any warnings
@@ -842,6 +138,10 @@ def repoman_main(argv):
# dofull will be true if we should print a "repoman full" informational message
dofull = options.mode != 'full'
+ # early out for manifest generation
+ if options.mode == "manifest":
+ sys.exit(dofail)
+
for x in qacats:
if x not in qatracker.fails:
continue
@@ -884,9 +184,9 @@ def repoman_main(argv):
suggest_ignore_masked = False
suggest_include_dev = False
- if have_pmasked and not (options.without_mask or options.ignore_masked):
+ if scanner.have['pmasked'] and not (options.without_mask or options.ignore_masked):
suggest_ignore_masked = True
- if have_dev_keywords and not options.include_dev:
+ if scanner.have['dev_keywords'] and not options.include_dev:
suggest_include_dev = True
if suggest_ignore_masked or suggest_include_dev:
@@ -1164,8 +464,8 @@ def repoman_main(argv):
commitmessagefile = None
if not commitmessage or not commitmessage.strip():
msg_prefix = ""
- if repolevel > 1:
- msg_prefix = "/".join(reposplit[1:]) + ": "
+ if scanner.repolevel > 1:
+ msg_prefix = "/".join(scanner.reposplit[1:]) + ": "
try:
editor = os.environ.get("EDITOR")
@@ -1196,10 +496,10 @@ def repoman_main(argv):
report_options.append("--force")
if options.ignore_arches:
report_options.append("--ignore-arches")
- if include_arches is not None:
+ if scanner.include_arches is not None:
report_options.append(
"--include-arches=\"%s\"" %
- " ".join(sorted(include_arches)))
+ " ".join(sorted(scanner.include_arches)))
if vcs_settings.vcs == "git":
# Use new footer only for git (see bug #438364).
@@ -1238,18 +538,18 @@ def repoman_main(argv):
committer_name = utilities.get_committer_name(env=repoman_settings)
for x in sorted(vcs_files_to_cps(
chain(myupdates, mymanifests, myremoved),
- repolevel, reposplit, categories)):
+ scanner.repolevel, scanner.reposplit, scanner.categories)):
catdir, pkgdir = x.split("/")
checkdir = repo_settings.repodir + "/" + x
checkdir_relative = ""
- if repolevel < 3:
+ if scanner.repolevel < 3:
checkdir_relative = os.path.join(pkgdir, checkdir_relative)
- if repolevel < 2:
+ if scanner.repolevel < 2:
checkdir_relative = os.path.join(catdir, checkdir_relative)
checkdir_relative = os.path.join(".", checkdir_relative)
changelog_path = os.path.join(checkdir_relative, "ChangeLog")
- changelog_modified = changelog_path in changed.changelogs
+ changelog_modified = changelog_path in scanner.changed.changelogs
if changelog_modified and options.echangelog != 'force':
continue
@@ -1459,7 +759,7 @@ def repoman_main(argv):
if modified:
portage.util.write_atomic(x, b''.join(mylines), mode='wb')
- if repolevel == 1:
+ if scanner.repolevel == 1:
utilities.repoman_sez(
"\"You're rather crazy... "
"doing the entire repository.\"\n")
@@ -1467,7 +767,7 @@ def repoman_main(argv):
if vcs_settings.vcs in ('cvs', 'svn') and (myupdates or myremoved):
for x in sorted(vcs_files_to_cps(
chain(myupdates, myremoved, mymanifests),
- repolevel, reposplit, categories)):
+ scanner.repolevel, scanner.reposplit, scanner.categories)):
repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
digestgen(mysettings=repoman_settings, myportdb=portdb)
@@ -1480,7 +780,7 @@ def repoman_main(argv):
try:
for x in sorted(vcs_files_to_cps(
chain(myupdates, myremoved, mymanifests),
- repolevel, reposplit, categories)):
+ scanner.repolevel, scanner.reposplit, scanner.categories)):
repoman_settings["O"] = os.path.join(repo_settings.repodir, x)
manifest_path = os.path.join(repoman_settings["O"], "Manifest")
if not need_signature(manifest_path):
diff --git a/pym/repoman/scanner.py b/pym/repoman/scanner.py
new file mode 100644
index 0000000..44ff33b
--- /dev/null
+++ b/pym/repoman/scanner.py
@@ -0,0 +1,715 @@
+
+import copy
+import io
+import logging
+import re
+import sys
+from itertools import chain
+from pprint import pformat
+
+from _emerge.Package import Package
+
+import portage
+from portage import normalize_path
+from portage import os
+from portage import _encodings
+from portage import _unicode_encode
+from portage.dep import Atom
+from portage.output import green
+from repoman.checks.directories.files import FileChecks
+from repoman.checks.ebuilds.checks import run_checks
+from repoman.checks.ebuilds.eclasses.live import LiveEclassChecks
+from repoman.checks.ebuilds.eclasses.ruby import RubyEclassChecks
+from repoman.checks.ebuilds.fetches import FetchChecks
+from repoman.checks.ebuilds.keywords import KeywordChecks
+from repoman.checks.ebuilds.isebuild import IsEbuild
+from repoman.checks.ebuilds.thirdpartymirrors import ThirdPartyMirrors
+from repoman.checks.ebuilds.manifests import Manifests
+from repoman.check_missingslot import check_missingslot
+from repoman.checks.ebuilds.misc import bad_split_check, pkg_invalid
+from repoman.checks.ebuilds.pkgmetadata import PkgMetadata
+from repoman.checks.ebuilds.use_flags import USEFlagChecks
+from repoman.checks.ebuilds.variables.description import DescriptionChecks
+from repoman.checks.ebuilds.variables.eapi import EAPIChecks
+from repoman.checks.ebuilds.variables.license import LicenseChecks
+from repoman.checks.ebuilds.variables.restrict import RestrictChecks
+from repoman.ebuild import Ebuild
+from repoman.modules.commit import repochecks
+from repoman.profile import check_profiles, dev_profile_keywords, setup_profile
+from repoman.qa_data import missingvars, suspect_virtual, suspect_rdepend
+from repoman.qa_tracker import QATracker
+from repoman.repos import repo_metadata
+from repoman.scan import Changes, scan
+from repoman.vcs.vcsstatus import VCSStatus
+from repoman.vcs.vcs import vcs_files_to_cps
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+NON_ASCII_RE = re.compile(r'[^\x00-\x7f]')
+
+
+def sort_key(item):
+ return item[2].sub_path
+
+
+
+class Scanner(object):
+ '''Primary scan class. Operates all the small Q/A tests and checks'''
+
+ def __init__(self, repo_settings, myreporoot, config_root, options,
+ vcs_settings, mydir, env):
+ '''Class __init__'''
+ self.repo_settings = repo_settings
+ self.config_root = config_root
+ self.options = options
+ self.vcs_settings = vcs_settings
+ self.env = env
+
+ # Repoman sets it's own ACCEPT_KEYWORDS and we don't want it to
+ # behave incrementally.
+ self.repoman_incrementals = tuple(
+ x for x in portage.const.INCREMENTALS if x != 'ACCEPT_KEYWORDS')
+
+ self.categories = []
+ for path in self.repo_settings.repo_config.eclass_db.porttrees:
+ self.categories.extend(portage.util.grabfile(
+ os.path.join(path, 'profiles', 'categories')))
+ self.repo_settings.repoman_settings.categories = frozenset(
+ portage.util.stack_lists([self.categories], incremental=1))
+ self.categories = self.repo_settings.repoman_settings.categories
+
+ self.portdb = repo_settings.portdb
+ self.portdb.settings = self.repo_settings.repoman_settings
+ # We really only need to cache the metadata that's necessary for visibility
+ # filtering. Anything else can be discarded to reduce memory consumption.
+ self.portdb._aux_cache_keys.clear()
+ self.portdb._aux_cache_keys.update(
+ ["EAPI", "IUSE", "KEYWORDS", "repository", "SLOT"])
+
+ self.reposplit = myreporoot.split(os.path.sep)
+ self.repolevel = len(self.reposplit)
+
+ if self.options.mode == 'commit':
+ repochecks.commit_check(self.repolevel, self.reposplit)
+ repochecks.conflict_check(self.vcs_settings, self.options)
+
+ # Make startdir relative to the canonical repodir, so that we can pass
+ # it to digestgen and it won't have to be canonicalized again.
+ if self.repolevel == 1:
+ startdir = self.repo_settings.repodir
+ else:
+ startdir = normalize_path(mydir)
+ startdir = os.path.join(
+ self.repo_settings.repodir, *startdir.split(os.sep)[-2 - self.repolevel + 3:])
+
+ # get lists of valid keywords, licenses, and use
+ new_data = repo_metadata(self.portdb, self.repo_settings.repoman_settings)
+ kwlist, liclist, uselist, profile_list, \
+ global_pmaskdict, liclist_deprecated = new_data
+ self.repo_metadata = {
+ 'kwlist': kwlist,
+ 'liclist': liclist,
+ 'uselist': uselist,
+ 'profile_list': profile_list,
+ 'pmaskdict': global_pmaskdict,
+ 'lic_deprecated': liclist_deprecated,
+ }
+
+ self.repo_settings.repoman_settings['PORTAGE_ARCHLIST'] = ' '.join(sorted(kwlist))
+ self.repo_settings.repoman_settings.backup_changes('PORTAGE_ARCHLIST')
+
+ self.profiles = setup_profile(profile_list)
+
+ check_profiles(self.profiles, self.repo_settings.repoman_settings.archlist())
+
+ scanlist = scan(self.repolevel, self.reposplit, startdir, self.categories, self.repo_settings)
+
+ self.dev_keywords = dev_profile_keywords(self.profiles)
+
+ self.qatracker = QATracker()
+
+ if self.options.echangelog is None and self.repo_settings.repo_config.update_changelog:
+ self.options.echangelog = 'y'
+
+ if self.vcs_settings.vcs is None:
+ self.options.echangelog = 'n'
+
+ self.check = {}
+ # The --echangelog option causes automatic ChangeLog generation,
+ # which invalidates changelog.ebuildadded and changelog.missing
+ # checks.
+ # Note: Some don't use ChangeLogs in distributed SCMs.
+ # It will be generated on server side from scm log,
+ # before package moves to the rsync server.
+ # This is needed because they try to avoid merge collisions.
+ # Gentoo's Council decided to always use the ChangeLog file.
+ # TODO: shouldn't this just be switched on the repo, iso the VCS?
+ is_echangelog_enabled = self.options.echangelog in ('y', 'force')
+ self.vcs_settings.vcs_is_cvs_or_svn = self.vcs_settings.vcs in ('cvs', 'svn')
+ self.check['changelog'] = not is_echangelog_enabled and self.vcs_settings.vcs_is_cvs_or_svn
+
+ if self.options.mode == "manifest":
+ pass
+ elif self.options.pretend:
+ print(green("\nRepoMan does a once-over of the neighborhood..."))
+ else:
+ print(green("\nRepoMan scours the neighborhood..."))
+
+ self.changed = Changes(self.options)
+ self.changed.scan(self.vcs_settings)
+
+ self.have = {
+ 'pmasked': False,
+ 'dev_keywords': False,
+ }
+
+ # NOTE: match-all caches are not shared due to potential
+ # differences between profiles in _get_implicit_iuse.
+ self.caches = {
+ 'arch': {},
+ 'arch_xmatch': {},
+ 'shared_xmatch': {"cp-list": {}},
+ }
+
+ self.include_arches = None
+ if self.options.include_arches:
+ self.include_arches = set()
+ self.include_arches.update(*[x.split() for x in self.options.include_arches])
+
+ # Disable the "ebuild.notadded" check when not in commit mode and
+ # running `svn status` in every package dir will be too expensive.
+ self.check['ebuild_notadded'] = not \
+ (self.vcs_settings.vcs == "svn" and self.repolevel < 3 and self.options.mode != "commit")
+
+ self.effective_scanlist = scanlist
+ if self.options.if_modified == "y":
+ self.effective_scanlist = sorted(vcs_files_to_cps(
+ chain(self.changed.changed, self.changed.new, self.changed.removed),
+ self.repolevel, self.reposplit, self.categories))
+
+ self.live_eclasses = portage.const.LIVE_ECLASSES
+
+ # initialize our checks classes here before the big xpkg loop
+ self.manifester = Manifests(self.options, self.qatracker, self.repo_settings.repoman_settings)
+ self.is_ebuild = IsEbuild(self.repo_settings.repoman_settings, self.repo_settings, self.portdb, self.qatracker)
+ self.filescheck = FileChecks(
+ self.qatracker, self.repo_settings.repoman_settings, self.repo_settings, self.portdb, self.vcs_settings)
+ self.status_check = VCSStatus(self.vcs_settings, self.qatracker)
+ self.fetchcheck = FetchChecks(
+ self.qatracker, self.repo_settings.repoman_settings, self.repo_settings, self.portdb, self.vcs_settings)
+ self.pkgmeta = PkgMetadata(self.options, self.qatracker, self.repo_settings.repoman_settings)
+ self.thirdparty = ThirdPartyMirrors(self.repo_settings.repoman_settings, self.qatracker)
+ self.use_flag_checks = USEFlagChecks(self.qatracker, uselist)
+ self.keywordcheck = KeywordChecks(self.qatracker, self.options)
+ self.liveeclasscheck = LiveEclassChecks(self.qatracker)
+ self.rubyeclasscheck = RubyEclassChecks(self.qatracker)
+ self.eapicheck = EAPIChecks(self.qatracker, self.repo_settings)
+ self.descriptioncheck = DescriptionChecks(self.qatracker)
+ self.licensecheck = LicenseChecks(self.qatracker, liclist, liclist_deprecated)
+ self.restrictcheck = RestrictChecks(self.qatracker)
+
+
+ def scan_pkgs(self, can_force):
+ for xpkg in self.effective_scanlist:
+ # ebuilds and digests added to cvs respectively.
+ logging.info("checking package %s" % xpkg)
+ # save memory by discarding xmatch caches from previous package(s)
+ self.caches['arch_xmatch'].clear()
+ self.eadded = []
+ catdir, pkgdir = xpkg.split("/")
+ checkdir = self.repo_settings.repodir + "/" + xpkg
+ checkdir_relative = ""
+ if self.repolevel < 3:
+ checkdir_relative = os.path.join(pkgdir, checkdir_relative)
+ if self.repolevel < 2:
+ checkdir_relative = os.path.join(catdir, checkdir_relative)
+ checkdir_relative = os.path.join(".", checkdir_relative)
+
+ if self.manifester.run(checkdir, self.portdb):
+ continue
+ if not self.manifester.generated_manifest:
+ self.manifester.digest_check(xpkg, checkdir)
+ if self.options.mode == 'manifest-check':
+ continue
+
+ checkdirlist = os.listdir(checkdir)
+
+ self.pkgs, self.allvalid = self.is_ebuild.check(checkdirlist, checkdir, xpkg)
+ if self.is_ebuild.continue_:
+ # If we can't access all the metadata then it's totally unsafe to
+ # commit since there's no way to generate a correct Manifest.
+ # Do not try to do any more QA checks on this package since missing
+ # metadata leads to false positives for several checks, and false
+ # positives confuse users.
+ can_force = False
+ continue
+
+ self.keywordcheck.prepare()
+
+ # Sort ebuilds in ascending order for the KEYWORDS.dropped check.
+ ebuildlist = sorted(self.pkgs.values())
+ ebuildlist = [pkg.pf for pkg in ebuildlist]
+
+ self.filescheck.check(
+ checkdir, checkdirlist, checkdir_relative, self.changed.changed, self.changed.new)
+
+ self.status_check.check(self.check['ebuild_notadded'], checkdir, checkdir_relative, xpkg)
+ self.eadded.extend(self.status_check.eadded)
+
+ self.fetchcheck.check(
+ xpkg, checkdir, checkdir_relative, self.changed.changed, self.changed.new)
+
+ if self.check['changelog'] and "ChangeLog" not in checkdirlist:
+ self.qatracker.add_error("changelog.missing", xpkg + "/ChangeLog")
+
+ self.pkgmeta.check(xpkg, checkdir, checkdirlist, self.repolevel)
+ self.muselist = frozenset(self.pkgmeta.musedict)
+
+ changelog_path = os.path.join(checkdir_relative, "ChangeLog")
+ self.changelog_modified = changelog_path in self.changed.changelogs
+
+ self._scan_ebuilds(ebuildlist, xpkg, catdir, pkgdir)
+ return self.qatracker, can_force
+
+
+ def _scan_ebuilds(self, ebuildlist, xpkg, catdir, pkgdir):
+ # detect unused local USE-descriptions
+ used_useflags = set()
+
+ for y_ebuild in ebuildlist:
+
+ ebuild = Ebuild(
+ self.repo_settings, self.repolevel, pkgdir, catdir, self.vcs_settings,
+ xpkg, y_ebuild)
+
+ if self.check['changelog'] and not self.changelog_modified \
+ and ebuild.ebuild_path in self.changed.new_ebuilds:
+ self.qatracker.add_error('changelog.ebuildadded', ebuild.relative_path)
+
+ if ebuild.untracked(self.check['ebuild_notadded'], y_ebuild, self.eadded):
+ # ebuild not added to vcs
+ self.qatracker.add_error(
+ "ebuild.notadded", xpkg + "/" + y_ebuild + ".ebuild")
+
+ if bad_split_check(xpkg, y_ebuild, pkgdir, self.qatracker):
+ continue
+
+ pkg = self.pkgs[y_ebuild]
+ if pkg_invalid(pkg, self.qatracker, ebuild):
+ self.allvalid = False
+ continue
+
+ myaux = pkg._metadata
+ eapi = myaux["EAPI"]
+ inherited = pkg.inherited
+ live_ebuild = self.live_eclasses.intersection(inherited)
+
+ self.eapicheck.check(pkg, ebuild)
+
+ for k, v in myaux.items():
+ if not isinstance(v, basestring):
+ continue
+ m = NON_ASCII_RE.search(v)
+ if m is not None:
+ self.qatracker.add_error(
+ "variable.invalidchar",
+ "%s: %s variable contains non-ASCII "
+ "character at position %s" %
+ (ebuild.relative_path, k, m.start() + 1))
+
+ if not self.fetchcheck.src_uri_error:
+ self.thirdparty.check(myaux, ebuild.relative_path)
+
+ if myaux.get("PROVIDE"):
+ self.qatracker.add_error("virtual.oldstyle", ebuild.relative_path)
+
+ for pos, missing_var in enumerate(missingvars):
+ if not myaux.get(missing_var):
+ if catdir == "virtual" and \
+ missing_var in ("HOMEPAGE", "LICENSE"):
+ continue
+ if live_ebuild and missing_var == "KEYWORDS":
+ continue
+ myqakey = missingvars[pos] + ".missing"
+ self.qatracker.add_error(myqakey, xpkg + "/" + y_ebuild + ".ebuild")
+
+ if catdir == "virtual":
+ for var in ("HOMEPAGE", "LICENSE"):
+ if myaux.get(var):
+ myqakey = var + ".virtual"
+ self.qatracker.add_error(myqakey, ebuild.relative_path)
+
+ self.descriptioncheck.check(pkg, ebuild)
+
+ keywords = myaux["KEYWORDS"].split()
+
+ ebuild_archs = set(
+ kw.lstrip("~") for kw in keywords if not kw.startswith("-"))
+
+ self.keywordcheck.check(
+ pkg, xpkg, ebuild, y_ebuild, keywords, ebuild_archs, self.changed,
+ live_ebuild, self.repo_metadata['kwlist'], self.profiles)
+
+ if live_ebuild and self.repo_settings.repo_config.name == "gentoo":
+ self.liveeclasscheck.check(
+ pkg, xpkg, ebuild, y_ebuild, keywords, self.repo_metadata['pmaskdict'])
+
+ if self.options.ignore_arches:
+ arches = [[
+ self.repo_settings.repoman_settings["ARCH"], self.repo_settings.repoman_settings["ARCH"],
+ self.repo_settings.repoman_settings["ACCEPT_KEYWORDS"].split()]]
+ else:
+ arches = set()
+ for keyword in keywords:
+ if keyword[0] == "-":
+ continue
+ elif keyword[0] == "~":
+ arch = keyword[1:]
+ if arch == "*":
+ for expanded_arch in self.profiles:
+ if expanded_arch == "**":
+ continue
+ arches.add(
+ (keyword, expanded_arch, (
+ expanded_arch, "~" + expanded_arch)))
+ else:
+ arches.add((keyword, arch, (arch, keyword)))
+ else:
+ if keyword == "*":
+ for expanded_arch in self.profiles:
+ if expanded_arch == "**":
+ continue
+ arches.add(
+ (keyword, expanded_arch, (expanded_arch,)))
+ else:
+ arches.add((keyword, keyword, (keyword,)))
+ if not arches:
+ # Use an empty profile for checking dependencies of
+ # packages that have empty KEYWORDS.
+ arches.add(('**', '**', ('**',)))
+
+ unknown_pkgs = set()
+ baddepsyntax = False
+ badlicsyntax = False
+ badprovsyntax = False
+ # catpkg = catdir + "/" + y_ebuild
+
+ inherited_java_eclass = "java-pkg-2" in inherited or \
+ "java-pkg-opt-2" in inherited
+ inherited_wxwidgets_eclass = "wxwidgets" in inherited
+ # operator_tokens = set(["||", "(", ")"])
+ type_list, badsyntax = [], []
+ for mytype in Package._dep_keys + ("LICENSE", "PROPERTIES", "PROVIDE"):
+ mydepstr = myaux[mytype]
+
+ buildtime = mytype in Package._buildtime_keys
+ runtime = mytype in Package._runtime_keys
+ token_class = None
+ if mytype.endswith("DEPEND"):
+ token_class = portage.dep.Atom
+
+ try:
+ atoms = portage.dep.use_reduce(
+ mydepstr, matchall=1, flat=True,
+ is_valid_flag=pkg.iuse.is_valid_flag, token_class=token_class)
+ except portage.exception.InvalidDependString as e:
+ atoms = None
+ badsyntax.append(str(e))
+
+ if atoms and mytype.endswith("DEPEND"):
+ if runtime and \
+ "test?" in mydepstr.split():
+ self.qatracker.add_error(
+ mytype + '.suspect',
+ "%s: 'test?' USE conditional in %s" %
+ (ebuild.relative_path, mytype))
+
+ for atom in atoms:
+ if atom == "||":
+ continue
+
+ is_blocker = atom.blocker
+
+ # Skip dependency.unknown for blockers, so that we
+ # don't encourage people to remove necessary blockers,
+ # as discussed in bug 382407. We use atom.without_use
+ # due to bug 525376.
+ if not is_blocker and \
+ not self.portdb.xmatch("match-all", atom.without_use) and \
+ not atom.cp.startswith("virtual/"):
+ unknown_pkgs.add((mytype, atom.unevaluated_atom))
+
+ if catdir != "virtual":
+ if not is_blocker and \
+ atom.cp in suspect_virtual:
+ self.qatracker.add_error(
+ 'virtual.suspect', ebuild.relative_path +
+ ": %s: consider using '%s' instead of '%s'" %
+ (mytype, suspect_virtual[atom.cp], atom))
+ if not is_blocker and \
+ atom.cp.startswith("perl-core/"):
+ self.qatracker.add_error('dependency.perlcore',
+ ebuild.relative_path +
+ ": %s: please use '%s' instead of '%s'" %
+ (mytype,
+ atom.replace("perl-core/","virtual/perl-"),
+ atom))
+
+ if buildtime and \
+ not is_blocker and \
+ not inherited_java_eclass and \
+ atom.cp == "virtual/jdk":
+ self.qatracker.add_error(
+ 'java.eclassesnotused', ebuild.relative_path)
+ elif buildtime and \
+ not is_blocker and \
+ not inherited_wxwidgets_eclass and \
+ atom.cp == "x11-libs/wxGTK":
+ self.qatracker.add_error(
+ 'wxwidgets.eclassnotused',
+ "%s: %ss on x11-libs/wxGTK without inheriting"
+ " wxwidgets.eclass" % (ebuild.relative_path, mytype))
+ elif runtime:
+ if not is_blocker and \
+ atom.cp in suspect_rdepend:
+ self.qatracker.add_error(
+ mytype + '.suspect',
+ ebuild.relative_path + ": '%s'" % atom)
+
+ if atom.operator == "~" and \
+ portage.versions.catpkgsplit(atom.cpv)[3] != "r0":
+ qacat = 'dependency.badtilde'
+ self.qatracker.add_error(
+ qacat, "%s: %s uses the ~ operator"
+ " with a non-zero revision: '%s'" %
+ (ebuild.relative_path, mytype, atom))
+
+ check_missingslot(atom, mytype, eapi, self.portdb, self.qatracker,
+ ebuild.relative_path, myaux)
+
+ type_list.extend([mytype] * (len(badsyntax) - len(type_list)))
+
+ for m, b in zip(type_list, badsyntax):
+ if m.endswith("DEPEND"):
+ qacat = "dependency.syntax"
+ else:
+ qacat = m + ".syntax"
+ self.qatracker.add_error(
+ qacat, "%s: %s: %s" % (ebuild.relative_path, m, b))
+
+ badlicsyntax = len([z for z in type_list if z == "LICENSE"])
+ badprovsyntax = len([z for z in type_list if z == "PROVIDE"])
+ baddepsyntax = len(type_list) != badlicsyntax + badprovsyntax
+ badlicsyntax = badlicsyntax > 0
+ badprovsyntax = badprovsyntax > 0
+
+ self.use_flag_checks.check(pkg, xpkg, ebuild, y_ebuild, self.muselist)
+
+ ebuild_used_useflags = self.use_flag_checks.getUsedUseFlags()
+ used_useflags = used_useflags.union(ebuild_used_useflags)
+
+ self.rubyeclasscheck.check(pkg, ebuild)
+
+ # license checks
+ if not badlicsyntax:
+ self.licensecheck.check(pkg, xpkg, ebuild, y_ebuild)
+
+ self.restrictcheck.check(pkg, xpkg, ebuild, y_ebuild)
+
+ # Syntax Checks
+ if not self.vcs_settings.vcs_preserves_mtime:
+ if ebuild.ebuild_path not in self.changed.new_ebuilds and \
+ ebuild.ebuild_path not in self.changed.ebuilds:
+ pkg.mtime = None
+ try:
+ # All ebuilds should have utf_8 encoding.
+ f = io.open(
+ _unicode_encode(
+ ebuild.full_path, encoding=_encodings['fs'], errors='strict'),
+ mode='r', encoding=_encodings['repo.content'])
+ try:
+ for check_name, e in run_checks(f, pkg):
+ self.qatracker.add_error(
+ check_name, ebuild.relative_path + ': %s' % e)
+ finally:
+ f.close()
+ except UnicodeDecodeError:
+ # A file.UTF8 failure will have already been recorded above.
+ pass
+
+ if self.options.force:
+ # The dep_check() calls are the most expensive QA test. If --force
+ # is enabled, there's no point in wasting time on these since the
+ # user is intent on forcing the commit anyway.
+ continue
+
+ relevant_profiles = []
+ for keyword, arch, groups in arches:
+ if arch not in self.profiles:
+ # A missing profile will create an error further down
+ # during the KEYWORDS verification.
+ continue
+
+ if self.include_arches is not None:
+ if arch not in self.include_arches:
+ continue
+
+ relevant_profiles.extend(
+ (keyword, groups, prof) for prof in self.profiles[arch])
+
+ relevant_profiles.sort(key=sort_key)
+
+ for keyword, groups, prof in relevant_profiles:
+
+ is_stable_profile = prof.status == "stable"
+ is_dev_profile = prof.status == "dev" and \
+ self.options.include_dev
+ is_exp_profile = prof.status == "exp" and \
+ self.options.include_exp_profiles == 'y'
+ if not (is_stable_profile or is_dev_profile or is_exp_profile):
+ continue
+
+ dep_settings = self.caches['arch'].get(prof.sub_path)
+ if dep_settings is None:
+ dep_settings = portage.config(
+ config_profile_path=prof.abs_path,
+ config_incrementals=self.repoman_incrementals,
+ config_root=self.config_root,
+ local_config=False,
+ _unmatched_removal=self.options.unmatched_removal,
+ env=self.env, repositories=self.repo_settings.repoman_settings.repositories)
+ dep_settings.categories = self.repo_settings.repoman_settings.categories
+ if self.options.without_mask:
+ dep_settings._mask_manager_obj = \
+ copy.deepcopy(dep_settings._mask_manager)
+ dep_settings._mask_manager._pmaskdict.clear()
+ self.caches['arch'][prof.sub_path] = dep_settings
+
+ xmatch_cache_key = (prof.sub_path, tuple(groups))
+ xcache = self.caches['arch_xmatch'].get(xmatch_cache_key)
+ if xcache is None:
+ self.portdb.melt()
+ self.portdb.freeze()
+ xcache = self.portdb.xcache
+ xcache.update(self.caches['shared_xmatch'])
+ self.caches['arch_xmatch'][xmatch_cache_key] = xcache
+
+ self.repo_settings.trees[self.repo_settings.root]["porttree"].settings = dep_settings
+ self.portdb.settings = dep_settings
+ self.portdb.xcache = xcache
+
+ dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups)
+ # just in case, prevent config.reset() from nuking these.
+ dep_settings.backup_changes("ACCEPT_KEYWORDS")
+
+ # This attribute is used in dbapi._match_use() to apply
+ # use.stable.{mask,force} settings based on the stable
+ # status of the parent package. This is required in order
+ # for USE deps of unstable packages to be resolved correctly,
+ # since otherwise use.stable.{mask,force} settings of
+ # dependencies may conflict (see bug #456342).
+ dep_settings._parent_stable = dep_settings._isStable(pkg)
+
+ # Handle package.use*.{force,mask) calculation, for use
+ # in dep_check.
+ dep_settings.useforce = dep_settings._use_manager.getUseForce(
+ pkg, stable=dep_settings._parent_stable)
+ dep_settings.usemask = dep_settings._use_manager.getUseMask(
+ pkg, stable=dep_settings._parent_stable)
+
+ if not baddepsyntax:
+ ismasked = not ebuild_archs or \
+ pkg.cpv not in self.portdb.xmatch("match-visible",
+ Atom("%s::%s" % (pkg.cp, self.repo_settings.repo_config.name)))
+ if ismasked:
+ if not self.have['pmasked']:
+ self.have['pmasked'] = bool(dep_settings._getMaskAtom(
+ pkg.cpv, pkg._metadata))
+ if self.options.ignore_masked:
+ continue
+ # we are testing deps for a masked package; give it some lee-way
+ suffix = "masked"
+ matchmode = "minimum-all"
+ else:
+ suffix = ""
+ matchmode = "minimum-visible"
+
+ if not self.have['dev_keywords']:
+ self.have['dev_keywords'] = \
+ bool(self.dev_keywords.intersection(keywords))
+
+ if prof.status == "dev":
+ suffix = suffix + "indev"
+
+ for mytype in Package._dep_keys:
+
+ mykey = "dependency.bad" + suffix
+ myvalue = myaux[mytype]
+ if not myvalue:
+ continue
+
+ success, atoms = portage.dep_check(
+ myvalue, self.portdb, dep_settings,
+ use="all", mode=matchmode, trees=self.repo_settings.trees)
+
+ if success:
+ if atoms:
+
+ # Don't bother with dependency.unknown for
+ # cases in which *DEPEND.bad is triggered.
+ for atom in atoms:
+ # dep_check returns all blockers and they
+ # aren't counted for *DEPEND.bad, so we
+ # ignore them here.
+ if not atom.blocker:
+ unknown_pkgs.discard(
+ (mytype, atom.unevaluated_atom))
+
+ if not prof.sub_path:
+ # old-style virtuals currently aren't
+ # resolvable with empty profile, since
+ # 'virtuals' mappings are unavailable
+ # (it would be expensive to search
+ # for PROVIDE in all ebuilds)
+ atoms = [
+ atom for atom in atoms if not (
+ atom.cp.startswith('virtual/')
+ and not self.portdb.cp_list(atom.cp))]
+
+ # we have some unsolvable deps
+ # remove ! deps, which always show up as unsatisfiable
+ atoms = [
+ str(atom.unevaluated_atom)
+ for atom in atoms if not atom.blocker]
+
+ # if we emptied out our list, continue:
+ if not atoms:
+ continue
+ self.qatracker.add_error(mykey,
+ "%s: %s: %s(%s)\n%s"
+ % (ebuild.relative_path, mytype, keyword, prof,
+ pformat(atoms, indent=6)))
+ else:
+ self.qatracker.add_error(mykey,
+ "%s: %s: %s(%s)\n%s"
+ % (ebuild.relative_path, mytype, keyword, prof,
+ pformat(atoms, indent=6)))
+
+ if not baddepsyntax and unknown_pkgs:
+ type_map = {}
+ for mytype, atom in unknown_pkgs:
+ type_map.setdefault(mytype, set()).add(atom)
+ for mytype, atoms in type_map.items():
+ self.qatracker.add_error(
+ "dependency.unknown", "%s: %s: %s"
+ % (ebuild.relative_path, mytype, ", ".join(sorted(atoms))))
+
+ # check if there are unused local USE-descriptions in metadata.xml
+ # (unless there are any invalids, to avoid noise)
+ if self.allvalid:
+ for myflag in self.muselist.difference(used_useflags):
+ self.qatracker.add_error(
+ "metadata.warning",
+ "%s/metadata.xml: unused local USE-description: '%s'"
+ % (xpkg, myflag))
next reply other threads:[~2015-09-21 23:51 UTC|newest]
Thread overview: 217+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-21 23:47 Brian Dolbec [this message]
2015-09-21 23:51 ` [gentoo-commits] proj/portage:master commit in: pym/repoman/ Brian Dolbec
-- strict thread matches above, loose matches on Subject: below --
2016-05-03 9:33 [gentoo-commits] proj/portage:repoman " Brian Dolbec
2016-04-29 17:24 [gentoo-commits] proj/portage:master " Brian Dolbec
2016-04-28 15:05 ` [gentoo-commits] proj/portage:repoman " Brian Dolbec
2016-04-29 17:24 [gentoo-commits] proj/portage:master " Brian Dolbec
2016-04-28 15:05 ` [gentoo-commits] proj/portage:repoman " Brian Dolbec
2016-04-29 17:24 [gentoo-commits] proj/portage:master " Brian Dolbec
2016-04-26 14:47 ` [gentoo-commits] proj/portage:repoman " Brian Dolbec
2016-04-28 15:05 Brian Dolbec
2016-04-27 5:22 Brian Dolbec
2016-04-27 5:22 Brian Dolbec
2016-04-27 5:22 Brian Dolbec
2016-04-26 18:08 Zac Medico
2016-04-25 15:32 Brian Dolbec
2016-04-25 15:32 Brian Dolbec
2016-04-25 15:32 Brian Dolbec
2016-04-21 16:54 Brian Dolbec
2016-04-21 16:54 Brian Dolbec
2016-04-21 16:54 Brian Dolbec
2016-04-21 16:54 Brian Dolbec
2016-04-17 15:42 Brian Dolbec
2016-04-16 20:00 Zac Medico
2016-03-15 19:00 Brian Dolbec
2016-03-12 18:10 Brian Dolbec
2016-03-12 18:10 Brian Dolbec
2016-03-12 18:10 Brian Dolbec
2016-03-11 0:41 Brian Dolbec
2016-03-11 0:41 Brian Dolbec
2016-03-11 0:41 Brian Dolbec
2016-03-07 21:53 Brian Dolbec
2016-03-07 21:53 Brian Dolbec
2016-03-07 21:53 Brian Dolbec
2016-02-01 7:55 Zac Medico
2016-02-01 7:21 Zac Medico
2016-01-31 20:03 Brian Dolbec
2016-01-31 20:03 Brian Dolbec
2016-01-31 20:03 Brian Dolbec
2016-01-30 8:00 Brian Dolbec
2016-01-30 8:00 Brian Dolbec
2016-01-30 8:00 Brian Dolbec
2016-01-30 6:58 Brian Dolbec
2016-01-30 6:58 Brian Dolbec
2016-01-30 6:58 Brian Dolbec
2016-01-29 5:01 Brian Dolbec
2016-01-29 5:01 Brian Dolbec
2016-01-29 5:01 Brian Dolbec
2016-01-27 23:15 Brian Dolbec
2016-01-27 23:15 Brian Dolbec
2016-01-27 23:15 Brian Dolbec
2016-01-23 1:42 Brian Dolbec
2016-01-23 1:42 Brian Dolbec
2016-01-23 1:42 Brian Dolbec
2016-01-22 20:55 Brian Dolbec
2016-01-22 20:55 Brian Dolbec
2016-01-22 20:55 Brian Dolbec
2016-01-21 19:42 Brian Dolbec
2016-01-21 19:42 Brian Dolbec
2016-01-21 19:15 Brian Dolbec
2016-01-21 18:30 Brian Dolbec
2016-01-21 18:30 Brian Dolbec
2016-01-18 19:23 Brian Dolbec
2016-01-18 19:23 Brian Dolbec
2016-01-11 8:01 Brian Dolbec
2016-01-11 8:01 Brian Dolbec
2016-01-11 6:31 Brian Dolbec
2016-01-11 6:31 Brian Dolbec
2016-01-11 6:31 Brian Dolbec
2016-01-10 20:17 Brian Dolbec
2016-01-10 20:17 Brian Dolbec
2016-01-10 20:17 Brian Dolbec
2016-01-10 3:26 Brian Dolbec
2016-01-10 3:26 Brian Dolbec
2016-01-10 3:26 Brian Dolbec
2016-01-06 4:21 Brian Dolbec
2016-01-06 4:21 Brian Dolbec
2015-12-30 23:38 Brian Dolbec
2015-09-21 23:51 [gentoo-commits] proj/portage:master " Brian Dolbec
2015-09-21 23:47 ` [gentoo-commits] proj/portage:repoman " Brian Dolbec
2015-09-21 23:51 [gentoo-commits] proj/portage:master " Brian Dolbec
2015-09-21 23:47 ` [gentoo-commits] proj/portage:repoman " Brian Dolbec
2015-09-21 23:51 [gentoo-commits] proj/portage:master " Brian Dolbec
2015-09-21 23:47 ` [gentoo-commits] proj/portage:repoman " Brian Dolbec
2015-09-21 23:51 [gentoo-commits] proj/portage:master " Brian Dolbec
2015-09-21 23:47 ` [gentoo-commits] proj/portage:repoman " Brian Dolbec
2015-09-21 23:51 [gentoo-commits] proj/portage:master " Brian Dolbec
2015-09-21 23:47 ` [gentoo-commits] proj/portage:repoman " Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-21 23:47 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 2:06 Brian Dolbec
2015-09-20 0:20 Brian Dolbec
2015-09-19 17:32 Brian Dolbec
2015-09-19 16:48 Brian Dolbec
2015-09-19 16:28 Brian Dolbec
2015-09-19 16:28 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 4:36 Brian Dolbec
2015-09-19 1:22 Brian Dolbec
2015-09-19 1:22 Brian Dolbec
2015-09-17 18:58 Brian Dolbec
2015-09-17 18:58 Brian Dolbec
2015-09-17 15:32 Brian Dolbec
2015-09-17 4:51 Brian Dolbec
2015-09-17 4:51 Brian Dolbec
2015-09-17 4:51 Brian Dolbec
2015-09-17 4:51 Brian Dolbec
2015-09-17 4:51 Brian Dolbec
2015-09-17 4:51 Brian Dolbec
2015-09-17 4:51 Brian Dolbec
2015-09-17 4:51 Brian Dolbec
2015-09-17 4:51 Brian Dolbec
2015-09-17 3:08 Brian Dolbec
2015-09-17 3:08 Brian Dolbec
2015-09-17 3:08 Brian Dolbec
2015-09-17 3:08 Brian Dolbec
2015-09-17 3:08 Brian Dolbec
2015-09-17 3:08 Brian Dolbec
2015-09-17 3:08 Brian Dolbec
2015-09-17 3:08 Brian Dolbec
2015-09-17 3:08 Brian Dolbec
2015-09-17 2:45 Brian Dolbec
2015-09-17 2:45 Brian Dolbec
2015-09-17 2:45 Brian Dolbec
2015-09-05 21:48 Brian Dolbec
2015-09-05 21:48 Brian Dolbec
2015-09-05 21:48 Brian Dolbec
2015-09-05 21:48 Brian Dolbec
2015-09-05 21:48 Brian Dolbec
2015-09-05 21:48 Brian Dolbec
2015-09-05 21:27 Brian Dolbec
2015-09-05 21:27 Brian Dolbec
2015-09-05 21:27 Brian Dolbec
2015-09-05 21:27 Brian Dolbec
2015-09-05 21:27 Brian Dolbec
2015-09-05 21:27 Brian Dolbec
2015-08-11 23:54 Brian Dolbec
2015-08-11 23:54 Brian Dolbec
2015-08-11 23:54 Brian Dolbec
2015-08-11 23:54 Brian Dolbec
2015-08-11 23:54 Brian Dolbec
2015-08-11 23:54 Brian Dolbec
2015-08-10 14:45 Michał Górny
2015-08-10 14:45 Michał Górny
2015-08-10 14:45 Michał Górny
2015-08-10 14:45 Michał Górny
2015-08-10 14:45 Michał Górny
2015-08-10 14:45 Michał Górny
2015-08-10 13:44 Brian Dolbec
2015-08-10 13:44 Brian Dolbec
2015-08-10 13:44 Brian Dolbec
2015-08-10 13:44 Brian Dolbec
2015-08-10 13:44 Brian Dolbec
2015-08-10 13:44 Brian Dolbec
2014-11-17 2:08 Brian Dolbec
2014-11-17 0:55 Brian Dolbec
2014-11-17 0:55 Brian Dolbec
2014-11-17 0:55 Brian Dolbec
2014-11-17 0:55 Brian Dolbec
2014-11-17 0:55 Brian Dolbec
2014-10-01 23:46 Brian Dolbec
2014-10-01 23:46 Brian Dolbec
2014-10-01 23:46 Brian Dolbec
2014-10-01 23:46 Brian Dolbec
2014-10-01 23:46 Brian Dolbec
2014-10-01 23:02 Brian Dolbec
2014-10-01 23:02 Brian Dolbec
2014-10-01 23:02 Brian Dolbec
2014-10-01 23:02 Brian Dolbec
2014-10-01 23:02 Brian Dolbec
2014-06-03 19:33 Brian Dolbec
2014-06-03 18:15 Brian Dolbec
2014-06-03 18:15 Brian Dolbec
2014-06-03 11:29 Tom Wijsman
2014-06-02 17:01 Tom Wijsman
2014-06-02 15:44 Brian Dolbec
2014-06-02 15:44 Brian Dolbec
2014-06-02 15:44 Brian Dolbec
2014-06-02 15:01 Tom Wijsman
2014-06-02 14:24 Brian Dolbec
2014-06-02 14:11 Tom Wijsman
2014-06-02 1:10 Brian Dolbec
2014-06-02 1:10 Brian Dolbec
2014-05-30 13:03 Brian Dolbec
2014-05-30 13:03 Brian Dolbec
2014-05-30 13:03 Brian Dolbec
2014-05-27 6:04 Brian Dolbec
2014-05-27 6:04 Brian Dolbec
2014-05-27 6:04 Brian Dolbec
2014-05-27 6:04 Brian Dolbec
2014-05-27 5:04 Brian Dolbec
2014-05-27 5:04 Brian Dolbec
2014-05-27 5:04 Brian Dolbec
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1442878966.9f63c395ee23b00d77d00e667a28624de5baff49.dolsen@gentoo \
--to=dolsen@gentoo.org \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox