Exemple #1
0
def _setup_shared_opts(namespace):
    namespace.exclude_restrict = None
    exclude_restrictions = []

    if namespace.pkgsets:
        disabled, enabled = namespace.pkgsets
        unknown_sets = set(disabled + enabled).difference(
            namespace.config.pkgset)
        if unknown_sets:
            argparser.error("unknown set%s: %s (available sets: %s)" %
                            (pluralism(unknown_sets), ', '.join(
                                sorted(map(repr, unknown_sets))), ', '.join(
                                    sorted(namespace.config.pkgset))))
        for s in set(disabled):
            exclude_restrictions.extend(namespace.config.pkgset[s])
        for s in set(enabled):
            namespace.restrict.append(
                boolean.OrRestriction(*namespace.config.pkgset[s]))

    # handle command line and file excludes
    excludes = namespace.excludes if namespace.excludes is not None else []
    if namespace.exclude_file is not None:
        excludes.extend(namespace.exclude_file.read().split('\n'))
    if excludes:
        exclude_restrictions.extend(convert_to_restrict(excludes,
                                                        default=None))

    if exclude_restrictions:
        namespace.restrict.append(
            boolean.OrRestriction(negate=True, *exclude_restrictions))
        namespace.exclude_restrict = boolean.OrRestriction(
            *exclude_restrictions)
Exemple #2
0
def _setup_restrictions(namespace, attr):
    repo = namespace.domain.all_repos
    target_restrictions = []

    # If no targets are passed, create a restriction from the current working
    # directory if inside a known repo.
    cwd = os.getcwd()
    if not namespace.targets and cwd in repo:
        namespace.targets = [cwd]

    for target in namespace.targets:
        try:
            target_restrictions.append(parserestrict.parse_match(target))
        except parserestrict.ParseError as e:
            if os.path.exists(target):
                try:
                    restrict = repo.path_restrict(target)
                    # toss the repo restriction, keep the rest
                    target_restrictions.append(
                        boolean.AndRestriction(*restrict[1:]))
                except ValueError as e:
                    argparser.error(e)
            else:
                argparser.error(e)

    if target_restrictions:
        namespace.restrict.append(boolean.OrRestriction(*target_restrictions))
    if namespace.restrict:
        namespace.restrict = boolean.AndRestriction(*namespace.restrict)
Exemple #3
0
 def test_dnf_solutions(self):
     assert self.kls(true, true).dnf_solutions() == [[true, true]]
     assert self.kls(self.kls(true, true), true).dnf_solutions() == [[true, true, true]]
     assert (list(map(set, self.kls(
                 true, true,
                 boolean.OrRestriction(false, true)).dnf_solutions())) ==
         [set([true, true, false]), set([true, true, true])])
     assert self.kls().dnf_solutions() == [[]]
Exemple #4
0
 def test_cnf_solutions(self):
     assert self.kls(true, true).cnf_solutions() == [[true], [true]]
     assert self.kls(self.kls(true, true), true).cnf_solutions() == [[true], [true], [true]]
     assert (list(self.kls(
                 true, true,
                 boolean.OrRestriction(false, true)).cnf_solutions()) ==
         list([[true], [true], [false, true]]))
     assert self.kls().cnf_solutions() == []
Exemple #5
0
def _setup_shared_opts(namespace, attr):
    # handle command line and file excludes
    excludes = namespace.excludes if namespace.excludes is not None else []
    if namespace.exclude_file is not None:
        excludes.extend(namespace.exclude_file.read().split('\n'))
    exclude_restrictions = commandline.convert_to_restrict(excludes, default=None)

    if exclude_restrictions != [None]:
        namespace.restrict.append(
            boolean.OrRestriction(negate=True, *exclude_restrictions))
Exemple #6
0
 def test_cnf_solutions(self):
     self.assertEqual(
         self.kls(true, true).cnf_solutions(), [[true], [true]])
     self.assertEqual(
         self.kls(self.kls(true, true), true).cnf_solutions(),
         [[true], [true], [true]])
     self.assertEqual(
         list(
             self.kls(true, true,
                      boolean.OrRestriction(false, true)).cnf_solutions()),
         list([[true], [true], [false, true]]))
     self.assertEqual(self.kls().cnf_solutions(), [])
