Пример #1
0
 def test_file_match_no_dups(self):
     tree = self.make_branch_and_tree('tree')
     rn = RenameMap(tree)
     rn.add_edge_hashes(self.a_lines, 'aid')
     self.build_tree_contents([('tree/a', b''.join(self.a_lines))])
     self.build_tree_contents([('tree/b', b''.join(self.b_lines))])
     self.build_tree_contents([('tree/c', b''.join(self.b_lines))])
     self.assertEqual({'a': 'aid'}, rn.file_match(['a', 'b', 'c']))
Пример #2
0
 def test_add_file_edge_hashes(self):
     tree = self.make_branch_and_tree('tree')
     self.build_tree_contents([('tree/a', b''.join(self.a_lines))])
     tree.add('a', b'a')
     rn = RenameMap(tree)
     rn.add_file_edge_hashes(tree, [b'a'])
     self.assertEqual({b'a'}, rn.edge_hashes[myhash(('a\n', 'b\n'))])
     self.assertEqual({b'a'}, rn.edge_hashes[myhash(('b\n', 'c\n'))])
     self.assertIs(None, rn.edge_hashes.get(myhash(('c\n', 'd\n'))))
Пример #3
0
 def test_guess_renames_dry_run(self):
     tree = self.make_branch_and_tree('tree')
     tree.lock_write()
     self.addCleanup(tree.unlock)
     self.build_tree(['tree/file'])
     tree.add('file', b'file-id')
     tree.commit('Added file')
     os.rename('tree/file', 'tree/file2')
     RenameMap.guess_renames(tree.basis_tree(), tree, dry_run=True)
     self.assertEqual('file', tree.id2path(b'file-id'))
Пример #4
0
 def test_guess_renames_handles_directories(self):
     tree = self.make_branch_and_tree('tree')
     tree.lock_write()
     self.addCleanup(tree.unlock)
     self.build_tree(['tree/dir/', 'tree/dir/file'])
     tree.add(['dir', 'dir/file'], [b'dir-id', b'file-id'])
     tree.commit('Added file')
     os.rename('tree/dir', 'tree/dir2')
     RenameMap.guess_renames(tree.basis_tree(), tree)
     self.assertEqual('dir2/file', tree.id2path(b'file-id'))
     self.assertEqual('dir2', tree.id2path(b'dir-id'))
Пример #5
0
 def test_match_directories(self):
     tree = self.make_branch_and_tree('tree')
     rn = RenameMap(tree)
     required_parents = rn.get_required_parents({
         'path1': 'a',
         'path2/tr': 'b',
         'path3/path4/path5': 'c',
     })
     self.assertEqual({
         'path2': {'b'},
         'path3/path4': {'c'},
         'path3': set()
     }, required_parents)
Пример #6
0
 def test_guess_renames_preserves_children(self):
     """When a directory has been moved, its children are preserved."""
     tree = self.make_branch_and_tree('tree')
     tree.lock_write()
     self.addCleanup(tree.unlock)
     self.build_tree_contents([('tree/foo/', b''), ('tree/foo/bar', b'bar'),
                               ('tree/foo/empty', b'')])
     tree.add(['foo', 'foo/bar', 'foo/empty'],
              [b'foo-id', b'bar-id', b'empty-id'])
     tree.commit('rev1')
     os.rename('tree/foo', 'tree/baz')
     RenameMap.guess_renames(tree.basis_tree(), tree)
     self.assertEqual('baz/empty', tree.id2path(b'empty-id'))
Пример #7
0
 def test_hitcounts(self):
     rn = RenameMap(None)
     rn.add_edge_hashes(self.a_lines, 'a')
     rn.add_edge_hashes(self.b_lines, 'b')
     self.assertEqual({'a': 2.5, 'b': 0.5}, rn.hitcounts(self.a_lines))
     self.assertEqual({'a': 1}, rn.hitcounts(self.a_lines[:-1]))
     self.assertEqual({'b': 2.5, 'a': 0.5}, rn.hitcounts(self.b_lines))
Пример #8
0
 def test_find_directory_renames(self):
     tree = self.make_branch_and_tree('tree')
     rn = RenameMap(tree)
     matches = {
         'path1': 'a',
         'path3/path4/path5': 'c',
     }
     required_parents = {
         'path2': {'b'},
         'path3/path4': {'c'},
         'path3': set([])
     }
     missing_parents = {
         'path2-id': {'b'},
         'path4-id': {'c'},
         'path3-id': {'path4-id'}
     }
     matches = rn.match_parents(required_parents, missing_parents)
     self.assertEqual({
         'path3/path4': 'path4-id',
         'path2': 'path2-id'
     }, matches)
Пример #9
0
 def test_add_edge_hashes(self):
     rn = RenameMap(None)
     rn.add_edge_hashes(self.a_lines, 'a')
     self.assertEqual({'a'}, rn.edge_hashes[myhash(('a\n', 'b\n'))])
     self.assertEqual({'a'}, rn.edge_hashes[myhash(('b\n', 'c\n'))])
     self.assertIs(None, rn.edge_hashes.get(myhash(('c\n', 'd\n'))))
