Ejemplo n.º 1
0
    def test_circular_level(self):
        """
        Simple circular dependency with different USE levels

        A → B → C
         ↖←←←←←↙
        """

        graph = nx.DiGraph()
        graph.add_nodes_from('ABC')
        graph.add_edge('A', 'B', dep=DepType.DEPEND, level=0)
        graph.add_edge('B', 'C', dep=DepType.DEPEND, level=0)
        graph.add_edge('C', 'A', dep=DepType.DEPEND, level=1)

        # check both forward and reverse graph to make sure it is
        # actually resolving circular dependencies and not just
        # producing incidentally correct output
        cycles: typing.List[CycleTuple] = []
        self.assertEqual(
            list(get_ordered_nodes(graph.copy(), cycles.append)),
            ['C', 'B', 'A'])
        self.assertEqual(
            cycles,
            [([('A', 'B'), ('B', 'C'), ('C', 'A')], ('C', 'A'))])

        cycles = []
        self.assertEqual(
            list(get_ordered_nodes(graph.reverse())),
            ['A', 'B', 'C'])
        self.assertEqual(
            cycles,
            [])
Ejemplo n.º 2
0
    def test_cross(self):
        """
        Test graph with crossed subtrees (common dependencies)

             A
            ↙↓↘
           B ↓ G
          ↙↓↘↓ ↑
         C D E ↑
             ↓↗
             F
        """

        graph = nx.DiGraph()
        graph.add_nodes_from('ABCDEFG')
        graph.add_edge('A', 'B', dep=DepType.DEPEND, level=0)
        graph.add_edge('B', 'C', dep=DepType.DEPEND, level=0)
        graph.add_edge('B', 'D', dep=DepType.DEPEND, level=0)
        graph.add_edge('A', 'E', dep=DepType.DEPEND, level=0)
        graph.add_edge('B', 'E', dep=DepType.DEPEND, level=0)
        graph.add_edge('E', 'F', dep=DepType.DEPEND, level=0)
        graph.add_edge('A', 'G', dep=DepType.DEPEND, level=0)
        graph.add_edge('F', 'G', dep=DepType.DEPEND, level=0)

        out = list(get_ordered_nodes(graph))
        # verify that all nodes are present
        self.assertEqual(sorted(out), list('ABCDEFG'))
        # A must always come last
        self.assertEqual(out[-1], 'A')
        # verify relative order
        self.assertLess(out.index('C'), out.index('B'))
        self.assertLess(out.index('D'), out.index('B'))
        self.assertLess(out.index('E'), out.index('B'))
        self.assertLess(out.index('F'), out.index('E'))
        self.assertLess(out.index('G'), out.index('F'))
Ejemplo n.º 3
0
 def test_simple(self):
     """Test simple A -> B -> C graph"""
     graph = nx.DiGraph()
     graph.add_nodes_from('ABC')
     graph.add_edge('A', 'B', dep=DepType.DEPEND, level=0)
     graph.add_edge('B', 'C', dep=DepType.DEPEND, level=0)
     self.assertEqual(
         list(get_ordered_nodes(graph)),
         ['C', 'B', 'A'])
Ejemplo n.º 4
0
    def test_loose(self):
        """Test graph with unconnected nodes"""
        graph = nx.DiGraph()
        graph.add_nodes_from('ABCD')
        graph.add_edge('A', 'B', dep=DepType.DEPEND, level=0)

        out = list(get_ordered_nodes(graph))
        # verify that all nodes are present
        self.assertEqual(sorted(out), list('ABCD'))
        # verify relative order
        self.assertLess(out.index('B'), out.index('A'))
Ejemplo n.º 5
0
    def test_multi_circular(self):
        """
        Complex dependency graph with multiple circular dependencies

           B←A
           ↓↗↓↘
           C D→F
             ↕↖↓
             E G
        """

        graph = nx.DiGraph()
        graph.add_nodes_from('ABCDEFG')
        graph.add_edge('A', 'B', dep=DepType.DEPEND, level=0)
        graph.add_edge('B', 'C', dep=DepType.DEPEND, level=0)
        graph.add_edge('C', 'A', dep=DepType.RDEPEND, level=0)
        graph.add_edge('A', 'D', dep=DepType.DEPEND, level=0)
        graph.add_edge('D', 'E', dep=DepType.DEPEND, level=0)
        graph.add_edge('D', 'F', dep=DepType.RDEPEND, level=0)
        graph.add_edge('E', 'D', dep=DepType.PDEPEND, level=0)
        graph.add_edge('A', 'F', dep=DepType.RDEPEND, level=0)
        graph.add_edge('F', 'G', dep=DepType.DEPEND, level=0)
        graph.add_edge('G', 'D', dep=DepType.DEPEND, level=0)

        cycles: typing.List[CycleTuple] = []
        out = list(get_ordered_nodes(graph, cycles.append))
        # verify that all nodes are present
        self.assertEqual(sorted(out), list('ABCDEFG'))
        # A must always come last
        self.assertEqual(out[-1], 'A')
        # verify relative order
        self.assertLess(out.index('C'), out.index('B'))
        self.assertLess(out.index('D'), out.index('G'))
        self.assertLess(out.index('E'), out.index('D'))
        self.assertLess(out.index('G'), out.index('F'))
        # verify cycle resolution
        self.assertEqual(
            sorted(cycles),
            [([('A', 'B'), ('B', 'C'), ('C', 'A')], ('C', 'A')),
             ([('D', 'E'), ('E', 'D')], ('E', 'D')),
             ([('D', 'F'), ('F', 'G'), ('G', 'D')], ('D', 'F')),
             ])
