예제 #1
0
    def __call__(self, environ, start_response):
        # End of URL is now /diff/<rev_id>?context=<context_lines>
        # or /diff/<rev_id>/<rev_id>?context=<context_lines>
        # This allows users to choose how much context they want to see.
        # Old format was /diff/<rev_id>/<rev_id> or /diff/<rev_id>
        """Default method called from /diff URL."""
        z = time.time()

        args = []
        while True:
            arg = path_info_pop(environ)
            if arg is None:
                break
            args.append(arg)

        numlines = 3 # This is the default.

        opts = parse_querystring(environ)
        for opt in opts:
            if opt[0] == 'context':
                try:
                    numlines = int(opt[1])
                except ValueError:
                    pass

        revid_from = args[0]
        # Convert a revno to a revid if we get a revno.
        revid_from = self._history.fix_revid(revid_from)
        change = self._history.get_changes([revid_from])[0]

        if len(args) == 2:
            revid_to = self._history.fix_revid(args[1])
        elif len(change.parents) == 0:
            revid_to = NULL_REVISION
        else:
            revid_to = change.parents[0].revid

        repo = self._branch.branch.repository
        revtree1 = repo.revision_tree(revid_to)
        revtree2 = repo.revision_tree(revid_from)

        diff_content_stream = StringIO()
        show_diff_trees(revtree1, revtree2, diff_content_stream,
                        old_label='', new_label='', context=numlines)

        content = diff_content_stream.getvalue()

        self.log.info('/diff %r:%r in %r secs with %r context' % (revid_from, revid_to,
                                                  time.time() - z, numlines))

        revno1 = self._history.get_revno(revid_from)
        revno2 = self._history.get_revno(revid_to)
        filename = '%s_%s.diff' % (revno1, revno2)
        headers = [
            ('Content-Type', 'application/octet-stream'),
            ('Content-Length', str(len(content))),
            ('Content-Disposition', 'attachment; filename=%s' % (filename,)),
            ]
        start_response('200 OK', headers)
        return [content]
예제 #2
0
 def show_base_diff(self, outf):
     base_tree = self.base_tree()
     result_tree = self.tree()
     if result_tree:
         show_diff_trees(
             base_tree, result_tree, outf,
             old_label='upstream/',
             new_label=(
                 'proposed/' if self.merge_proposal else 'pushed/'))
예제 #3
0
 def show_diff(
     self, outf: BinaryIO, old_label: str = "old/", new_label: str = "new/"
 ) -> None:
     base_tree = self.base_tree()
     show_diff_trees(
         base_tree,
         self.local_tree.basis_tree(),
         outf,
         old_label=old_label,
         new_label=new_label,
     )
예제 #4
0
def move_upstream_changes_to_patch(
    local_tree: WorkingTree,
    basis_tree: Tree,
    subpath: str,
    patch_name: str,
    description: str,
    dirty_tracker=None,
    timestamp: Optional[datetime] = None,
) -> Tuple[List[str], str]:
    """Move upstream changes to patch.

    Args:
      local_tree: local tree
      subpath: subpath
      patch_name: Suggested patch name
      description: Description
      dirty_tracker: Dirty tracker
    """
    if timestamp is None:
        timestamp = datetime.now()
    diff = BytesIO()
    show_diff_trees(basis_tree, local_tree, diff)
    reset_tree(local_tree, basis_tree, subpath, dirty_tracker)
    header = Message()
    lines = description.splitlines()
    # See https://dep-team.pages.debian.net/deps/dep3/ for fields.
    header["Description"] = (lines[0] + "\n" +
                             "\n".join([(" " + line) if line else " ."
                                        for line in lines[1:]]))
    header["Origin"] = "other"
    header["Last-Update"] = timestamp.strftime("%Y-%m-%d")
    patches_directory = tree_patches_directory(local_tree, subpath)
    patchname = add_patch(
        local_tree,
        os.path.join(subpath, patches_directory),
        patch_name,
        diff.getvalue(),
        header,
    )
    specific_files = [
        os.path.join(subpath, patches_directory),
        os.path.join(subpath, patches_directory, "series"),
        os.path.join(subpath, patches_directory, patchname),
    ]
    local_tree.add(specific_files)
    return specific_files, patchname
