[debrepatch] 01/02: debrepatch: use debdiff-apply now in devscripts

Ximin Luo infinity0 at debian.org
Wed Jul 12 13:19:01 UTC 2017


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch master
in repository debrepatch.

commit d7a71d12f41859e54b5f9faa973bd24f2571eac4
Author: Ximin Luo <infinity0 at debian.org>
Date:   Wed Jul 12 15:00:47 2017 +0200

    debrepatch: use debdiff-apply now in devscripts
---
 README.rst |   3 -
 debpatch   | 289 -------------------------------------------------------------
 debpatch.1 | 112 ------------------------
 debrepatch |   6 +-
 4 files changed, 3 insertions(+), 407 deletions(-)

diff --git a/README.rst b/README.rst
index 1bbf026..7ab1899 100644
--- a/README.rst
+++ b/README.rst
@@ -18,9 +18,6 @@ Setting up
 Required:
 $ aptitude install quilt dpkg-dev devscripts python3-unidiff python3-debian
 
-Required, until we get this into devscripts
-$ which debpatch || { test -x ./debpatch && export PATH=$PWD:$PATH; }
-
 Optional, if you want to auto-upload or auto-rebuild:
 $ aptitude install dput reprotest
 
diff --git a/debpatch b/debpatch
deleted file mode 100755
index 09b7d53..0000000
--- a/debpatch
+++ /dev/null
@@ -1,289 +0,0 @@
-#!/usr/bin/python3
-# 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.
-#
-# See file /usr/share/common-licenses/GPL-3 for more details.
-#
-"""
-Apply a debdiff to a Debian source package.
-
-It handles d/changelog hunks specially, to avoid conflicts.
-
-Depends on dpkg-dev, devscripts, python3-unidiff, quilt.
-"""
-
-import argparse
-import email.utils
-import hashlib
-import io
-import logging
-import os
-import random
-import unidiff
-import shutil
-import subprocess
-import sys
-import tempfile
-import time
-
-from debian.changelog import Changelog, ChangeBlock
-
-dirname = os.path.dirname
-basename = os.path.basename
-C = subprocess.check_call
-
-# this can be any valid value, it doesn't appear in the final output
-DCH_DUMMY_TAIL = "\n -- debpatch dummy tool <infinity0 at debian.org>  Thu, 01 Jan 1970 00:00:00 +0000\n\n"
-CHBLOCK_DUMMY_PACKAGE = "debpatch PLACEHOLDER"
-TRY_ENCODINGS = ["utf-8", "latin-1"]
-DISTRIBUTION_DEFAULT = "experimental"
-
-def workaround_dpkg_865430(dscfile, origdir, stdout):
-    f = subprocess.check_output(["dcmd", "--tar", "echo", dscfile]).rstrip()
-    if not os.path.exists(os.path.join(origdir.encode("utf-8"), os.path.basename(f))):
-        C(["dcmd", "--tar", "cp", dscfile, origdir], stdout=stdout)
-
-def is_dch(path):
-    return (basename(path) == 'changelog'
-        and basename(dirname(path)) == 'debian'
-        and dirname(dirname(dirname(path))) == '')
-
-def hunk_lines_to_str(hunk_lines):
-    return "".join(map(lambda x: str(x)[1:], hunk_lines))
-
-def read_dch_patch(dch_patch):
-    if len(dch_patch) > 1:
-        raise ValueError("don't know how to deal with d/changelog patch that has more than one hunk")
-    hunk = dch_patch[0]
-    source_str = hunk_lines_to_str(hunk.source_lines()) + DCH_DUMMY_TAIL
-    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 = 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):
-    target_version = str(target.version)
-    dch_args = []
-    dch_env = dict(os.environ)
-
-    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 = str(current[0].version) + version_suffix
-        logging.info("using version %s based on suffix %s", version, version_suffix)
-
-    if dry_run:
-        return version
-
-    current._blocks.insert(0, target)
-    current.set_version(version)
-
-    shutil.copy(source_file, source_file + ".new")
-    try:
-        with open(source_file + ".new", "w") as fp:
-            current.write_to_open_file(fp)
-        os.rename(source_file + ".new", source_file)
-    except:
-        logging.warn("failed to patch %s", source_file)
-        logging.warn("half-applied changes in %s", source_file + ".new")
-        logging.warn("current working directory is %s", os.getcwd())
-        raise
-
-def call_patch(patch_str, *args, check=True, **kwargs):
-    return subprocess.run(
-        ["patch", "-p1"] + list(args),
-        input=patch_str,
-        universal_newlines=True,
-        check=check,
-        **kwargs)
-
-def check_patch(patch_str, *args, **kwargs):
-    return call_patch(patch_str,
-        "--dry-run", "-f", "--silent",
-        *args,
-        check=False,
-        stdout=subprocess.DEVNULL,
-        stderr=subprocess.DEVNULL,
-        **kwargs).returncode == 0
-
-def debpatch(patch, patch_name, args):
-    # don't change anything if...
-    dry_run = args.target_version or args.source_version
-
-    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 = ChangeBlock(
-            package = CHBLOCK_DUMMY_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:
-        patch.remove(changelog[0])
-        old_version, target = read_dch_patch(changelog[0])
-
-    if args.source_version:
-        if old_version:
-            print(old_version)
-        return False
-
-    # read this here so --source-version can work even without a d/changelog
-    with open(args.changelog) as fp:
-        current = Changelog(fp.read())
-    if target.package == CHBLOCK_DUMMY_PACKAGE:
-        target.package = current[0].package
-
-    if not dry_run:
-        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
-    new_version = apply_dch_patch(args.changelog, current, patch_name, old_version, target, dry_run)
-    if args.target_version:
-        print(new_version)
-        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')
-    parser.add_argument('-v', '--verbose', action="store_true",
-        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",
-        help="Don't apply the patch; instead print out the version of the "
-        "package that it is supposed to be applied to, or nothing if the patch "
-        "does not specify a source version.")
-    parser.add_argument('--target-version', action="store_true",
-        help="Don't apply the patch; instead print out the new version of the "
-        "package debpatch(1) would generate, when the patch is applied to the "
-        "the given target package, as specified by the other arguments.")
-    parser.add_argument('orig_dsc_or_dir', nargs='?', default=".",
-        help="Target to apply the patch to. This can either be an unpacked "
-        "source tree, or a .dsc file. In the former case, the directory is "
-        "modified in-place; in the latter case, a second .dsc is created. "
-        "Default: %(default)s")
-    parser.add_argument('patch_file', nargs='?', default="/dev/stdin",
-        help="Patch file to apply, in the format output by debdiff(1). "
-        "Default: %(default)s")
-    group1 = parser.add_argument_group('Options for .dsc patch targets')
-    group1.add_argument('--no-clean', action="store_true",
-        help="Don't clean temporary directories after a failure, so you can "
-        "examine what failed.")
-    group1.add_argument('--quilt-refresh', action="store_true",
-        help="If the building of the new source package fails, try to refresh "
-        "patches using quilt(1) then try building it again.")
-    group1.add_argument('-d', '--directory', default=None,
-        help="Extract the .dsc into this directory, which won't be cleaned up "
-        "after debpatch(1) exits. If not given, then it will be extracted to a "
-        "temporary directory.")
-    args = parser.parse_args(args)
-    #print(args)
-
-    if args.verbose:
-        logging.getLogger().setLevel(logging.DEBUG)
-
-    with open(args.patch_file, 'rb') as fp:
-        data = fp.read()
-    for enc in TRY_ENCODINGS:
-        try:
-            patch = unidiff.PatchSet(data.splitlines(keepends=True), encoding=enc)
-            break
-        except:
-            if enc == TRY_ENCODINGS[-1]:
-                raise
-            else:
-                continue
-
-    patch_name = '%s:%s' % (
-        basename(args.patch_file),
-        hashlib.sha256(data).hexdigest()[:20 if args.patch_file == '/dev/stdin' else 8])
-    quiet = args.source_version or args.target_version
-    dry_run = args.source_version or args.target_version
-    stdout = subprocess.DEVNULL if quiet else None # user can redirect stderr themselves
-
-    # change directory before applying patches
-    if os.path.isdir(args.orig_dsc_or_dir):
-        os.chdir(args.orig_dsc_or_dir)
-        debpatch(patch, patch_name, args)
-    elif os.path.isfile(args.orig_dsc_or_dir):
-        dscfile = args.orig_dsc_or_dir
-        parts = os.path.splitext(os.path.basename(dscfile))
-        if parts[1] != ".dsc":
-            raise ValueError("unrecognised patch target: %s" % dscfile)
-        extractdir = args.directory if args.directory else tempfile.mkdtemp()
-        if not os.path.isdir(extractdir):
-            os.makedirs(extractdir)
-        try:
-            builddir = os.path.join(extractdir, parts[0]) # dpkg-source doesn't like existing dirs
-            C(["dpkg-source", "-x", "--skip-patches", dscfile, builddir], stdout=stdout)
-            origdir = os.getcwd()
-            workaround_dpkg_865430(dscfile, origdir, stdout)
-            os.chdir(builddir)
-            did_patch = debpatch(patch, patch_name, args)
-            if dry_run or not did_patch:
-                return
-            os.chdir(origdir)
-            try:
-                C(["dpkg-source", "-b", builddir])
-            except subprocess.CalledProcessError:
-                if args.quilt_refresh:
-                    C(["sh", "-c", """
-set -ex
-export QUILT_PATCHES=debian/patches
-while quilt push; do quilt refresh; done
-"""
-                        ], cwd=builddir)
-                    C(["dpkg-source", "-b", builddir])
-                else:
-                    raise
-        finally:
-            cleandir = builddir if args.directory else extractdir
-            if args.no_clean:
-                logging.warn("you should clean up temp files in %s", cleandir)
-            else:
-                shutil.rmtree(cleandir)
-
-if __name__ == "__main__":
-    sys.exit(main(sys.argv[1:]))
diff --git a/debpatch.1 b/debpatch.1
deleted file mode 100644
index e94f55c..0000000
--- a/debpatch.1
+++ /dev/null
@@ -1,112 +0,0 @@
-.\" Copyright (c) 2016, Ximin Luo <infinity0 at debian.org>
-.\"
-.\" 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.
-.\"
-.\" See file /usr/share/common-licenses/GPL-3 for more details.
-.\"
-.TH DEBPATCH 1 "Debian Utilities" "DEBIAN"
-
-.SH NAME
-debpatch \- apply a debdiff to a Debian source package
-
-.SH SYNOPSIS
-.B debpatch
-[options] [orig_dsc_or_dir] [patch_file]
-.br
-.B debpatch
-[options] < [patch_file]
-
-.SH DESCRIPTION
-.B debpatch
-takes a \fIpatchfile\fR that describes the differences between two Debian
-source packages \fIold\fR and \fInew\fR, and applies it to a target Debian
-source package \fIorig\fR.
-.PP
-\fIorig\fR could either be the same as \fIold\fR or it could be different.
-\fIpatchfile\fR is expected to be a unified diff between two Debian source
-trees, as what
-.BR debdiff (1)
-normally generates.
-.PP
-Any changes to \fIdebian/changelog\fR are dealt with specially, to avoid the
-conflicts that changelog diffs typically produce when applied naively. The
-exact behaviour may be tweaked in the future, so one should not rely on it.
-.PP
-If \fIpatchfile\fR does not apply to \fIorig\fR, even after the special-casing
-of \fIdebian/changelog\fR, no changes are made and
-.BR debpatch (1)
-will exit with a non-zero error code.
-
-.SH ARGUMENTS
-.TP
-orig_dsc_or_dir
-Target to apply the patch to. This can either be an unpacked source tree, or a
-\[char46]dsc file. In the former case, the directory is modified in\-place; in
-the latter case, a second .dsc is created. Default: \fI.\fP
-.TP
-patch_file
-Patch file to apply, in the format output by
-.BR debdiff (1).
-Default:
-\fI\,/dev/stdin\/\fP
-
-.SH OPTIONS
-.TP
-\fB\-h\fR, \fB\-\-help\fR
-show this help message and exit
-.TP
-\fB\-v\fR, \fB\-\-verbose\fR
-Output more information
-.TP
-\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
-\fB\-\-source\-version\fR
-Don't apply the patch; instead print out the version of the package that it is
-supposed to be applied to, or nothing if the patch does not specify a source
-version.
-.TP
-\fB\-\-target\-version\fR
-Don't apply the patch; instead print out the new version of the package
-.BR debpatch (1)
-would generate, when the patch is applied to the the given target
-package, as specified by the other arguments.
-.SS "For .dsc patch targets:"
-.TP
-\fB\-\-no\-clean\fR
-Don't clean temporary directories after a failure, so you can examine what
-failed.
-.TP
-\fB\-\-quilt\-refresh\fR
-If the building of the new source package fails, try to refresh patches using
-.BR quilt (1)
-then try building it again.
-.TP
-\fB\-d\fR DIRECTORY, \fB\-\-directory\fR DIRECTORY
-Extract the .dsc into this directory, which won't be cleaned up after
-.BR debpatch (1)
-exits. If not given, then it will be extracted to a temporary directory.
-
-.SH AUTHORS
-\fBdebpatch\fR and this manual page were written by Ximin Luo
-<infinity0 at debian.org>
-.PP
-Both are released under the GNU General Public License, version 3 or later.
-
-.SH SEE ALSO
-.BR debdiff (1)
diff --git a/debrepatch b/debrepatch
index d2ed521..52d7a23 100755
--- a/debrepatch
+++ b/debrepatch
@@ -22,7 +22,7 @@ while getopts 'hyut:fb:p:' o; do
     h )     cat <<EOF
 $USAGE
 