Ejemplo n.º 6
0
    def commit(self) -> int:
        repo, git_repo = self.get_git_repository()
        arch = self.get_arch()

        if not have_nattka_depgraph:
            log.warning('Unable to import nattka.depgraph, dependency sorting '
                        'will not be available')
            log.warning('(nattka.depgraph requires networkx)')

        ret = 0
        bugnos, bugs = self.find_bugs()
        for bno in bugnos:
            b = bugs[bno]
            if b.category is None:
                log.error(f'Bug {bno}: neither stablereq nor keywordreq')
                ret = 1
                continue

            try:
                plist = dict(
                    match_package_list(
                        repo,
                        b,
                        filter_arch=arch,
                        permit_allarches=not self.args.ignore_allarches))
            except PackageMatchException as e:
                log.error(f'Bug {bno}: {e}')
                ret = 1
                continue

            if have_nattka_depgraph:
                graph = get_depgraph_for_packages(plist)
                ordered_nodes = list(get_ordered_nodes(graph))
                order = sorted(plist,
                               key=lambda x:
                               (ordered_nodes.index(x.key), x.fullver))
            else:
                order = list(plist)

            allarches = (not self.args.ignore_allarches
                         and 'ALLARCHES' in b.keywords)
            log.info(f'Bug {bno} ({b.category.name})'
                     f'{" ALLARCHES" if allarches else ""}')
            for p in order:
                keywords = [k for k in plist[p] if k in arch]
                if not keywords:
                    continue

                ebuild_path = Path(p.path).relative_to(repo.location)
                pfx = f'{p.category}/{p.package}'
                act = ('Stabilize'
                       if b.category == BugCategory.STABLEREQ else 'Keyword')
                if allarches:
                    kws = 'ALLARCHES'
                else:
                    kws = ' '.join(keywords)
                msg = f'{pfx}: {act} {p.fullver} {kws}, #{bno}'
                try:
                    print(git_commit(git_repo.path, msg, [str(ebuild_path)]))
                except GitCommitNoChanges:
                    pass

        return ret
Ejemplo n.º 7
0
    def apply(self) -> int:
        repo = self.get_repository()
        arch = self.get_arch()

        if not have_nattka_depgraph:
            log.warning('Unable to import nattka.depgraph, dependency sorting '
                        'will not be available')
            log.warning('(nattka.depgraph requires networkx)')

        ret = 0
        bugnos, bugs = self.find_bugs(arch=arch)
        for bno in bugnos:
            b = bugs[bno]
            if b.category is None:
                print(f'# bug {bno}: neither stablereq nor keywordreq\n')
                ret = 1
                continue

            try:
                plist = dict(
                    match_package_list(
                        repo,
                        b,
                        only_new=True,
                        filter_arch=arch,
                        permit_allarches=not self.args.ignore_allarches))
            except PackageMatchException as e:
                print(f'# bug {bno}: {e}\n')
                ret = 1
                continue

            if (b.sanity_check is not True
                    and not self.args.ignore_sanity_check):
                if b.sanity_check is False:
                    print(f'# bug {bno}: sanity check failed\n')
                else:
                    print(f'# bug {bno}: no sanity check result\n')
                ret = 1
                continue

            all_keywords = frozenset(
                itertools.chain.from_iterable(plist.values()))
            unresolved_deps = []
            for depno in b.depends:
                depb = bugs[depno]
                if depb.resolved:
                    continue
                if depb.category == b.category:
                    try:
                        for depp, depkw in match_package_list(
                                repo,
                                depb,
                                only_new=True,
                                filter_arch=all_keywords):
                            pass
                    except PackageListEmpty:
                        # ignore dependent bugs with empty package list
                        # or mismatched keywords
                        # (assuming the bug passed sanity-check anyway)
                        continue
                    except PackageMatchException:
                        pass
                unresolved_deps.append(depno)

            if unresolved_deps and not self.args.ignore_dependencies:
                print(f'# bug {bno}: unresolved dependency on '
                      f'{", ".join(str(x) for x in unresolved_deps)}\n')
                ret = 1
                continue

            if have_nattka_depgraph:
                graph = get_depgraph_for_packages(plist)
                ordered_nodes = list(get_ordered_nodes(graph))
                order = sorted(plist,
                               key=lambda x:
                               (ordered_nodes.index(x.key), x.fullver))
            else:
                order = list(plist)

            allarches = (not self.args.ignore_allarches
                         and 'ALLARCHES' in b.keywords)
            print(f'# bug {bno} ({b.category.name})'
                  f'{" ALLARCHES" if allarches else ""}')
            for p in order:
                kws = ' '.join(f'~{k}' for k in plist[p])
                if b.category == BugCategory.STABLEREQ:
                    print(f'={p.cpvstr} {kws}')
                else:
                    print(f'={p.cpvstr} **  # -> {kws}')
            print()
            if not self.args.no_update:
                add_keywords(plist.items(),
                             b.category == BugCategory.STABLEREQ)

        return ret