Exemple #7
0
 def test_dnf_solutions(self):
     self.assertEqual(self.kls(true, true).dnf_solutions(), [[true, true]])
     self.assertEqual(
         self.kls(self.kls(true, true), true).dnf_solutions(),
         [[true, true, true]])
     self.assertEqual(
         map(
             set,
             self.kls(true, true,
                      boolean.OrRestriction(false, true)).dnf_solutions()),
         [set([true, true, false]),
          set([true, true, true])])
     self.assertEqual(self.kls().dnf_solutions(), [[]])
Exemple #8
0
    def test_identify_candidates(self):
        with pytest.raises(TypeError):
            self.repo.match("asdf")
        rc = packages.PackageRestriction("category",
                                         values.StrExactMatch("dev-util"))
        assert \
            sorted(set(x.package for x in self.repo.itermatch(rc))) == \
            sorted(["diffball", "bsdiff"])
        rp = packages.PackageRestriction("package",
                                         values.StrExactMatch("diffball"))
        assert list(
            x.version
            for x in self.repo.itermatch(rp, sorter=sorted)) == ["0.7", "1.0"]
        assert \
            self.repo.match(packages.OrRestriction(rc, rp), sorter=sorted) == \
            sorted(VersionedCPV(x) for x in (
                "dev-util/diffball-0.7", "dev-util/diffball-1.0",
                "dev-util/bsdiff-0.4.1", "dev-util/bsdiff-0.4.2"))
        assert \
            sorted(self.repo.itermatch(packages.AndRestriction(rc, rp))) == \
            sorted(VersionedCPV(x) for x in (
                "dev-util/diffball-0.7", "dev-util/diffball-1.0"))
        assert sorted(self.repo) == self.repo.match(packages.AlwaysTrue,
                                                    sorter=sorted)
        # mix/match cat/pkg to check that it handles that corner case
        # properly for sorting.
        assert \
            sorted(self.repo, reverse=True) == \
            self.repo.match(packages.OrRestriction(
                rc, rp, packages.AlwaysTrue),
                sorter=partial(sorted, reverse=True))
        rc2 = packages.PackageRestriction("category",
                                          values.StrExactMatch("dev-lib"))
        assert sorted(self.repo.itermatch(packages.AndRestriction(rp,
                                                                  rc2))) == []

        # note this mixes a category level match, and a pkg level
        # match. they *must* be treated as an or.
        assert \
            sorted(self.repo.itermatch(packages.OrRestriction(rp, rc2))) == \
            sorted(VersionedCPV(x) for x in (
                "dev-util/diffball-0.7", "dev-util/diffball-1.0",
                "dev-lib/fake-1.0", "dev-lib/fake-1.0-r1"))

        # this is similar to the test above, but mixes a cat/pkg
        # candidate with a pkg candidate
        rp2 = packages.PackageRestriction("package",
                                          values.StrExactMatch("fake"))
        r = packages.OrRestriction(atom("dev-util/diffball"), rp2)
        assert \
            sorted(self.repo.itermatch(r)) == \
            sorted(VersionedCPV(x) for x in (
                "dev-util/diffball-0.7", "dev-util/diffball-1.0",
                "dev-lib/fake-1.0", "dev-lib/fake-1.0-r1"))

        assert \
            sorted(self.repo.itermatch(
                packages.OrRestriction(packages.AlwaysTrue, rp2))) == \
            sorted(VersionedCPV(x) for x in (
                "dev-util/diffball-0.7", "dev-util/diffball-1.0",
                "dev-util/bsdiff-0.4.1", "dev-util/bsdiff-0.4.2",
                "dev-lib/fake-1.0", "dev-lib/fake-1.0-r1"))

        assert \
            sorted(self.repo.itermatch(packages.PackageRestriction(
                'category', values.StrExactMatch('dev-util', negate=True)))) == \
            sorted(VersionedCPV(x) for x in ("dev-lib/fake-1.0", "dev-lib/fake-1.0-r1"))

        obj = malleable_obj(livefs=False)
        pkg_cls = post_curry(MutatedPkg, {'repo': obj})
        assert \
            sorted(self.repo.itermatch(boolean.AndRestriction(boolean.OrRestriction(
                packages.PackageRestriction(
                    "repo.livefs", values.EqualityMatch(False)),
                packages.PackageRestriction(
                    "category", values.StrExactMatch("virtual"))),
                atom("dev-lib/fake")),
                pkg_cls=pkg_cls)) == \
            sorted(VersionedCPV(x) for x in (
                "dev-lib/fake-1.0", "dev-lib/fake-1.0-r1"))

        assert \
            sorted(self.repo.itermatch(packages.PackageRestriction(
                'category', values.StrExactMatch('dev-lib', negate=True),
                negate=True))) == \
            sorted(VersionedCPV(x) for x in (
                "dev-lib/fake-1.0", "dev-lib/fake-1.0-r1"))

        assert \
            sorted(self.repo.itermatch(packages.PackageRestriction(
                'category', values.StrExactMatch('dev-lib', negate=True), negate=True))) == \
            sorted(VersionedCPV(x) for x in (
                "dev-lib/fake-1.0", "dev-lib/fake-1.0-r1"))