-Use debpatch(1) to apply a debdiff to the latest version of a given source
+Use debdiff-apply(1) to apply a debdiff to the latest version of a given source
 package. If successful and the package is at a different version than what is
 mentioned in d/changelog from the debdiff, then run a command from inside the
 unpacked and patched package source directory.
@@ -91,7 +91,7 @@ srcdir="$srcpkg-$(echo "$oldver" | sed -re 's/([^:]*:)?(.*)-.*/\2/')"
 apt-get -t "$suite" source "$srcpkg"
 olddsc="$(ls -1 *.dsc)" # TODO: probably more correct to use $oldver
 rm -rf "$srcdir"
-debpatch --verbose --no-clean --directory . "$olddsc" "$patchfile"
+debdiff-apply --verbose --no-clean --directory . "$olddsc" "$patchfile"
 newdsc="$(ls -1 *.dsc | grep -v -F "$olddsc")"
 
 log I "$srcpkg patched successfully"
@@ -102,7 +102,7 @@ log I "updated patch written to $patchdir/$srcpkg.patch.new"
 
 if [ -z "$*" ]; then
     exit 0
-elif [ "$(debpatch --source-version < "$patchfile")" = "$oldver" ] && ! $force_postpatch; then
+elif [ "$(debdiff-apply --source-version < "$patchfile")" = "$oldver" ] && ! $force_postpatch; then
     exit 0
 fi
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/debrepatch.git



More information about the Reproducible-commits mailing list