This is an automated email from the git hooks/post-receive script. infinity0 pushed a commit to branch pu/debpatch in repository devscripts.
commit 290b7ffbe10e50a35b3e369dd4db7a101ae8e9cd Author: Ximin Luo <[email protected]> Date: Tue Apr 18 20:49:21 2017 +0200 debpatch: rewrite to use debian.changelog python module This allows us to avoid dpkg-parsechangelog and mostly dch. Also tidy up some other things based on reviewer feedback. --- debian/copyright | 20 +------- scripts/debpatch | 139 ++++++++++++++++++++--------------------------------- scripts/debpatch.1 | 4 ++ 3 files changed, 59 insertions(+), 104 deletions(-) diff --git a/debian/copyright b/debian/copyright index 438c48e..f3f40dc 100644 --- a/debian/copyright +++ b/debian/copyright @@ -21,8 +21,8 @@ the GPL, version 2 or later. - annotate-output, debdiff and nmudiff are released under version 2 (only) of the GPL. -- debsnap, diff2patches and git-deborig are released under version 3 - or later of the GPL +- debpatch, debsnap, diff2patches and git-deborig are released under + version 3 or later of the GPL - deb-reversion is under the Artistic License version 2.0. @@ -82,22 +82,6 @@ License: GPL-3+ On Debian systems, the complete text of the GNU General Public License version 3 can be found in the /usr/share/common-licenses/GPL-3 file. -Files: scripts/debpatch* -Copyright: 2016 Ximin Luo <[email protected]> -License: GPL-3+ - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - . - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - . - On Debian systems, the complete text of the GNU General Public License - version 3 can be found in the /usr/share/common-licenses/GPL-3 file. - Files: doc/suspicious-source.1 doc/wrap-and-sort.1 scripts/devscripts/* diff --git a/scripts/debpatch b/scripts/debpatch index fd861e3..578392a 100755 --- a/scripts/debpatch +++ b/scripts/debpatch @@ -20,6 +20,7 @@ Depends on dpkg-dev, devscripts, python3-unidiff, quilt. """ import argparse +import email.utils import hashlib import io import logging @@ -30,6 +31,9 @@ import shutil import subprocess import sys import tempfile +import time + +from debian.changelog import Changelog, ChangeBlock dirname = os.path.dirname basename = os.path.basename @@ -40,22 +44,6 @@ DCH_DUMMY_TAIL = "\n -- debpatch dummy tool <[email protected]> Thu, 01 Jan TRY_ENCODINGS = ["utf-8", "latin-1"] DISTRIBUTION_DEFAULT = "experimental" -def parse_dch(dch_str, *args): - return subprocess.run( - ["dpkg-parsechangelog", "-l-", "-c1"] + list(args), - input=dch_str, - check=True, - universal_newlines=True, - stdout=subprocess.PIPE, - ).stdout.rstrip() - -def read_dch(dch_str): - dch = {} - for i in ("Version", "Distribution", "Urgency", "Maintainer"): - dch[i] = parse_dch(dch_str, "-S"+i) - dch["Changes"] = "".join(parse_dch(dch_str, "-SChanges").splitlines(True)[3:]) - return dch - def is_dch(path): return (basename(path) == 'changelog' and basename(dirname(path)) == 'debian' @@ -72,68 +60,42 @@ def read_dch_patch(dch_patch): target_str = hunk_lines_to_str(hunk.target_lines()) # here we assume the debdiff has enough context to see the previous version # this should be true all the time in practice - source_version = parse_dch(source_str, "-SVersion") - target = read_dch(target_str) + source_version = str(Changelog(source_str, 1)[0].version) + target = Changelog(target_str, 1)[0] return source_version, target def apply_dch_patch(source_file, current, patch_name, old_version, target, dry_run): - # Do not change this text, unless you also add logic to detect markers from - # previously-released versions. - marker = "Patch %s applied by debpatch(1)." % patch_name - if marker in current["Changes"]: - logging.info("patch %s already applied to d/changelog", patch_name) - return target["Version"] - + target_version = str(target.version) dch_args = [] dch_env = dict(os.environ) - if target["Distribution"] == "UNRELEASED": - # UNRELEASED causes hard-to-reason-about behaviours in dch, let's avoid that - newdist = current["Distribution"] if current["Distribution"] != "UNRELEASED" else DISTRIBUTION_DEFAULT - logging.info("using distribution '%s' instead of 'UNRELEASED'", newdist) - target["Distribution"] = newdist - - if not old_version or not target["Version"].startswith(old_version): - logging.warn("don't know how to reapply version-change %s to %s" % - (old_version, target["Version"])) - version = subprocess.check_output(["sh", "-c", - "EDITOR=cat dch -n 2>/dev/null | dpkg-parsechangelog -l- -SVersion" - ]).decode("utf-8").rstrip() + if not old_version or not target_version.startswith(old_version): + logging.warn("don't know how to rebase version-change (%s => %s) onto %s" % + (old_version, target_version, old_version)) + newlog = subprocess.getoutput("EDITOR=cat dch -n 2>/dev/null").rstrip() + version = str(Changelog(newlog, 1)[0].version) logging.warn("using version %s based on `dch -n`; feel free to make me smarter", version) else: - version_suffix = target["Version"][len(old_version):] - version = current["Version"] + version_suffix + version_suffix = target_version[len(old_version):] + version = str(current[0].version) + version_suffix logging.info("using version %s based on suffix %s", version, version_suffix) if dry_run: return version - dch_args += ["-v", version] - dch_args += ["--force-distribution", "-D", target["Distribution"]] - dch_args += ["-u", target["Urgency"]] - if "Maintainer" in target: - dch_env["DEBEMAIL"] = target["Maintainer"] - del dch_env["DEBFULLNAME"] - - changes = target["Changes"] - if changes.lstrip().startswith("["): - changes = "\n" + changes + current._blocks.insert(0, target) + current.set_version(version) - token = "DEBPATCH PLACEHOLDER %s DELETEME" % random.randint(0, 2**64) - shutil.copy(source_file, source_file + ".debpatch.bak") + shutil.copy(source_file, source_file + ".new") try: - C(["dch", "-c", source_file] + dch_args + [token]) - C(["dch", "-c", source_file, "-a", marker], ) - C(["sed", "-e", "/%s/c\\\n%s" % (token, changes.replace("\n", "\\\n")), "-i", source_file]) + with open(source_file + ".new", "w") as fp: + current.write_to_open_file(fp) + os.rename(source_file + ".new", source_file) except: - os.rename(source_file, source_file + ".debpatch.err") logging.warn("failed to patch %s", source_file) - logging.warn("half-applied changes in %s", source_file + ".debpatch.err") + logging.warn("half-applied changes in %s", source_file + ".new") logging.warn("current working directory is %s", os.getcwd()) - os.rename(source_file + ".debpatch.bak", source_file) raise - else: - os.unlink(source_file + ".debpatch.bak") def call_patch(patch_str, *args, check=True, **kwargs): return subprocess.run( @@ -152,34 +114,27 @@ def check_patch(patch_str, *args, **kwargs): stderr=subprocess.DEVNULL, **kwargs).returncode == 0 -def apply_patch_str(patch_name, patch_str): - if check_patch(patch_str, "-N"): - call_patch(patch_str) - logging.info("patch %s applies!", patch_name) - elif check_patch(patch_str, "-R"): - logging.info("patch %s already applied", patch_name) - else: - call_patch(patch_str, "--dry-run") - raise ValueError("patch %s doesn't apply!", patch_name) - def debpatch(patch, patch_name, args): - if len(patch_name) > 60: - # this messes with our dch "already applied" logic detection, sorry - raise ValueError("pick a shorter patch name; sorry") - # don't change anything if... dry_run = args.target_version + with open(args.changelog) as fp: + current = Changelog(fp.read()) + changelog = list(filter(lambda x: is_dch(x.path), patch)) if not changelog: logging.info("no debian/changelog in patch: %s" % args.patch_file) old_version = None - target = { - "Version": None, - "Distribution": DISTRIBUTION_DEFAULT, - "Urgency": "low", - "Changes": " * Rebase patch %s." % patch_name, - } + target = ChangeBlock( + package = current[0].package, + author = "%s <%s>" % (os.getenv("DEBFULLNAME"), os.getenv("DEBEMAIL")), + date = email.utils.formatdate(time.time(), localtime=True), + version = None, + distributions = args.distribution, + urgency = "low", + changes = ["", " * Rebase patch %s." % patch_name, ""], + ) + target.add_trailing_line("") elif len(changelog) > 1: raise ValueError("more than one debian/changelog patch???") else: @@ -189,23 +144,32 @@ def debpatch(patch, patch_name, args): if args.source_version: if old_version: print(old_version) - return + return False if not dry_run: - apply_patch_str(patch_name, str(patch)) + patch_str = str(patch) + if check_patch(patch_str, "-N"): + call_patch(patch_str) + logging.info("patch %s applies!", patch_name) + elif check_patch(patch_str, "-R"): + logging.warn("patch %s already applied", patch_name) + return False + else: + call_patch(patch_str, "--dry-run", "-f") + raise ValueError("patch %s doesn't apply!", patch_name) # only apply d/changelog patch if the rest of the patch applied - with open(args.changelog) as fp: - current = read_dch(fp.read()) new_version = apply_dch_patch(args.changelog, current, patch_name, old_version, target, dry_run) if args.target_version: print(new_version) - return + return False if args.repl: import code code.interact(local=locals()) + return True + def main(args): parser = argparse.ArgumentParser( description='Apply a debdiff to a Debian source package') @@ -213,6 +177,9 @@ def main(args): help='Output more information') parser.add_argument('-c', '--changelog', default='debian/changelog', help='Path to debian/changelog; default: %(default)s') + parser.add_argument('-D', '--distribution', default='experimental', + help='Distribution to use, if the patch doesn\'t already contain a ' + 'changelog; default: %(default)s') parser.add_argument('--repl', action="store_true", help="Run the python REPL after processing.") parser.add_argument('--source-version', action="store_true", @@ -283,8 +250,8 @@ def main(args): C(["dpkg-source", "-x", "--skip-patches", args.orig_dsc_or_dir, builddir], stdout=stdout) origdir = os.getcwd() os.chdir(builddir) - debpatch(patch, patch_name, args) - if dry_run: + did_patch = debpatch(patch, patch_name, args) + if dry_run or not did_patch: return os.chdir(origdir) try: diff --git a/scripts/debpatch.1 b/scripts/debpatch.1 index 8af6fb7..e94f55c 100644 --- a/scripts/debpatch.1 +++ b/scripts/debpatch.1 @@ -69,6 +69,10 @@ Output more information \fB\-c\fR CHANGELOG, \fB\-\-changelog\fR CHANGELOG Path to debian/changelog; default: debian/changelog .TP +\fB\-D\fR DISTRIBUTION, \fB\-\-distribution\fR DISTRIBUTION +Distribution to use, if the patch doesn't already contain a changelog; default: +experimental +.TP \fB\-\-repl\fR Run the python REPL after processing. .TP -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/devscripts.git _______________________________________________ devscripts-devel mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/devscripts-devel