Exemple #9
0
def _validate_scan_args(parser, namespace):
    cwd_in_repo = namespace.cwd in namespace.target_repo

    if namespace.targets:
        repo = namespace.target_repo

        # read targets from stdin in a non-blocking manner
        if len(namespace.targets) == 1 and namespace.targets[0] == '-':

            def stdin():
                while True:
                    line = sys.stdin.readline()
                    if not line:
                        break
                    yield line.rstrip()

            namespace.targets = stdin()

        def restrictions():
            for target in namespace.targets:
                if os.path.isabs(target) or (os.path.exists(target)
                                             and cwd_in_repo):
                    # try to use target as a path restrict if it exists on the filesystem
                    try:
                        scope, restrict = _path_restrict(target, namespace)
                    except ValueError as e:
                        parser.error(e)
                else:
                    # otherwise assume it's a package restriction of some type
                    try:
                        restrict = parserestrict.parse_match(target)
                        scope = _restrict_to_scope(restrict)
                    except parserestrict.ParseError as e:
                        parser.error(e)
                yield scope, restrict

        # Collapse restrictions for passed in targets while keeping the
        # generator intact for piped in targets.
        namespace.restrictions = restrictions()
        if isinstance(namespace.targets, list):
            namespace.restrictions = list(namespace.restrictions)

            # collapse restrictions in order to run them in parallel
            if len(namespace.restrictions) > 1:
                # multiple targets are restricted to a single scanning scope
                scopes = {scope for scope, restrict in namespace.restrictions}
                if len(scopes) > 1:
                    scan_scopes = ', '.join(sorted(map(str, scopes)))
                    parser.error(
                        f'targets specify multiple scan scope levels: {scan_scopes}'
                    )

                combined_restrict = boolean.OrRestriction(
                    *(r for s, r in namespace.restrictions))
                namespace.restrictions = [(scopes.pop(), combined_restrict)]
    else:
        if cwd_in_repo:
            scope, restrict = _path_restrict(namespace.cwd, namespace)
        else:
            restrict = packages.AlwaysTrue
            scope = base.repo_scope
        namespace.restrictions = [(scope, restrict)]

    # determine enabled checks and keywords
    namespace.enabled_checks = set()
    namespace.disabled_keywords = set()
    namespace.enabled_keywords = set()

    # selected scopes
    if namespace.selected_scopes is not None:
        namespace.disabled_keywords |= {
            k
            for k in objects.KEYWORDS.values()
            if k.scope in namespace.selected_scopes[0]
        }
        namespace.enabled_keywords |= {
            k
            for k in objects.KEYWORDS.values()
            if k.scope in namespace.selected_scopes[1]
        }

    # selected checks
    if namespace.selected_checks is not None:
        if namespace.selected_checks[1]:
            namespace.enabled_checks |= {
                objects.CHECKS[c]
                for c in namespace.selected_checks[1]
            }
        elif namespace.selected_checks[0]:
            # only specifying disabled checks enables all checks by default and removes selected checks
            namespace.enabled_checks = (
                set(objects.CHECKS.values()) -
                {objects.CHECKS[c]
                 for c in namespace.selected_checks[0]})

    # selected keywords
    if namespace.selected_keywords is not None:
        namespace.disabled_keywords |= {
            objects.KEYWORDS[k]
            for k in namespace.selected_keywords[0]
        }
        namespace.enabled_keywords |= {
            objects.KEYWORDS[k]
            for k in namespace.selected_keywords[1]
        }

    # determine keywords to filter
    namespace.filtered_keywords = None
    if namespace.enabled_keywords or namespace.disabled_keywords:
        # all keywords are selected by default
        if not namespace.enabled_keywords:
            namespace.enabled_keywords = set(objects.KEYWORDS.values())

        # translate requested keywords to their actual classes
        namespace.filtered_keywords = {}
        for keyword in namespace.enabled_keywords - namespace.disabled_keywords:
            for check in objects.CHECKS.values():
                for result in check.known_results:
                    if issubclass(result, keyword):
                        namespace.filtered_keywords[result] = check

        # only enable checks for the requested keywords
        if not namespace.enabled_checks:
            namespace.enabled_checks = frozenset(
                namespace.filtered_keywords.values())
        namespace.filtered_keywords = frozenset(namespace.filtered_keywords)

    # all checks are run by default
    if not namespace.enabled_checks:
        namespace.enabled_checks = list(objects.CHECKS.values())

    # skip checks that may be disabled
    namespace.enabled_checks = [
        c for c in namespace.enabled_checks if not c.skip(namespace)
    ]

    # only run version scope checks when using a package filter
    if namespace.filter is not None:
        namespace.enabled_checks = [
            c for c in namespace.enabled_checks
            if c.scope is base.version_scope
        ]

    if not namespace.enabled_checks:
        parser.error('no active checks')

    namespace.addons = set()

    for check in namespace.enabled_checks:
        add_addon(check, namespace.addons)
    try:
        for addon in namespace.addons:
            addon.check_args(parser, namespace)
    except argparse.ArgumentError as e:
        if namespace.debug:
            raise
        parser.error(str(e))
