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]
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/'))
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, )
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
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)
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
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)
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