예제 #5
0
    def show_diff(
        self,
        repository,
        outf,
        role="main",
        old_label: str = "old/",
        new_label: str = "new/",
    ) -> None:
        from breezy.diff import show_diff_trees

        for (brole, name, base_revision, revision) in self.branches:
            if role == brole:
                break
        else:
            raise KeyError
        old_tree = repository.revision_tree(base_revision)
        new_tree = repository.revision_tree(revision)
        show_diff_trees(old_tree,
                        new_tree,
                        outf,
                        old_label=old_label,
                        new_label=new_label)
예제 #6
0
def main(argv: List[str]) -> Optional[int]:  # noqa: C901
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--command", help="Path to script to run.", type=str)
    parser.add_argument(
        "--diff", action="store_true", help="Show diff of generated changes."
    )
    parser.add_argument(
        "--no-update-changelog",
        action="store_false",
        default=None,
        dest="update_changelog",
        help="do not update the changelog",
    )
    parser.add_argument(
        "--update-changelog",
        action="store_true",
        dest="update_changelog",
        help="force updating of the changelog",
        default=None,
    )

    parser.add_argument(
        "--commit-pending",
        help="Commit pending changes after script.",
        choices=["yes", "no", "auto"],
        default=None,
        type=str,
    )
    parser.add_argument(
        "--build-verify",
        help="Build package to verify it.",
        dest="build_verify",
        action="store_true",
    )
    parser.add_argument(
        "--builder",
        default=DEFAULT_BUILDER,
        type=str,
        help="Build command to use when verifying build.",
    )
    parser.add_argument(
        "--build-target-dir",
        type=str,
        help=(
            "Store built Debian files in specified directory " "(with --build-verify)"
        ),
    )
    parser.add_argument(
        "--install", "-i",
        action="store_true",
        help="Install built package (implies --build-verify)")
    parser.add_argument(
        "--dump-context", action="store_true",
        help="Report context on success")

    parser.add_argument(
        "--recipe", type=str, help="Recipe to use.")
    args = parser.parse_args(argv)

    if args.recipe:
        from ..recipe import Recipe
        recipe = Recipe.from_path(args.recipe)
    else:
        recipe = None

    if args.commit_pending:
        commit_pending = {"auto": None, "yes": True, "no": False}[args.commit_pending]
    elif recipe:
        commit_pending = recipe.commit_pending
    else:
        commit_pending = None

    if args.command:
        command = args.command
    elif recipe and recipe.command:
        command = recipe.command
    else:
        logging.exception('No command or recipe specified.')
        return 1

    local_tree, subpath = WorkingTree.open_containing('.')

    check_clean_tree(local_tree)

    try:
        try:
            result = script_runner(
                local_tree, script=command, commit_pending=commit_pending,
                subpath=subpath, update_changelog=args.update_changelog)
        except MissingChangelog as e:
            logging.error('No debian changelog file (%s) present', e.args[0])
            return False
        except ScriptMadeNoChanges:
            logging.info('Script made no changes')
            return False

        if result.description:
            logging.info('Succeeded: %s', result.description)

        if args.build_verify or args.install:
            try:
                build(local_tree, subpath, builder=args.builder, result_dir=args.build_target_dir)
            except BuildFailedError:
                logging.error("%s: build failed", result.source)
                return False
            except MissingUpstreamTarball:
                logging.error("%s: unable to find upstream source", result.source)
                return False
    except Exception:
        reset_tree(local_tree, subpath)
        raise

    if args.install:
        install_built_package(local_tree, subpath, args.build_target_dir)

    if args.diff:
        from breezy.diff import show_diff_trees
        old_tree = local_tree.revision_tree(result.old_revision)
        new_tree = local_tree.revision_tree(result.new_revision)
        show_diff_trees(
            old_tree,
            new_tree,
            sys.stdout.buffer,
            old_label='old/',
            new_label='new/')

    if args.dump_context:
        json.dump(result.context, sys.stdout, indent=5)
    return 0