Exemple #10
0
def _validate_scan_args(parser, namespace):
    namespace.enabled_checks = list(const.CHECKS.values())
    namespace.enabled_keywords = list(const.KEYWORDS.values())

    # Get the current working directory for repo detection and restriction
    # creation, fallback to the root dir if it's be removed out from under us.
    try:
        cwd = abspath(os.getcwd())
    except FileNotFoundError as e:
        cwd = '/'

    # if we have no target repo figure out what to use
    if namespace.target_repo is None:
        target_repo = _determine_target_repo(namespace, parser, cwd)
        # fallback to the default repo
        if target_repo is None:
            target_repo = namespace.config.get_default('repo')
        namespace.target_repo = target_repo

    # use filtered repo if filtering is enabled
    if namespace.filtered:
        namespace.target_repo = namespace.domain.ebuild_repos[
            namespace.target_repo.repo_id]

    # determine if we're running in the gentoo repo or a clone
    namespace.gentoo_repo = 'gentoo' in namespace.target_repo.aliases

    # multiplex of target repo and its masters used for package existence queries
    namespace.search_repo = multiplex.tree(*namespace.target_repo.trees)

    if namespace.targets:
        repo = namespace.target_repo

        # read targets from stdin in a non-blocking manner
        if len(namespace.targets) == 1 and namespace.targets[0] == '-':

            def stdin():
                while True:
                    line = sys.stdin.readline()
                    if not line:
                        break
                    yield line.rstrip()

            namespace.targets = stdin()

        def restrictions():
            for target in namespace.targets:
                try:
                    r = parserestrict.parse_match(target)
                except parserestrict.ParseError as e:
                    if os.path.exists(target):
                        try:
                            r = _path_restrict(target, namespace)
                        except ValueError as e:
                            parser.error(e)
                    else:
                        parser.error(e)
                yield _restrict_to_scope(r), r

        # Collapse restrictions for passed in targets while keeping the
        # generator intact for piped in targets.
        namespace.restrictions = restrictions()
        if isinstance(namespace.targets, list):
            namespace.restrictions = list(namespace.restrictions)

            # collapse restrictions in order to run them in parallel
            if len(namespace.restrictions) > 1:
                # multiple targets are restricted to a single scanning scope
                scopes = {scope for scope, restrict in namespace.restrictions}
                if len(scopes) > 1:
                    scan_scopes = ', '.join(sorted(map(str, scopes)))
                    parser.error(
                        f'targets specify multiple scan scope levels: {scan_scopes}'
                    )

                combined_restrict = boolean.OrRestriction(
                    *(r for s, r in namespace.restrictions))
                namespace.restrictions = [(scopes.pop(), combined_restrict)]
    else:
        if cwd in namespace.target_repo:
            restrict = _path_restrict(cwd, namespace)
        else:
            restrict = packages.AlwaysTrue
        namespace.restrictions = [(_restrict_to_scope(restrict), restrict)]

    if namespace.checkset is None:
        namespace.checkset = namespace.config.get_default('pkgcheck_checkset')
    if namespace.checkset is not None:
        namespace.enabled_checks = list(
            namespace.checkset.filter(namespace.enabled_checks))

    if namespace.selected_scopes is not None:
        disabled_scopes, enabled_scopes = namespace.selected_scopes

        # validate selected scopes
        selected_scopes = set(disabled_scopes + enabled_scopes)
        unknown_scopes = selected_scopes - set(base.scopes)
        if unknown_scopes:
            unknown = ', '.join(map(repr, unknown_scopes))
            available = ', '.join(base.scopes)
            parser.error(f'unknown scope{_pl(unknown_scopes)}: '
                         f'{unknown} (available scopes: {available})')

        disabled_scopes = {base.scopes[x] for x in disabled_scopes}
        enabled_scopes = {base.scopes[x] for x in enabled_scopes}

        # convert scopes to keyword lists
        disabled_keywords = [
            k.__name__ for k in const.KEYWORDS.values()
            if k.scope in disabled_scopes
        ]
        enabled_keywords = [
            k.__name__ for k in const.KEYWORDS.values()
            if k.scope in enabled_scopes
        ]

        # filter outputted keywords
        namespace.enabled_keywords = base.filter_update(
            namespace.enabled_keywords, enabled_keywords, disabled_keywords)

    if namespace.selected_keywords is not None:
        disabled_keywords, enabled_keywords = namespace.selected_keywords

        error = (k for k, v in const.KEYWORDS.items()
                 if issubclass(v, results.Error))
        warning = (k for k, v in const.KEYWORDS.items()
                   if issubclass(v, results.Warning))
        info = (k for k, v in const.KEYWORDS.items()
                if issubclass(v, results.Info))

        alias_map = {'error': error, 'warning': warning, 'info': info}
        replace_aliases = lambda x: alias_map.get(x, [x])

        # expand keyword aliases to keyword lists
        disabled_keywords = list(
            chain.from_iterable(map(replace_aliases, disabled_keywords)))
        enabled_keywords = list(
            chain.from_iterable(map(replace_aliases, enabled_keywords)))

        # validate selected keywords
        selected_keywords = set(disabled_keywords + enabled_keywords)
        available_keywords = set(const.KEYWORDS.keys())
        unknown_keywords = selected_keywords - available_keywords
        if unknown_keywords:
            unknown = ', '.join(map(repr, unknown_keywords))
            parser.error(f'unknown keyword{_pl(unknown_keywords)}: {unknown}')

        # filter outputted keywords
        namespace.enabled_keywords = base.filter_update(
            namespace.enabled_keywords, enabled_keywords, disabled_keywords)

    namespace.filtered_keywords = set(namespace.enabled_keywords)
    if namespace.filtered_keywords == set(const.KEYWORDS.values()):
        namespace.filtered_keywords = None

    disabled_checks, enabled_checks = ((), ())
    if namespace.selected_checks is not None:
        disabled_checks, enabled_checks = namespace.selected_checks
        available_checks = list(const.CHECKS.keys())

        alias_map = {'all': available_checks}
        replace_aliases = lambda x: alias_map.get(x, [x])

        # expand check aliases to check lists
        disabled_checks = list(
            chain.from_iterable(map(replace_aliases, disabled_checks)))
        enabled_checks = list(
            chain.from_iterable(map(replace_aliases, enabled_checks)))

        # overwrite selected checks with expanded aliases
        namespace.selected_checks = (disabled_checks, enabled_checks)

        # validate selected checks
        selected_checks = set(disabled_checks + enabled_checks)
        unknown_checks = selected_checks.difference(available_checks)
        if unknown_checks:
            unknown = ', '.join(map(repr, unknown_checks))
            parser.error(f'unknown check{_pl(unknown_checks)}: {unknown} ')
    elif namespace.filtered_keywords is not None:
        # enable checks based on enabled keyword -> check mapping
        enabled_checks = []
        for check, cls in const.CHECKS.items():
            if namespace.filtered_keywords.intersection(cls.known_results):
                enabled_checks.append(check)

    # filter checks to run
    if enabled_checks:
        whitelist = base.Whitelist(enabled_checks)
        namespace.enabled_checks = list(
            whitelist.filter(namespace.enabled_checks))
    if disabled_checks:
        blacklist = base.Blacklist(disabled_checks)
        namespace.enabled_checks = list(
            blacklist.filter(namespace.enabled_checks))

    # skip checks that may be disabled
    namespace.enabled_checks = [
        c for c in namespace.enabled_checks if not c.skip(namespace)
    ]

    if not namespace.enabled_checks:
        parser.error('no active checks')

    namespace.addons = set()

    for check in namespace.enabled_checks:
        add_addon(check, namespace.addons)
    try:
        for addon in namespace.addons:
            addon.check_args(parser, namespace)
    except argparse.ArgumentError as e:
        if namespace.debug:
            raise
        parser.error(str(e))