37
from .errors import BzrError
38
from .hooks import Hooks
41
class BadCommitMessageEncoding(BzrError):
43
_fmt = 'The specified commit message contains characters unsupported by '\
44
'the current encoding.'
34
from brzlib.errors import BzrError, BadCommitMessageEncoding
35
from brzlib.hooks import Hooks
48
"""Return sequence of possible editor binaries for the current platform"""
39
"""Return a sequence of possible editor binaries for the current platform"""
50
yield os.environ["BRZ_EDITOR"], '$BRZ_EDITOR'
41
yield os.environ["BZR_EDITOR"], '$BZR_EDITOR'
54
45
e = config.GlobalStack().get('editor')
56
yield e, bedding.config_path()
47
yield e, config.config_filename()
58
49
for varname in 'VISUAL', 'EDITOR':
59
50
if varname in os.environ:
72
63
for candidate, candidate_source in _get_editor():
73
64
edargs = cmdline.split(candidate)
66
## mutter("trying editor: %r", (edargs +[filename]))
75
67
x = call(edargs + [filename])
77
69
if candidate_source is not None:
78
70
# We tried this editor because some user configuration (an
79
71
# environment variable or config file) said to try it. Let
92
84
raise BzrError("Could not start any editor.\nPlease specify one with:\n"
93
" - $BRZ_EDITOR\n - editor=/some/path in %s\n"
94
" - $VISUAL\n - $EDITOR" %
95
bedding.config_path())
85
" - $BZR_EDITOR\n - editor=/some/path in %s\n"
86
" - $VISUAL\n - $EDITOR" % \
87
config.config_filename())
98
90
DEFAULT_IGNORE_LINE = "%(bar)s %(msg)s %(bar)s" % \
99
{'bar': '-' * 14, 'msg': 'This line and the following will be ignored'}
91
{ 'bar' : '-' * 14, 'msg' : 'This line and the following will be ignored' }
102
94
def edit_commit_message(infotext, ignoreline=DEFAULT_IGNORE_LINE,
119
111
:return: commit message or None.
122
if start_message is not None:
114
if not start_message is None:
123
115
start_message = start_message.encode(osutils.get_user_encoding())
124
116
infotext = infotext.encode(osutils.get_user_encoding(), 'replace')
125
117
return edit_commit_message_encoded(infotext, ignoreline, start_message)
149
141
msgfilename = None
151
143
msgfilename, hasinfo = _create_temp_file_with_commit_template(
152
infotext, ignoreline, start_message)
144
infotext, ignoreline, start_message)
153
145
if not msgfilename:
155
147
basename = osutils.basename(msgfilename)
156
msg_transport = transport.get_transport_from_path(
157
osutils.dirname(msgfilename))
148
msg_transport = transport.get_transport_from_path(osutils.dirname(msgfilename))
158
149
reference_content = msg_transport.get_bytes(basename)
159
150
if not _run_editor(msgfilename):
162
153
if edited_content == reference_content:
163
154
if not ui.ui_factory.confirm_action(
164
155
u"Commit message was not edited, use anyway",
165
"breezy.msgeditor.unchanged",
156
"brzlib.msgeditor.unchanged",
167
158
# Returning "" makes cmd_commit raise 'empty commit message
168
159
# specified' which is a reasonable error, given the user has
169
160
# rejected using the unedited template.
173
164
lastline, nlines = 0, 0
174
with codecs.open(msgfilename, mode='rb', encoding=osutils.get_user_encoding()) as f:
165
# codecs.open() ALWAYS opens file in binary mode but we need text mode
166
# 'rU' mode useful when bzr.exe used on Cygwin (bialix 20070430)
167
f = file(msgfilename, 'rU')
170
for line in codecs.getreader(osutils.get_user_encoding())(f):
177
171
stripped_line = line.strip()
178
172
# strip empty line before the log message starts
234
230
tmp_fileno, msgfilename = tempfile.mkstemp(prefix='bzr_log.',
235
231
dir=tmpdir, text=True)
236
with os.fdopen(tmp_fileno, 'wb') as msgfile:
232
msgfile = os.fdopen(tmp_fileno, 'w')
237
234
if start_message is not None:
238
msgfile.write(b"%s\n" % start_message)
235
msgfile.write("%s\n" % start_message)
240
237
if infotext is not None and infotext != "":
242
trailer = b"\n\n%s\n\n%s" % (
243
ignoreline.encode(osutils.get_user_encoding()), infotext)
244
msgfile.write(trailer)
239
msgfile.write("\n\n%s\n\n%s" %(ignoreline, infotext))
248
245
return (msgfilename, hasinfo)
258
255
# TODO: Rather than running the status command, should prepare a draft of
259
256
# the revision to be committed, then pause and ask the user to
260
257
# confirm/write a message.
261
from .status import show_tree_status
258
from StringIO import StringIO # must be unicode-safe
259
from brzlib.status import show_tree_status
262
260
status_tmp = StringIO()
263
261
show_tree_status(working_tree, specific_files=specific_files,
264
262
to_file=status_tmp, verbose=True)
276
274
# TODO: Rather than running the status command, should prepare a draft of
277
275
# the revision to be committed, then pause and ask the user to
278
276
# confirm/write a message.
279
from .diff import show_diff_trees
277
from StringIO import StringIO # must be unicode-safe
278
from brzlib.diff import show_diff_trees
281
280
template = make_commit_message_template(working_tree, specific_files)
282
281
template = template.encode(output_encoding, "replace")
286
285
show_diff_trees(working_tree.basis_tree(),
287
286
working_tree, stream, specific_files,
288
287
path_encoding=output_encoding)
289
template = template + b'\n' + stream.getvalue()
288
template = template + '\n' + stream.getvalue()
305
304
These are all empty initially.
307
Hooks.__init__(self, "breezy.msgeditor", "hooks")
309
'set_commit_message',
306
Hooks.__init__(self, "brzlib.msgeditor", "hooks")
307
self.add_hook('set_commit_message',
310
308
"Set a fixed commit message. "
311
309
"set_commit_message is called with the "
312
"breezy.commit.Commit object (so you can also change e.g. "
313
"revision properties by editing commit.builder._revprops) and the "
314
"message so far. set_commit_message must return the message to "
315
"use or None if it should use the message editor as normal.",
318
'commit_message_template',
310
"brzlib.commit.Commit object (so you can also change e.g. revision "
311
"properties by editing commit.builder._revprops) and the message "
312
"so far. set_commit_message must return the message to use or None"
313
" if it should use the message editor as normal.", (2, 4))
314
self.add_hook('commit_message_template',
319
315
"Called when a commit message is being generated. "
320
"commit_message_template is called with the breezy.commit.Commit "
316
"commit_message_template is called with the brzlib.commit.Commit "
321
317
"object and the message that is known so far. "
322
318
"commit_message_template must return a new message to use (which "
323
319
"could be the same as it was given). When there are multiple "