Exemplo n.º 1
0
def default_fixers(local_tree,
                   subpath,
                   apt,
                   committer=None,
                   update_changelog=None):
    packaging_context = DebianPackagingContext(
        local_tree,
        subpath,
        committer,
        update_changelog,
        commit_reporter=NullCommitReporter())
    return (versioned_package_fixers(apt.session, packaging_context, apt) +
            apt_fixers(apt, packaging_context))
Exemplo n.º 2
0
    def resolve(self, error, context=("build", )):
        from ..session.plain import PlainSession

        session = PlainSession()
        apt = AptManager(session)
        apt._searchers = [DummyAptSearcher(self._apt_files)]
        context = DebianPackagingContext(
            self.tree,
            subpath="",
            committer="ognibuild <*****@*****.**>",
            update_changelog=True,
            commit_reporter=NullCommitReporter(),
        )
        fixers = versioned_package_fixers(session, context, apt) + apt_fixers(
            apt, context)
        return resolve_error(error, ("build", ), fixers)
Exemplo n.º 3
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
Exemplo n.º 4
0
def prepare_upload_package(
    local_tree,
    subpath,
    pkg,
    last_uploaded_version,
    builder,
    gpg_strategy=None,
    min_commit_age=None,
    allowed_committers=None,
):
    if local_tree.has_filename(os.path.join(subpath, "debian/gbp.conf")):
        subprocess.check_call(["gbp", "dch", "--ignore-branch"],
                              cwd=local_tree.abspath("."))
    cl, top_level = find_changelog(local_tree, merge=False, max_blocks=None)
    if cl.version == last_uploaded_version:
        raise NoUnuploadedChanges(cl.version)
    previous_version_in_branch = changelog_find_previous_upload(cl)
    if last_uploaded_version > previous_version_in_branch:
        raise LastUploadMoreRecent(last_uploaded_version,
                                   previous_version_in_branch)

    logging.info("Checking revisions since %s" % last_uploaded_version)
    with local_tree.lock_read():
        try:
            last_release_revid = find_last_release_revid(
                local_tree.branch, last_uploaded_version)
        except NoSuchTag:
            raise LastReleaseRevisionNotFound(pkg, last_uploaded_version)
        graph = local_tree.branch.repository.get_graph()
        revids = list(
            graph.iter_lefthand_ancestry(local_tree.branch.last_revision(),
                                         [last_release_revid]))
        if not revids:
            logging.info("No pending changes")
            return
        if gpg_strategy:
            logging.info("Verifying GPG signatures...")
            count, result, all_verifiables = gpg.bulk_verify_signatures(
                local_tree.branch.repository, revids, gpg_strategy)
            for revid, code, key in result:
                if code != gpg.SIGNATURE_VALID:
                    raise Exception("No valid GPG signature on %r: %d" %
                                    (revid, code))
        for revid, rev in local_tree.branch.repository.iter_revisions(revids):
            if rev is not None:
                check_revision(rev, min_commit_age, allowed_committers)

        if cl.distributions != "UNRELEASED":
            raise NoUnreleasedChanges(cl.version)
    qa_upload = False
    team_upload = False
    control_path = local_tree.abspath(os.path.join(subpath, "debian/control"))
    with ControlEditor(control_path) as e:
        maintainer = parseaddr(e.source["Maintainer"])
        if maintainer[1] == "*****@*****.**":
            qa_upload = True
        # TODO(jelmer): Check whether this is a team upload
        # TODO(jelmer): determine whether this is a NMU upload
    if qa_upload or team_upload:
        changelog_path = local_tree.abspath(
            os.path.join(subpath, "debian/changelog"))
        with ChangelogEditor(changelog_path) as e:
            if qa_upload:
                changeblock_ensure_first_line(e[0], "QA upload.")
            elif team_upload:
                changeblock_ensure_first_line(e[0], "Team upload.")
        local_tree.commit(
            specific_files=[os.path.join(subpath, "debian/changelog")],
            message="Mention QA Upload.",
            allow_pointless=False,
            reporter=NullCommitReporter(),
        )
    tag_name = release(local_tree, subpath)
    target_dir = tempfile.mkdtemp()
    builder = builder.replace("${LAST_VERSION}", last_uploaded_version)
    target_changes = _build_helper(local_tree,
                                   subpath,
                                   local_tree.branch,
                                   target_dir,
                                   builder=builder)
    debsign(target_changes)
    return target_changes, tag_name
