/breezy-debian/trunk

To get this branch, use:
bzr branch https://code.breezy-vcs.org/breezy-debian/trunk
393.4.1 by Scott James Remnant
Bring in Scott James Remnant's merge_changelog script.
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
# Copyright ? 2008 Canonical Ltd.
4
# Author: Scott James Remnant <scott@ubuntu.com>.
5
# Hacked up by: Bryce Harrington <bryce@ubuntu.com>
6
#
7
# This program is free software: you can redistribute it and/or modify
8
# it under the terms of version 3 of the GNU General Public License as
9
# published by the Free Software Foundation.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
750 by Jelmer Vernooij
use relative imports.
19
from __future__ import absolute_import
20
632.1.3 by Jelmer Vernooij
Cope with dpkg-mergechangelogs not being available.
21
import errno
581.3.3 by Andrew Bennetts
Update tests for different (but mostly better) behaviour provided by using dpkg-mergechangelogs.
22
import logging
581.3.1 by Andrew Bennetts
Quick hack to use dpkg-mergechangelogs.
23
import os.path
581.3.4 by Andrew Bennetts
Workaround bug 815700 in dpkg-mergechangelogs (it emits slightly non-standard conflict markers), and link to bug 815704 in an XXX comment in a test.
24
import re
581.3.1 by Andrew Bennetts
Quick hack to use dpkg-mergechangelogs.
25
import shutil
26
import subprocess
27
import tempfile
393.4.1 by Scott James Remnant
Bring in Scott James Remnant's merge_changelog script.
28
750 by Jelmer Vernooij
use relative imports.
29
from ... import (
393.4.14 by Vincent Ladeuil
Use the shiny merge.ConfigurableFileMerger.
30
    merge,
660.1.1 by Martin Packman
Fix handling of encoding with logging in merge_changelogs and tests
31
    osutils,
393.4.14 by Vincent Ladeuil
Use the shiny merge.ConfigurableFileMerger.
32
    )
33
400.2.1 by John Arbash Meinel
Lots of simplification.
34
581.3.3 by Andrew Bennetts
Update tests for different (but mostly better) behaviour provided by using dpkg-mergechangelogs.
35
# A logger in the 'bzr' hierarchy.  By default messages will be propagated to
36
# the standard bzr logger, but tests can easily intercept just this logger if
37
# they wish.
761 by Jelmer Vernooij
Fix remaining tests.
38
_logger = logging.getLogger('breezy.plugins.debian.merge_changelog')
581.3.3 by Andrew Bennetts
Update tests for different (but mostly better) behaviour provided by using dpkg-mergechangelogs.
39
40
393.4.14 by Vincent Ladeuil
Use the shiny merge.ConfigurableFileMerger.
41
class ChangeLogFileMerge(merge.ConfigurableFileMerger):
42
43
    name_prefix = 'deb_changelog'
44
    default_files = ['debian/changelog']
45
46
    def merge_text(self, params):
1007 by Jelmer Vernooij
Some reformatting.
47
        return merge_changelog(
48
            params.this_lines, params.other_lines, params.base_lines)
581.3.1 by Andrew Bennetts
Quick hack to use dpkg-mergechangelogs.
49
393.4.1 by Scott James Remnant
Bring in Scott James Remnant's merge_changelog script.
50
400.2.2 by John Arbash Meinel
Make sure that the blocks are in sorted order before we do anything else.
51
def merge_changelog(this_lines, other_lines, base_lines=[]):
393.4.1 by Scott James Remnant
Bring in Scott James Remnant's merge_changelog script.
52
    """Merge a changelog file."""
581.3.1 by Andrew Bennetts
Quick hack to use dpkg-mergechangelogs.
53
    # Write the BASE, THIS and OTHER versions to files in a temporary
54
    # directory, and use dpkg-mergechangelogs to merge them.
55
    tmpdir = tempfile.mkdtemp('deb_changelog_merge')
56
    try:
57
        def writelines(filename, lines):
831 by Jelmer Vernooij
More python3 porting work.
58
            with open(filename, 'wb') as f:
581.3.1 by Andrew Bennetts
Quick hack to use dpkg-mergechangelogs.
59
                for line in lines:
60
                    f.write(line)
61
        base_filename = os.path.join(tmpdir, 'changelog.base')
62
        this_filename = os.path.join(tmpdir, 'changelog.this')
63
        other_filename = os.path.join(tmpdir, 'changelog.other')
