[RFC] CommitTemplate (was Re: [ANN bzr-vim] syntax and ftplugin for bzr_log.* files)
Adeodato Simó
dato at net.com.org.es
Fri Jul 28 03:08:08 BST 2006
> Bundle attached.
Yay.
--
Adeodato Simó dato at net.com.org.es
Debian Developer adeodato at debian.org
Kindness is a language which the deaf can hear and the blind can read.
-- Mark Twain
-------------- next part --------------
# Bazaar revision bundle v0.8
#
# message:
# bzrlib/commit_template.py:
# - New file.
#
# Generalize the creation of templates for commit files with a
# CommitTemplate class, and register them the way log.py does with
# LogFormatter.
#
# Provide a DefaultCommitTemplate which replaces
# msgeeditor.make_commit_message_template.
#
# bzrlib/builtins.py:
# - (cmd_commit) accept a --template option.
#
# bzrlib/config.py:
# - add a commit_template configuration variable.
#
# bzrlib/msgeditor.py:
# - (make_commit_message_template) drop.
# - (DEFAULT_IGNORE_LINE) drop.
# - (edit_commit_message) accept a CommitTemplate, but remain compatible
# if a string is provided.
#
# committer: Adeodato Simó <dato at net.com.org.es>
# date: Fri 2006-07-28 03:05:37.003999949 +0200
=== added file bzrlib/commit_template.py // file-id:commit_template.py-20060727
... 224804-z60z2apdfnukp3or-1
--- /dev/null
+++ bzrlib/commit_template.py
@@ -0,0 +1,85 @@
+# Copyright (C) 2006 by Canonical Ltd
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""Commit file template support."""
+
+class CommitTemplate(object):
+ """Abstract class to prepare a commit template."""
+
+ def __init__(self, working_tree, specific_files):
+ self.working_tree = working_tree
+ self.specific_files = specific_files
+
+ self.template = self._template()
+ self.comment = self._comment()
+ self.ignoreline = self._ignoreline()
+
+ def _template(self):
+ return '\n'
+
+ def _comment(self):
+ return '\n'
+
+ def _ignoreline(self):
+ return "%(bar)s %(msg)s %(bar)s" % { 'bar' : '-' * 14,
+ 'msg' : 'This line and the following will be ignored' }
+
+
+class DefaultCommitTemplate(CommitTemplate):
+ def _comment(self):
+ from StringIO import StringIO # must be unicode-safe
+ from bzrlib.status import show_tree_status
+
+ status_tmp = StringIO()
+ show_tree_status(self.working_tree, specific_files=self.specific_files,
+ to_file=status_tmp)
+
+ return status_tmp.getvalue()
+
+
+class DiffCommitTemplate(DefaultCommitTemplate):
+ def _comment(self):
+ comment = DefaultCommitTemplate._comment(self)
+ # TODO implement for real
+ comment += "\n# START DIFF"
+ return comment
+
+
+# TODO This is copied from log.py, maybe refactor?
+COMMIT_TEMPLATES = {
+ 'default': DefaultCommitTemplate,
+ 'diff': DiffCommitTemplate,
+ # Remember to update config.__doc__ when adding a template
+}
+
+def commit_template(name, *args, **kwargs):
+ """Construct a CommitTemplate from arguments.
+
+ name:
+ Name of the CommitTemplate to construct; currently 'default' and
+ 'diff' are supported.
+ """
+ from bzrlib.errors import BzrCommandError
+ try:
+ return COMMIT_TEMPLATES[name](*args, **kwargs)
+ except KeyError:
+ raise BzrCommandError("unknown commit template: %r" % name)
+
+def register_commit_template(name, commit_template):
+ COMMIT_TEMPLATES[name] = commit_template
+
+def available_commit_templates():
+ return COMMIT_TEMPLATES.keys()
=== modified file bzrlib/builtins.py
--- bzrlib/builtins.py
+++ bzrlib/builtins.py
@@ -1678,6 +1678,8 @@
# XXX: verbose currently does nothing
+ from bzrlib.commit_template import available_commit_templates
+
takes_args = ['selected*']
takes_options = ['message', 'verbose',
Option('unchanged',
@@ -1688,6 +1690,12 @@
Option('strict',
help="refuse to commit if there are unknown "
"files in the working tree."),
+ Option('template', type=str,
+ argname='templat',
+ help="template format to use for commit files. "
+ "Possible values are: %s." % (', '.join(
+ sorted(available_commit_templates())))
+ ),
Option('local',
help="perform a local only commit in a bound "
"branch. Such commits are not pushed to "
@@ -1698,12 +1706,12 @@
aliases = ['ci', 'checkin']
def run(self, message=None, file=None, verbose=True, selected_list=None,
- unchanged=False, strict=False, local=False):
+ unchanged=False, strict=False, template=None, local=False):
from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
StrictCommitFailed)
- from bzrlib.msgeditor import edit_commit_message, \
- make_commit_message_template
+ from bzrlib.msgeditor import edit_commit_message
+ from bzrlib.commit_template import commit_template
from tempfile import TemporaryFile
# TODO: Need a blackbox test for invoking the external editor; may be
@@ -1724,7 +1732,9 @@
if local and not tree.branch.get_bound_location():
raise errors.LocalRequiresBoundBranch()
if message is None and not file:
- template = make_commit_message_template(tree, selected_list)
+ if (template == None):
+ template = tree.branch.get_config().commit_template()
+ template = commit_template(template, tree, selected_list)
message = edit_commit_message(template)
if message is None:
raise BzrCommandError("please specify a commit message"
=== modified file bzrlib/config.py
--- bzrlib/config.py
+++ bzrlib/config.py
@@ -28,6 +28,7 @@
create_signatures=always|never|when-required(default)
gpg_signing_command=name-of-program
log_format=name-of-format
+commit_template=name-of-template
in locations.conf, you specify the url of a branch and options for it.
Wildcards may be used - * and ? as normal in shell completion. Options
@@ -51,6 +52,9 @@
branch is configured to require them.
log_format - This options set the default log format. Options are long,
short, line, or a plugin can register new formats
+commit_template - this option sets the default template for commit files.
+ Possible values are default, diff, or a plugin can register
+ new templates.
In bazaar.conf you can also define aliases in the ALIASES sections, example
@@ -144,6 +148,17 @@
"""See log_format()."""
return None
+ def commit_template(self):
+ """What commit template class should be used"""
+ result = self._commit_template()
+ if result is None:
+ result = "default"
+ return result
+
+ def _commit_template(self):
+ """See commit_template()."""
+ return None
+
def __init__(self):
super(Config, self).__init__()
@@ -286,6 +301,10 @@
"""See Config.log_format."""
return self._get_user_option('log_format')
+ def _commit_template(self):
+ """See Config.commit_template."""
+ return self._get_user_option('commit_template')
+
def __init__(self, get_filename):
super(IniBasedConfig, self).__init__()
self._get_filename = get_filename
@@ -560,6 +579,10 @@
"""See Config.log_format."""
return self._get_best_value('_log_format')
+ def _commit_template(self):
+ """See Config.commit_template."""
+ return self._get_best_value('_commit_template')
+
def ensure_config_dir_exists(path=None):
"""Make sure a configuration directory exists.
=== modified file bzrlib/msgeditor.py
--- bzrlib/msgeditor.py
+++ bzrlib/msgeditor.py
@@ -25,6 +25,7 @@
import bzrlib
import bzrlib.config as config
+import bzrlib.commit_template as c_t
from bzrlib.errors import BzrError
from bzrlib.trace import warning, mutter
@@ -74,21 +75,16 @@
" - $BZR_EDITOR\n - editor=/some/path in %s\n - $EDITOR" % \
config.config_filename())
-
-DEFAULT_IGNORE_LINE = "%(bar)s %(msg)s %(bar)s" % \
- { 'bar' : '-' * 14, 'msg' : 'This line and the following will be ignored' }
-
-
-def edit_commit_message(infotext, ignoreline=DEFAULT_IGNORE_LINE):
+_marker = object()
+
+def edit_commit_message(commit_template, ignoreline=_marker):
"""Let the user edit a commit message in a temp file.
This is run if they don't give a message or
message-containing file on the command line.
- infotext:
- Text to be displayed at bottom of message for
- the user's reference; currently similar to
- 'bzr status'.
+ commit_template:
+ A CommitTemplate object to include in the file.
"""
import tempfile
@@ -96,11 +92,24 @@
try:
tmp_fileno, msgfilename = tempfile.mkstemp(prefix='bzr_log.', dir=u'.')
msgfile = os.close(tmp_fileno)
- if infotext is not None and infotext != "":
+
+ if commit_template is not None:
hasinfo = True
msgfile = file(msgfilename, "w")
- msgfile.write("\n\n%s\n\n%s" % (ignoreline,
- infotext.encode(bzrlib.user_encoding, 'replace')))
+ if not isinstance(commit_template, c_t.CommitTemplate):
+ # assume previous API (string)
+ template = "\n"
+ comment = commit_template
+ if ignoreline == _marker:
+ ignoreline = c_t.DefaultCommitTemplate.ignoreline
+ else:
+ template = commit_template.template
+ comment = commit_template.comment
+ ignoreline = commit_template.ignoreline
+
+ parts = map(lambda s: s.encode(bzrlib.user_encoding, 'replace'),
+ [ template, ignoreline, comment ])
+ msgfile.write("%s\n%s\n%s\n" % tuple(parts))
msgfile.close()
else:
hasinfo = False
@@ -133,6 +142,9 @@
return ""
# delete empty lines at the end
del msg[lastline:]
+ # maybe there was a template left unmodified
+ if "".join(msg) == template:
+ return ""
# add a newline at the end, if needed
if not msg[-1].endswith("\n"):
return "%s%s" % ("".join(msg), "\n")
@@ -145,23 +157,3 @@
os.unlink(msgfilename)
except IOError, e:
warning("failed to unlink %s: %s; ignored", msgfilename, e)
-
-
-def make_commit_message_template(working_tree, specific_files):
- """Prepare a template file for a commit into a branch.
-
- Returns a unicode string containing the template.
- """
- # TODO: Should probably be given the WorkingTree not the branch
- #
- # TODO: make provision for this to be overridden or modified by a hook
- #
- # TODO: Rather than running the status command, should prepare a draft of
- # the revision to be committed, then pause and ask the user to
- # confirm/write a message.
- from StringIO import StringIO # must be unicode-safe
- from bzrlib.status import show_tree_status
- status_tmp = StringIO()
- show_tree_status(working_tree, specific_files=specific_files,
- to_file=status_tmp)
- return status_tmp.getvalue()
# revision id: dato at net.com.org.es-20060728010537-4cc4ebdfce9994c2
# sha1: 871d021569ac1ed67ce517b8a4c0bc4d6fc51957
# inventory sha1: 832a149e4d6694ab1b007b719b690aabd8f5acc4
# parent ids:
# pqm at pqm.ubuntu.com-20060727200511-3bfb6377b1695fad
# base id: pqm at pqm.ubuntu.com-20060727200511-3bfb6377b1695fad
# properties:
# branch-nick: commit_templates
More information about the bazaar
mailing list