예제 #7
0
def main(argv=None):  # noqa: C901
    parser = argparse.ArgumentParser(prog="lintian-brush")

    fixer_group = parser.add_argument_group("fixer selection")
    fixer_group.add_argument("fixers",
                             metavar="FIXER",
                             nargs="*",
                             help="specific fixer to run")
    fixer_group.add_argument(
        "--fixers-dir",
        type=str,
        help="path to fixer scripts. [%(default)s]",
        default=find_fixers_dir(),
    )
    fixer_group.add_argument(
        "--exclude",
        metavar="EXCLUDE",
        type=str,
        action="append",
        help="Exclude a fixer.",
    )
    fixer_group.add_argument(
        "--modern",
        help=("Use features/compatibility levels that are not available in "
              "stable. (makes backporting harder)"),
        action="store_true",
        default=False,
    )
    fixer_group.add_argument("--compat-release",
                             type=str,
                             help=argparse.SUPPRESS)
    # Hide the minimum-certainty option for the moment.
    fixer_group.add_argument(
        "--minimum-certainty",
        type=str,
        choices=SUPPORTED_CERTAINTIES,
        default=None,
        help=argparse.SUPPRESS,
    )
    fixer_group.add_argument("--opinionated",
                             action="store_true",
                             help=argparse.SUPPRESS)
    fixer_group.add_argument(
        "--diligent",
        action="count",
        default=0,
        dest="diligence",
        help=argparse.SUPPRESS,
    )
    fixer_group.add_argument("--uncertain",
                             action="store_true",
                             help="Include changes with lower certainty.")
    fixer_group.add_argument("--yolo",
                             action="store_true",
                             help=argparse.SUPPRESS)

    fixer_group.add_argument("--force-subprocess",
                             action="store_true",
                             default=False,
                             help=argparse.SUPPRESS)

    package_group = parser.add_argument_group("package preferences")
    package_group.add_argument(
        "--allow-reformatting",
        default=None,
        action="store_true",
        help="Allow file reformatting and stripping of comments.")
    package_group.add_argument(
        "--no-update-changelog",
        action="store_false",
        default=None,
        dest="update_changelog",
        help="do not update the changelog",
    )
    package_group.add_argument(
        "--update-changelog",
        action="store_true",
        dest="update_changelog",
        help="force updating of the changelog",
        default=None,
    )
    package_group.add_argument("--trust",
                               action="store_true",
                               help=argparse.SUPPRESS)

    output_group = parser.add_argument_group("output")
    output_group.add_argument("--verbose",
                              help="be verbose",
                              action="store_true",
                              default=('SVP_API' in os.environ))
    output_group.add_argument("--diff",
                              help="Print resulting diff afterwards.",
                              action="store_true")
    output_group.add_argument("--version",
                              action="version",
                              version="%(prog)s " + version_string)
    output_group.add_argument("--list-fixers",
                              action="store_true",
                              help="list available fixers")
    output_group.add_argument(
        "--list-tags",
        action="store_true",
        help="list lintian tags for which fixers are available",
    )
    output_group.add_argument(
        "--dry-run",
        help=("Do not make any changes to the current repository. "
              "Note: currently creates a temporary clone of the repository."),
        action="store_true",
    )
    output_group.add_argument(
        "--identity",
        help="Print user identity that would be used when committing",
        action="store_true",
        default=False,
    )

    parser.add_argument(
        "-d",
        "--directory",
        metavar="DIRECTORY",
        help="directory to run in",
        type=str,
        default=".",
    )
    parser.add_argument(
        "--disable-net-access",
        help="Do not probe external services.",
        action="store_true",
        default=False,
    )

    parser.add_argument("--disable-inotify",
                        action="store_true",
                        default=False,
                        help=argparse.SUPPRESS)
    args = parser.parse_args(argv)

    logging.basicConfig(level=logging.INFO, format='%(message)s')

    if args.list_fixers and args.list_tags:
        parser.print_usage()
        return 1

    fixers = available_lintian_fixers(args.fixers_dir,
                                      force_subprocess=args.force_subprocess)
    if args.list_fixers:
        for script in sorted([fixer.name for fixer in fixers]):
            print(script)
    elif args.list_tags:
        tags = set()
        for fixer in fixers:
            tags.update(fixer.lintian_tags)
        for tag in sorted(tags):
            print(tag)
    else:
        try:
            if args.dry_run:
                branch, subpath = Branch.open_containing(args.directory)
                td = tempfile.mkdtemp()
                atexit.register(shutil.rmtree, td)
                # TODO(jelmer): Make a slimmer copy
                to_dir = branch.controldir.sprout(
                    td,
                    None,
                    create_tree_if_local=True,
                    source_branch=branch,
                    stacked=branch._format.supports_stacking(),
                )
                wt = to_dir.open_workingtree()
            else:
                wt, subpath = WorkingTree.open_containing(args.directory)
        except NotBranchError:
            logging.error(
                "No version control directory found (e.g. a .git directory).")
            return 1
        except DependencyNotPresent as e:
            logging.error(
                "Unable to open tree at %s: missing package %s",
                args.directory,
                e.library,
            )
            return 1
        if args.identity:
            print("Committer identity: %s" % get_committer(wt))
            print("Changelog identity: %s <%s>" % get_maintainer())
            return 0
        since_revid = wt.last_revision()
        if args.fixers:
            try:
                fixers = select_fixers(fixers, args.fixers, args.exclude)
            except KeyError as e:
                logging.error("Unknown fixer specified: %s", e.args[0])
                return 1
        debian_info = distro_info.DebianDistroInfo()
        if args.modern:
            if args.compat_release:
                logging.error(
                    "--compat-release and --modern are incompatible.")
                return 1
            compat_release = debian_info.devel()
        else:
            compat_release = args.compat_release
        minimum_certainty = args.minimum_certainty
        allow_reformatting = args.allow_reformatting
        update_changelog = args.update_changelog
        try:
            cfg = Config.from_workingtree(wt, subpath)
        except FileNotFoundError:
            pass
        else:
            if minimum_certainty is None:
                minimum_certainty = cfg.minimum_certainty()
            if compat_release is None:
                compat_release = cfg.compat_release()
            if allow_reformatting is None:
                allow_reformatting = cfg.allow_reformatting()
            if update_changelog is None:
                update_changelog = cfg.update_changelog()
        if minimum_certainty is None:
            if args.uncertain or args.yolo:
                minimum_certainty = "possible"
            else:
                minimum_certainty = DEFAULT_MINIMUM_CERTAINTY
        if compat_release is None:
            compat_release = debian_info.stable()
        if allow_reformatting is None:
            allow_reformatting = False
        with wt.lock_write():
            if control_files_in_root(wt, subpath):
                report_fatal(
                    "control-files-in-root",
                    "control files live in root rather than debian/ "
                    "(LarstIQ mode)",
                )

            try:
                overall_result = run_lintian_fixers(
                    wt,
                    fixers,
                    update_changelog=update_changelog,
                    compat_release=compat_release,
                    verbose=args.verbose,
                    minimum_certainty=minimum_certainty,
                    trust_package=args.trust,
                    allow_reformatting=allow_reformatting,
                    use_inotify=(False if args.disable_inotify else None),
                    subpath=subpath,
                    net_access=not args.disable_net_access,
                    opinionated=args.opinionated,
                    diligence=args.diligence,
                )
            except NotDebianPackage:
                report_fatal("not-debian-package", "Not a Debian package")
                return 1
            except WorkspaceDirty:
                logging.error("%s: Please commit pending changes first.",
                              wt.basedir)
                if args.verbose:
                    from breezy.status import show_tree_status

                    show_tree_status(wt)
                return 1
            except ChangelogCreateError as e:
                report_fatal("changelog-create-error",
                             "Error creating changelog entry: %s" % e)
                return 1
            except DescriptionMissing as e:
                report_fatal(
                    "fixer-description-missing",
                    "Fixer %s made changes but did not provide description." %
                    e.fixer)
                return 1

        if overall_result.overridden_lintian_issues:
            if len(overall_result.overridden_lintian_issues) == 1:
                logging.info("%d change skipped because of lintian overrides.",
                             len(overall_result.overridden_lintian_issues))
            else:
                logging.info(
                    "%d changes skipped because of lintian overrides.",
                    len(overall_result.overridden_lintian_issues))
        if overall_result.success:
            all_tags = set()
            for result, summary in overall_result.success:
                all_tags.update(result.fixed_lintian_tags)
            if all_tags:
                logging.info("Lintian tags fixed: %r", all_tags)
            else:
                logging.info("Some changes were made, "
                             "but there are no affected lintian tags.")
            min_certainty = overall_result.minimum_success_certainty()
            if min_certainty != "certain":
                logging.info(
                    "Some changes were made with lower certainty (%s); "
                    "please double check the changes.",
                    min_certainty,
                )
        else:
            report_fatal("nothing-to-do", "No changes made.")
            return 0
        if overall_result.failed_fixers and not args.verbose:
            logging.info(
                "Some fixer scripts failed to run: %r. "
                "Run with --verbose for details.",
                set(overall_result.failed_fixers.keys()),
            )
        if overall_result.formatting_unpreservable and not args.verbose:
            logging.info(
                "Some fixer scripts were unable to preserve formatting: %r. "
                "Run with --allow-reformatting to reformat %r.",
                set(overall_result.formatting_unpreservable),
                set(overall_result.formatting_unpreservable.values()),
            )
        if args.diff:
            from breezy.diff import show_diff_trees

            show_diff_trees(wt.branch.repository.revision_tree(since_revid),
                            wt, sys.stdout.buffer)
        if os.environ.get('SVP_API') == '1':
            applied = []
            if 'SVP_RESUME' in os.environ:
                with open(os.environ['SVP_RESUME'], 'r') as f:
                    base = json.load(f)
                    applied.extend(base['applied'])
            all_fixed_lintian_tags = set()
            for result, summary in overall_result.success:
                applied.append({
                    "summary":
                    summary,
                    "description":
                    result.description,
                    "fixed_lintian_tags":
                    result.fixed_lintian_tags,
                    "revision_id":
                    result.revision_id.decode("utf-8"),
                    "certainty":
                    result.certainty,
                })
                all_fixed_lintian_tags.update(result.fixed_lintian_tags)
            failed = {
                name: str(e)
                for (name, e) in overall_result.failed_fixers.items()
            }
            debian_context = {}
            if overall_result.changelog_behaviour:
                debian_context[
                    'changelog'] = overall_result.changelog_behaviour.json()
            with open(os.environ['SVP_RESULT'], 'w') as f:
                json.dump(
                    {
                        'value': calculate_value(all_fixed_lintian_tags),
                        'debian': debian_context,
                        'context': {
                            'applied': applied,
                            'failed': failed,
                            "versions": {
                                "lintian-brush": lintian_brush_version_string,
                                "breezy": breezy.version_string,
                            }
                        }
                    }, f)