Пример #10
0
def run_lintian_fixer(  # noqa: C901
    local_tree: WorkingTree,
    fixer: Fixer,
    committer: Optional[str] = None,
    update_changelog: Union[bool, Callable[[], bool]] = True,
    compat_release: Optional[str] = None,
    minimum_certainty: Optional[str] = None,
    trust_package: bool = False,
    allow_reformatting: bool = False,
    dirty_tracker=None,
    subpath: str = "",
    net_access: bool = True,
    opinionated: Optional[bool] = None,
    diligence: int = 0,
    timestamp: Optional[datetime] = None,
    basis_tree: Optional[Tree] = None,
    changes_by: str = "lintian-brush",
):
    """Run a lintian fixer on a tree.

    Args:
      local_tree: WorkingTree object
      basis_tree: Tree
      fixer: Fixer object to apply
      committer: Optional committer (name and email)
      update_changelog: Whether to add a new entry to the changelog
      compat_release: Minimum release that the package should be usable on
        (e.g. 'stable' or 'unstable')
      minimum_certainty: How certain the fixer should be
        about its changes.
      trust_package: Whether to run code from the package if necessary
      allow_reformatting: Whether to allow reformatting of changed files
      dirty_tracker: Optional object that can be used to tell if the tree
        has been changed.
      subpath: Path in tree to operate on
      net_access: Whether to allow accessing external services
      opinionated: Whether to be opinionated
      diligence: Level of diligence
    Returns:
      tuple with set of FixerResult, summary of the changes
    """
    if basis_tree is None:
        basis_tree = local_tree.basis_tree()

    changelog_path = os.path.join(subpath, "debian/changelog")

    try:
        with local_tree.get_file(changelog_path) as f:
            cl = Changelog(f, max_blocks=1)
    except NoSuchFile:
        raise NotDebianPackage(local_tree, subpath)
    package = cl.package
    if cl.distributions == "UNRELEASED":
        current_version = cl.version
    else:
        current_version = cl.version
        increment_version(current_version)
    if compat_release is None:
        compat_release = "sid"
    if minimum_certainty is None:
        minimum_certainty = DEFAULT_MINIMUM_CERTAINTY
    logger.debug('Running fixer %r', fixer)
    try:
        result = fixer.run(
            local_tree.abspath(subpath),
            package=package,
            current_version=current_version,
            compat_release=compat_release,
            minimum_certainty=minimum_certainty,
            trust_package=trust_package,
            allow_reformatting=allow_reformatting,
            net_access=net_access,
            opinionated=opinionated,
            diligence=diligence,
        )
    except BaseException:
        reset_tree(local_tree, basis_tree, subpath, dirty_tracker=dirty_tracker)
        raise
    if not certainty_sufficient(result.certainty, minimum_certainty):
        reset_tree(local_tree, basis_tree, subpath, dirty_tracker=dirty_tracker)
        raise NotCertainEnough(
            fixer, result.certainty, minimum_certainty,
            overridden_lintian_issues=result.overridden_lintian_issues)
    specific_files: Optional[List[str]]
    if dirty_tracker:
        relpaths = dirty_tracker.relpaths()
        # Sort paths so that directories get added before the files they
        # contain (on VCSes where it matters)
        local_tree.add(
            [
                p
                for p in sorted(relpaths)
                if local_tree.has_filename(p) and not local_tree.is_ignored(p)
            ]
        )
        specific_files = [p for p in relpaths if local_tree.is_versioned(p)]
        if not specific_files:
            raise NoChanges(
                fixer, "Script didn't make any changes",
                result.overridden_lintian_issues)
    else:
        local_tree.smart_add([local_tree.abspath(subpath)])
        specific_files = [subpath] if subpath else None

    if local_tree.supports_setting_file_ids():
        RenameMap.guess_renames(basis_tree, local_tree, dry_run=False)

    changes = list(
        local_tree.iter_changes(
            basis_tree,
            specific_files=specific_files,
            want_unversioned=False,
            require_versioned=True,
        )
    )

    if len(local_tree.get_parent_ids()) <= 1 and not changes:
        raise NoChanges(
            fixer, "Script didn't make any changes",
            result.overridden_lintian_issues)

    if not result.description:
        raise DescriptionMissing(fixer)

    lines = result.description.splitlines()
    summary = lines[0]
    details = list(itertools.takewhile(lambda line: line, lines[1:]))

    # If there are upstream changes in a non-native package, perhaps
    # export them to debian/patches
    if has_non_debian_changes(changes, subpath) and current_version.debian_revision:
        try:
            patch_name, specific_files = _upstream_changes_to_patch(
                local_tree,
                basis_tree,
                dirty_tracker,
                subpath,
                result.patch_name or fixer.name,
                result.description,
                timestamp=timestamp,
            )
        except BaseException:
            reset_tree(local_tree, basis_tree, subpath, dirty_tracker=dirty_tracker)
            raise

        summary = "Add patch %s: %s" % (patch_name, summary)

    if only_changes_last_changelog_block(
        local_tree, basis_tree, changelog_path, changes
    ):
        # If the script only changed the last entry in the changelog,
        # don't update the changelog
        update_changelog = False

    if callable(update_changelog):
        update_changelog = update_changelog()

    if update_changelog:
        from .changelog import add_changelog_entry

        add_changelog_entry(local_tree, changelog_path, [summary] + details)
        if specific_files:
            specific_files.append(changelog_path)

    description = result.description + "\n"
    description += "\n"
    description += "Changes-By: %s\n" % changes_by
    for tag in result.fixed_lintian_tags:
        description += "Fixes: lintian: %s\n" % tag
        description += "See-also: https://lintian.debian.org/tags/%s.html\n" % tag

    if committer is None:
        committer = get_committer(local_tree)

    revid = local_tree.commit(
        description,
        allow_pointless=False,
        reporter=NullCommitReporter(),
        committer=committer,
        specific_files=specific_files,
    )
    result.revision_id = revid
    # TODO(jelmer): Support running sbuild & verify lintian warning is gone?
    return result, summary