merging debian changelog

Pierre Habouzit madcoder at debian.org
Mon Jan 7 23:55:08 UTC 2008


On lun, jan 07, 2008 at 10:43:58 +0000, Pierre Habouzit wrote:
>   I know this is a painful thing to do (if you consider the inherent
> triviality of it), hence I ended up writing a custom merger. This is all
> very sketchy, but I'm sure people will enhance it :)

  Here is a better version, that I believe can be used as a git merge
driver using this configuration snipplet:

[merge "merge-debchangelog"]
    name = Debian Changelog merge driver
    driver = /path/to/merge-debchangelog.py %O %A %B %A

and then, if I'm correct, you can in the .gitattribute of your debian/
directory set:

----8<----
/changelog merge=merge-debchangelog
---->8----

  I'm not 100% sure it will work, but I think so, and by the way, the
script is fully reusable for other SCM. Its usage is:

  merge-debchangelog.py ANCESTOR YOURS OTHER [OUTPUT]

it's safe to reuse any of the three other argument as the output file,
else stdout is used.

  I didn't put a copyright statement, but consider it be under the BSD
license.
-- 
·O·  Pierre Habouzit
··O                                                madcoder at debian.org
OOO                                                http://www.madism.org
-------------- next part --------------
#!/usr/bin/python
import re, sys, apt_pkg, difflib

apt_pkg.InitSystem()

header_re = re.compile('^\S+ \((?P<version>.*)\) .*;.*urgency=(?P<urgency>\w+).*')
footer_re = re.compile('^ --(?: (.*)  (\w\w\w, +(\d| \d|\d\d) \w\w\w \d\d\d\d ' +
                       '\d\d:\d\d:\d\d [-+]\d\d\d\d( \(.*\))?))?\s*$')
diff_strs = ["<<<<<<<\n", "=======\n", ">>>>>>>\n"]
diff_auto = {' ': 0, '-': 1, '+': 2}

def parse_changelog(file):
    chunks = {}
    cur = ""
    ver = None
    for line in open(file).readlines():
        match = header_re.match(line)
        if match:
            if ver: chunks[ver] = cur.strip()
            ver = match.group('version')
            cur = ''
        cur += line
    if ver: chunks[ver] = cur.strip()
    return chunks

def to_state(l, old, new):
    while old != new:
        l.append(diff_strs[old])
        old = (old + 1) % 3
    return new

def do_merge(orig, left, right):
    o = parse_changelog(orig) # unused for now
    l = parse_changelog(left)
    r = parse_changelog(right)
    state = 0
    conflict = False
    res = []
    versions = list(set(l.keys() + r.keys()))
    versions.sort(lambda x, y: -apt_pkg.VersionCompare(x, y))
    for ver in versions:
        if ver in l and ver in r and l[ver] != r[ver]:
            conflict = True
            for line in difflib.ndiff(l[ver].split('\n'), r[ver].split('\n')):
                state = to_state(res, state, diff_auto[line[0]])
                res.append(line[2:] + "\n")
            state = to_state(res, state, 0)
        else:
            res.append((l.get(ver) or r.get(ver)) + "\n")
        res.append("\n")
    return conflict, res

if len(sys.argv) not in (4, 5):
    sys.stderr.write("""\
usage: merge-debchangelog.py ORIGIN YOURS OTHER [OUTPUT]

  if OUTPUT isn't specified, standard out is assumed
""")

conflict, res = do_merge(sys.argv[1], sys.argv[2], sys.argv[3])
if len(sys.argv) is 4:
    sys.stdout.writelines(res)
else:
    open(sys.argv[4], "w+").writelines(res)
sys.exit(conflict)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.alioth.debian.org/pipermail/vcs-pkg-discuss/attachments/20080108/ee6d6cdf/attachment.pgp 


More information about the vcs-pkg-discuss mailing list