64
        writelines(base_filename, base_lines)
65
        writelines(this_filename, this_lines)
66
        writelines(other_filename, other_lines)
632.1.3 by Jelmer Vernooij
Cope with dpkg-mergechangelogs not being available.
67
        try:
1007 by Jelmer Vernooij
Some reformatting.
68
            proc = subprocess.Popen(
69
                ['dpkg-mergechangelogs', base_filename, this_filename,
70
                 other_filename], stdout=subprocess.PIPE,
632.1.3 by Jelmer Vernooij
Cope with dpkg-mergechangelogs not being available.
71
                stderr=subprocess.PIPE)
798 by Jelmer Vernooij
Initial work on python3 support.
72
        except OSError as e:
632.1.3 by Jelmer Vernooij
Cope with dpkg-mergechangelogs not being available.
73
            if e.errno == errno.ENOENT:
74
                # No dpkg-mergechangelogs command available
638 by Vincent Ladeuil
Fix the returned values when dpkg-mergechangelogs is not available.
75
                return 'not_applicable', ''
632.1.3 by Jelmer Vernooij
Cope with dpkg-mergechangelogs not being available.
76
            raise
581.3.1 by Andrew Bennetts
Quick hack to use dpkg-mergechangelogs.
77
        stdout, stderr = proc.communicate()
78
        retcode = proc.returncode
581.3.3 by Andrew Bennetts
Update tests for different (but mostly better) behaviour provided by using dpkg-mergechangelogs.
79
        if stderr:
80
            # Relay the warning from dpkg-mergechangelogs to the user.  We
81
            # don't decorate the messages at all, as dpkg-mergechangelogs
82
            # warnings are already prefixed with "dpkg-mergechangelogs:
83
            # warning:" which makes the origin of the messages quite clear.
660.1.1 by Martin Packman
Fix handling of encoding with logging in merge_changelogs and tests
84
            encoding = osutils.get_user_encoding()
85
            # Errors are output using the locale, and log needs unicode.
86
            _logger.warning('%s', stderr.decode(encoding, "replace"))
581.3.1 by Andrew Bennetts
Quick hack to use dpkg-mergechangelogs.
87
        if retcode == 1:
581.3.4 by Andrew Bennetts
Workaround bug 815700 in dpkg-mergechangelogs (it emits slightly non-standard conflict markers), and link to bug 815704 in an XXX comment in a test.
88
            # dpkg-mergechangelogs reports a conflict.  Unfortunately it uses
89
            # slightly non-standard conflict markers (<http://pad.lv/815700>:
90
            # "<<<<<<" rather than "<<<<<<<", i.e. 6 chars instead of 7), so we
91
            # correct that here to make the results of this plugin as
92
            # consistent with regular bzr usage as possible.  Note that
93
            # conflict markers are never valid lines in a changelog file, so
94
            # it's reasonable for us to assume that any line that looks like a
95
            # conflict marker is a conflict marker (rather than valid content).
96
            # At worst a conflicted merge of an invalid changelog file that
97
            # already contained a non-standard conflict marker will have that
98
            # conflict marker made standard, which is more like a feature than
99
            # a bug!
100
            def replace_func(match_obj):
101
                match_text = match_obj.group(0)
102
                return match_text[0] * 7
831 by Jelmer Vernooij
More python3 porting work.
103
            stdout = re.sub(b'(?m)^[<=>]{6}$', replace_func, stdout)
834 by Jelmer Vernooij
More python3 fixes.
104
            return 'conflicted', stdout.splitlines(True)
660.1.3 by Martin Packman
Make non-zero return from dpkg-mergechangelog fall back to other merge handlers
105
        elif retcode != 0:
106
            # dpkg-mergechangelogs exited with an error. There is probably no
107
            # output at all, but regardless the merge should fall back to
108
            # another method.
1007 by Jelmer Vernooij
Some reformatting.
109
            _logger.warning(
110
                "dpkg-mergechangelogs failed with status %d", retcode)
834 by Jelmer Vernooij
More python3 fixes.
111
            return 'not_applicable', stdout.splitlines(True)
400.2.3 by John Arbash Meinel
Fix bug #516060, implement 3-way changelog merge.
112
        else:
834 by Jelmer Vernooij
More python3 fixes.
113
            return 'success', stdout.splitlines(True)
581.3.1 by Andrew Bennetts
Quick hack to use dpkg-mergechangelogs.
114
    finally:
115
        shutil.rmtree(tmpdir)