1
# Copyright (C) 2010 Canonical Ltd
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.
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.
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
17
"""Logic to create commit templates."""
19
from bzrlib.lazy_import import lazy_import
20
lazy_import(globals(), """
21
from bzrlib import osutils, patiencediff
24
class CommitTemplate(object):
26
def __init__(self, commit, message):
27
"""Create a commit template for commit with initial message message.
29
:param commit: A Commit object for the in progress commit.
30
:param message: The current message (which may be None).
33
self.message = message
38
If NEWS is missing or not not modified, the original template is
39
returned unaltered. Otherwise the changes from NEWS are concatenated
40
with whatever message was provided to __init__.
43
delta = self.commit.builder.get_basis_delta()
44
except AssertionError:
45
# Not 2a, someone can write a slow-format code path if they want
50
for old_path, new_path, fileid, entry in delta:
51
if new_path == 'NEWS':
53
found_old_path = old_path
57
if found_old_path is None:
59
_, new_chunks = list(self.commit.builder.repository.iter_files_bytes(
60
[(found_entry.file_id, found_entry.revision, None)]))[0]
61
content = ''.join(new_chunks)
62
return self.merge_message(content)
64
# Get a diff. XXX Is this hookable? I thought it was, can't find it
65
# though.... add DiffTree.diff_factories. Sadly thats not at the
66
# right level: we want to identify the changed lines, not have the
67
# final diff: because we want to grab the sections for regions
68
# changed in new version of the file. So for now a direct diff
69
# using patiencediff is done.
70
old_entry = self.commit.basis_tree.inventory[found_entry.file_id]
71
needed = [(found_entry.file_id, found_entry.revision, 'new'),
72
(old_entry.file_id, old_entry.revision, 'old')]
73
contents = self.commit.builder.repository.iter_files_bytes(needed)
75
for name, chunks in contents:
76
lines[name] = osutils.chunks_to_lines(chunks)
78
sequence_matcher = patiencediff.PatienceSequenceMatcher(
79
None, lines['old'], new)
81
for group in sequence_matcher.get_opcodes():
82
tag, i1, i2, j1, j2 = group
87
new_lines.extend(new[j1:j2])
88
return ''.join(new_lines)
90
def merge_message(self, new_message):
91
"""Merge new_message with self.message.
93
:param new_message: A string message to merge with self.message.
94
:return: A string with the merged messages.
96
if self.message is None:
98
return self.message + new_message