/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/plugins/commitfromnews/committemplate.py

  • Committer: Jelmer Vernooij
  • Date: 2017-07-23 23:43:55 UTC
  • mfrom: (6690.6.5 bundle-commitfromnews)
  • Revision ID: jelmer@jelmer.uk-20170723234355-v3g7apazhl5qc27w
Merge lp:~jelmer/brz/bundle-commitfromnews.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2010 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Logic to create commit templates."""
 
18
 
 
19
from __future__ import absolute_import
 
20
 
 
21
from ... import bugtracker, osutils, patiencediff
 
22
import re
 
23
 
 
24
_BUG_MATCH = re.compile(r'lp:(\d+)')
 
25
 
 
26
 
 
27
class CommitTemplate(object):
 
28
 
 
29
    def __init__(self, commit, message, filespec):
 
30
        """Create a commit template for commit with initial message message.
 
31
 
 
32
        :param commit: A Commit object for the in progress commit.
 
33
        :param message: The current message (which may be None).
 
34
        :param filespec: List of files to match
 
35
        """
 
36
        self.commit = commit
 
37
        self.message = message
 
38
        self.filespec = filespec
 
39
 
 
40
    def make(self):
 
41
        """Make the template.
 
42
 
 
43
        If NEWS is missing or not not modified, the original template is
 
44
        returned unaltered. Otherwise the changes from NEWS are concatenated
 
45
        with whatever message was provided to __init__.
 
46
        """
 
47
        delta = self.commit.builder.get_basis_delta()
 
48
        found_old_path = None
 
49
        found_entry = None
 
50
        for old_path, new_path, fileid, entry in delta:
 
51
            if new_path in self.filespec:
 
52
                found_entry = entry
 
53
                found_old_path = old_path
 
54
                break
 
55
        if not found_entry:
 
56
            return self.message
 
57
        if found_old_path is None:
 
58
            # New file
 
59
            _, new_chunks = list(
 
60
                self.commit.builder.repository.iter_files_bytes(
 
61
                    [(found_entry.file_id, found_entry.revision, None)]))[0]
 
62
            content = ''.join(new_chunks)
 
63
            return self.merge_message(content)
 
64
        else:
 
65
            # Get a diff. XXX Is this hookable? I thought it was, can't find it
 
66
            # though.... add DiffTree.diff_factories. Sadly thats not at the 
 
67
            # right level: we want to identify the changed lines, not have the
 
68
            # final diff: because we want to grab the sections for regions 
 
69
            # changed in new version of the file. So for now a direct diff
 
70
            # using patiencediff is done.
 
71
            old_revision = self.commit.basis_tree.get_file_revision(
 
72
                found_entry.file_id)
 
73
            needed = [(found_entry.file_id, found_entry.revision, 'new'),
 
74
                      (found_entry.file_id, old_revision, 'old')]
 
75
            contents = self.commit.builder.repository.iter_files_bytes(needed)
 
76
            lines = {}
 
77
            for name, chunks in contents:
 
78
                lines[name] = osutils.chunks_to_lines(chunks)
 
79
            new = lines['new']
 
80
            sequence_matcher = patiencediff.PatienceSequenceMatcher(
 
81
                None, lines['old'], new)
 
82
            new_lines = []
 
83
            for group in sequence_matcher.get_opcodes():
 
84
                tag, i1, i2, j1, j2 = group
 
85
                if tag == 'equal':
 
86
                    continue
 
87
                if tag == 'delete':
 
88
                    continue
 
89
                new_lines.extend(new[j1:j2])
 
90
            if not self.commit.revprops.get('bugs'):
 
91
                # TODO: Allow the user to configure the bug tracker to use
 
92
                # rather than hardcoding Launchpad.
 
93
                bt = bugtracker.tracker_registry.get('launchpad')
 
94
                bugids = []
 
95
                for line in new_lines:
 
96
                    bugids.extend(_BUG_MATCH.findall(line))
 
97
                self.commit.revprops['bugs'] = \
 
98
                    bugtracker.encode_fixes_bug_urls(
 
99
                        [bt.get_bug_url(bugid) for bugid in bugids])
 
100
            return self.merge_message(''.join(new_lines))
 
101
 
 
102
    def merge_message(self, new_message):
 
103
        """Merge new_message with self.message.
 
104
 
 
105
        :param new_message: A string message to merge with self.message.
 
106
        :return: A string with the merged messages.
 
107
        """
 
108
        if self.message is None:
 
109
            return new_message
 
110
        return self.message + new_message