~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/msgeditor.py

merge permissions branch, also fixup tests so they are lined up with bzr.dev to help prevent conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Bazaar-NG -- distributed version control
 
2
 
 
3
# Copyright (C) 2005 by Canonical Ltd
 
4
 
 
5
# This program is free software; you can redistribute it and/or modify
 
6
# it under the terms of the GNU General Public License as published by
 
7
# the Free Software Foundation; either version 2 of the License, or
 
8
# (at your option) any later version.
 
9
 
 
10
# This program is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
# GNU General Public License for more details.
 
14
 
 
15
# You should have received a copy of the GNU General Public License
 
16
# along with this program; if not, write to the Free Software
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 
 
19
 
 
20
"""Commit message editor support."""
 
21
 
 
22
import os
 
23
from subprocess import call
 
24
 
 
25
import bzrlib.config as config
 
26
from bzrlib.errors import BzrError
 
27
 
 
28
def _get_editor():
 
29
    """Return a sequence of possible editor binaries for the current platform"""
 
30
    try:
 
31
        yield os.environ["BZR_EDITOR"]
 
32
    except KeyError:
 
33
        pass
 
34
 
 
35
    e = config.GlobalConfig().get_editor()
 
36
    if e is not None:
 
37
        yield e
 
38
        
 
39
    try:
 
40
        yield os.environ["EDITOR"]
 
41
    except KeyError:
 
42
        pass
 
43
 
 
44
    if os.name == "nt":
 
45
        yield "notepad.exe"
 
46
    elif os.name == "posix":
 
47
        yield "/usr/bin/vi"
 
48
 
 
49
 
 
50
def _run_editor(filename):
 
51
    """Try to execute an editor to edit the commit message."""
 
52
    for e in _get_editor():
 
53
        edargs = e.split(' ')
 
54
        x = call(edargs + [filename])
 
55
        if x == 0:
 
56
            return True
 
57
        elif x == 127:
 
58
            continue
 
59
        else:
 
60
            break
 
61
    raise BzrError("Could not start any editor. "
 
62
                   "Please specify $EDITOR or use ~/.bzr.conf/editor")
 
63
                          
 
64
 
 
65
def edit_commit_message(infotext, ignoreline=None):
 
66
    """Let the user edit a commit message in a temp file.
 
67
 
 
68
    This is run if they don't give a message or
 
69
    message-containing file on the command line.
 
70
 
 
71
    infotext:
 
72
        Text to be displayed at bottom of message for
 
73
        the user's reference; currently similar to
 
74
        'bzr status'.
 
75
    """
 
76
    import tempfile
 
77
    
 
78
    if ignoreline is None:
 
79
        ignoreline = "-- This line and the following will be ignored --"
 
80
        
 
81
    try:
 
82
        tmp_fileno, msgfilename = tempfile.mkstemp(prefix='bzr_log.', dir=u'.')
 
83
        msgfile = os.close(tmp_fileno)
 
84
        if infotext is not None and infotext != "":
 
85
            hasinfo = True
 
86
            msgfile = file(msgfilename, "w")
 
87
            msgfile.write("\n\n%s\n\n%s" % (ignoreline, infotext))
 
88
            msgfile.close()
 
89
        else:
 
90
            hasinfo = False
 
91
 
 
92
        if not _run_editor(msgfilename):
 
93
            return None
 
94
        
 
95
        started = False
 
96
        msg = []
 
97
        lastline, nlines = 0, 0
 
98
        for line in file(msgfilename, "r"):
 
99
            stripped_line = line.strip()
 
100
            # strip empty line before the log message starts
 
101
            if not started:
 
102
                if stripped_line != "":
 
103
                    started = True
 
104
                else:
 
105
                    continue
 
106
            # check for the ignore line only if there
 
107
            # is additional information at the end
 
108
            if hasinfo and stripped_line == ignoreline:
 
109
                break
 
110
            nlines += 1
 
111
            # keep track of the last line that had some content
 
112
            if stripped_line != "":
 
113
                lastline = nlines
 
114
            msg.append(line)
 
115
            
 
116
        if len(msg) == 0:
 
117
            return ""
 
118
        # delete empty lines at the end
 
119
        del msg[lastline:]
 
120
        # add a newline at the end, if needed
 
121
        if not msg[-1].endswith("\n"):
 
122
            return "%s%s" % ("".join(msg), "\n")
 
123
        else:
 
124
            return "".join(msg)
 
125
    finally:
 
126
        # delete the msg file in any case
 
127
        try: os.unlink(msgfilename)
 
128
        except IOError: pass
 
129
 
 
130
 
 
131
def make_commit_message_template(working_tree, specific_files):
 
132
    """Prepare a template file for a commit into a branch.
 
133
 
 
134
    Returns a unicode string containing the template.
 
135
    """
 
136
    # TODO: Should probably be given the WorkingTree not the branch
 
137
    #
 
138
    # TODO: make provision for this to be overridden or modified by a hook
 
139
    #
 
140
    # TODO: Rather than running the status command, should prepare a draft of
 
141
    # the revision to be committed, then pause and ask the user to
 
142
    # confirm/write a message.
 
143
    from StringIO import StringIO       # must be unicode-safe
 
144
    from bzrlib.status import show_status
 
145
    status_tmp = StringIO()
 
146
    show_status(working_tree.branch, specific_files=specific_files, to_file=status_tmp)
 
147
    return status_tmp.getvalue()