예제 #8
0
def main(argv: List[str]) -> Optional[int]:  # noqa: C901
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("command",
                        help="Path to script to run.",
                        type=str,
                        nargs='?')
    parser.add_argument("--diff",
                        action="store_true",
                        help="Show diff of generated changes.")
    parser.add_argument(
        "--commit-pending",
        help="Commit pending changes after script.",
        choices=["yes", "no", "auto"],
        default=None,
        type=str,
    )
    parser.add_argument("--verify-command",
                        type=str,
                        help="Command to run to verify changes.")
    parser.add_argument("--recipe", type=str, help="Recipe to use.")
    args = parser.parse_args(argv)

    if args.recipe:
        from .recipe import Recipe
        recipe = Recipe.from_path(args.recipe)
    else:
        recipe = None

    if args.commit_pending:
        commit_pending = {
            "auto": None,
            "yes": True,
            "no": False
        }[args.commit_pending]
    elif recipe:
        commit_pending = recipe.commit_pending
    else:
        commit_pending = None

    if args.command:
        command = args.command
    elif recipe.command:
        command = recipe.command
    else:
        logging.exception('No command specified.')
        return 1

    local_tree, subpath = WorkingTree.open_containing('.')

    check_clean_tree(local_tree)

    try:
        result = script_runner(local_tree,
                               script=command,
                               commit_pending=commit_pending,
                               subpath=subpath)

        if result.description:
            logging.info('Succeeded: %s', result.description)

        if args.verify_command:
            try:
                subprocess.check_call(args.verify_command,
                                      shell=True,
                                      cwd=local_tree.abspath(subpath))
            except subprocess.CalledProcessError:
                logging.exception("Verify command failed.")
                return 1
    except Exception:
        reset_tree(local_tree, subpath)
        raise

    if args.diff:
        from breezy.diff import show_diff_trees
        old_tree = local_tree.revision_tree(result.old_revision)
        new_tree = local_tree.revision_tree(result.new_revision)
        show_diff_trees(old_tree,
                        new_tree,
                        sys.stdout.buffer,
                        old_label='old/',
                        new_label='new/')
    return 0