Exemplo n.º 5
0
def update_offical_vcs(wt,
                       subpath,
                       repo_url=None,
                       committer=None,
                       force=False,
                       create=False):
    # TODO(jelmer): Allow creation of the repository as well
    check_clean_tree(wt, wt.basis_tree(), subpath)

    debcargo_path = os.path.join(subpath, 'debian/debcargo.toml')
    control_path = os.path.join(subpath, 'debian/control')

    if wt.has_filename(debcargo_path):
        from debmutate.debcargo import DebcargoControlShimEditor
        editor = DebcargoControlShimEditor.from_debian_dir(
            wt.abspath(os.path.join(subpath, 'debian')))
    elif wt.has_filename(control_path):
        control_path = wt.abspath(control_path)
        editor = ControlEditor(control_path)
    else:
        raise FileNotFoundError(control_path)
    with editor:
        try:
            vcs_type, url = source_package_vcs(editor.source)
        except KeyError:
            pass
        else:
            if not force:
                raise VcsAlreadySpecified(vcs_type, url)
        maintainer_email = parseaddr(editor.source['Maintainer'])[1]
        source = editor.source['Source']
        if repo_url is None:
            repo_url = guess_repository_url(source, maintainer_email)
        if repo_url is None:
            raise NoVcsLocation()
        logging.info('Using repository URL: %s', repo_url)
        # TODO(jelmer): Detect vcs type in a better way
        if hasattr(wt.branch.repository, '_git'):
            vcs_type = 'Git'
        else:
            vcs_type = 'Bzr'
        update_control_for_vcs_url(editor.source, vcs_type, repo_url)

    if committer is None:
        committer = get_committer(wt)

    try:
        wt.commit(
            message='Set Vcs headers.',
            allow_pointless=False,
            reporter=NullCommitReporter(),
            committer=committer,
        )
    except PointlessCommit:
        if not force:
            # This can't happen
            raise

    if create:
        from breezy.forge import create_project
        try:
            forge, project = create_project(repo_url)
        except AlreadyControlDirError:
            logging.info('%s already exists', repo_url)
        except UnsupportedForge:
            logging.error('Unable to find a way to create %s', repo_url)
        else:
            logging.info('Created %s', repo_url)

    return repo_url
Exemplo n.º 6
0
def scrub_obsolete(wt: WorkingTree,
                   subpath: str,
                   compat_release: str,
                   upgrade_release: str,
                   update_changelog=None,
                   allow_reformatting: bool = False) -> ScrubObsoleteResult:
    """Scrub obsolete entries.
    """

    if control_files_in_root(wt, subpath):
        debian_path = subpath
    else:
        debian_path = os.path.join(subpath, 'debian')

    result = _scrub_obsolete(wt, debian_path, compat_release, upgrade_release,
                             allow_reformatting)

    if not result:
        return result

    specific_files = list(result.specific_files)
    summary = result.itemized()

    changelog_path = os.path.join(debian_path, "changelog")

    if update_changelog is None:
        from .detect_gbp_dch import guess_update_changelog
        from debian.changelog import Changelog

        with wt.get_file(changelog_path) as f:
            cl = Changelog(f, max_blocks=1)

        dch_guess = guess_update_changelog(wt, debian_path, cl)
        if dch_guess:
            update_changelog = dch_guess.update_changelog
            _note_changelog_policy(update_changelog, dch_guess.explanation)
            result.changelog_behaviour = dch_guess
        else:
            # Assume we should update changelog
            update_changelog = True
            result.changelog_behaviour = None

    if update_changelog:
        lines = []
        for release, entries in summary.items():
            lines.append("Remove constraints unnecessary since %s:" % release)
            lines.extend(["+ " + line for line in entries])
        add_changelog_entry(wt, changelog_path, lines)
        specific_files.append(changelog_path)

    lines = []
    for release, entries in summary.items():
        lines.extend(["Remove constraints unnecessary since %s" % release, ""])
        lines.extend(["* " + line for line in entries])
    lines.extend(["", "Changes-By: deb-scrub-obsolete"])

    committer = get_committer(wt)

    try:
        wt.commit(
            specific_files=specific_files,
            message="\n".join(lines),
            allow_pointless=False,
            reporter=NullCommitReporter(),
            committer=committer,
        )
    except PointlessCommit:
        pass

    return result