/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
49 by Jelmer Vernooij
Merge in Dan Loda's gannotate plugin and put it in annotate/
1
# This program is free software; you can redistribute it and/or modify
2
# it under the terms of the GNU General Public License as published by
3
# the Free Software Foundation; either version 2 of the License, or
4
# (at your option) any later version.
5
6
# This program is distributed in the hope that it will be useful,
7
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9
# GNU General Public License for more details.
10
11
# You should have received a copy of the GNU General Public License
12
# along with this program; if not, write to the Free Software
13
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14
208.2.1 by Robert Collins
Better module docstring.
15
"""Graphical support for Bazaar using GTK.
16
17
This plugin includes:
18
commit-notify     Start the graphical notifier of commits.
19
gannotate         GTK+ annotate. 
20
gbranch           GTK+ branching. 
21
gcheckout         GTK+ checkout. 
323 by Jelmer Vernooij
Add gsend command.
22
gcommit           GTK+ commit dialog.
242.1.2 by Adeodato Simó
Fix gconflicts docstring.
23
gconflicts        GTK+ conflicts. 
208.2.1 by Robert Collins
Better module docstring.
24
gdiff             Show differences in working tree in a GTK+ Window. 
25
ginit             Initialise a new branch.
26
gmissing          GTK+ missing revisions dialog. 
27
gpreferences      GTK+ preferences dialog. 
323 by Jelmer Vernooij
Add gsend command.
28
gpush             GTK+ push.
29
gsend             GTK+ send merge directive.
30
gstatus           GTK+ status dialog.
208.2.1 by Robert Collins
Better module docstring.
31
gtags             Manage branch tags.
32
visualise         Graphically visualise this branch. 
33
"""
73 by Jelmer Vernooij
Release 0.9, list myself as maintainer.
34
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
35
import sys
36
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
37
import bzrlib
38
487 by Jelmer Vernooij
Start working on 0.95.0.
39
version_info = (0, 95, 0, 'dev', 1)
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
40
287 by Jelmer Vernooij
Use standard version tuple.
41
if version_info[3] == 'final':
42
    version_string = '%d.%d.%d' % version_info[:3]
43
else:
44
    version_string = '%d.%d.%d%s%d' % version_info
45
__version__ = version_string
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
46
451.1.1 by Daniel Schierbeck
Bumped required version of bzrlib to 1.3.
47
required_bzrlib = (1, 3)
423.1.1 by Jelmer Vernooij
Allow bzr-gtk and Bazaar versions to be out of sync. No longer warn about
48
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
49
def check_bzrlib_version(desired):
50
    """Check that bzrlib is compatible.
51
52
    If version is < bzr-gtk version, assume incompatible.
53
    """
54
    bzrlib_version = bzrlib.version_info[:2]
55
    try:
56
        from bzrlib.trace import warning
57
    except ImportError:
58
        # get the message out any way we can
59
        from warnings import warn as warning
60
    if bzrlib_version < desired:
207 by Aaron Bentley
Import BzrError before using it
61
        from bzrlib.errors import BzrError
271 by Jelmer Vernooij
Add common widget for selecting branches.
62
        warning('Installed Bazaar version %s is too old to be used with bzr-gtk'
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
63
                ' %s.' % (bzrlib.__version__, __version__))
287 by Jelmer Vernooij
Use standard version tuple.
64
        raise BzrError('Version mismatch: %r, %r' % (version_info, bzrlib.version_info) )
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
65
66
287 by Jelmer Vernooij
Use standard version tuple.
67
if version_info[2] == "final":
423.1.1 by Jelmer Vernooij
Allow bzr-gtk and Bazaar versions to be out of sync. No longer warn about
68
    check_bzrlib_version(required_bzrlib)
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
69
146 by Jelmer Vernooij
Move more code to top-level directory.
70
from bzrlib.trace import warning
71
if __name__ != 'bzrlib.plugins.gtk':
72
    warning("Not running as bzrlib.plugins.gtk, things may break.")
73
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
74
from bzrlib.lazy_import import lazy_import
75
lazy_import(globals(), """
76
from bzrlib import (
77
    branch,
249 by Aaron Bentley
Add gselftest command
78
    builtins,
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
79
    errors,
426 by Aaron Bentley
Start support for Merge Directives
80
    merge_directive,
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
81
    workingtree,
82
    )
83
""")
84
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
85
from bzrlib.commands import Command, register_command, display_command
59.2.4 by Aaron Bentley
Teach gdiff to accept a single file argument
86
from bzrlib.errors import NotVersionedError, BzrCommandError, NoSuchFile
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
87
from bzrlib.option import Option
88
126.1.5 by Szilveszter Farkas (Phanatic)
bzr gbranch should work now (Fixed: #77751)
89
import os.path
90
66.2.20 by Aaron Bentley
Nicer error when PyGTK not installed
91
def import_pygtk():
92
    try:
93
        import pygtk
94
    except ImportError:
95
        raise errors.BzrCommandError("PyGTK not installed.")
96
    pygtk.require('2.0')
97
    return pygtk
98
99
133 by Jelmer Vernooij
Actually use the ui factory.
100
def set_ui_factory():
177 by Jelmer Vernooij
Register commands all at once.
101
    import_pygtk()
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
102
    from ui import GtkUIFactory
133 by Jelmer Vernooij
Actually use the ui factory.
103
    import bzrlib.ui
104
    bzrlib.ui.ui_factory = GtkUIFactory()
105
106
247 by Jelmer Vernooij
Use application path to find icons.
107
def data_path():
108
    return os.path.dirname(__file__)
109
110
399.1.19 by Jelmer Vernooij
Add utility function for finding icon paths.
111
def icon_path(*args):
112
    basedirs = [os.path.join(data_path()),
113
             "/usr/share/bzr-gtk", 
114
             "/usr/local/share/bzr-gtk"]
115
    for basedir in basedirs:
116
        path = os.path.join(basedir, 'icons', *args)
117
        if os.path.exists(path):
118
            return path
119
    return None
120
121
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
122
def open_display():
123
    pygtk = import_pygtk()
124
    try:
125
        import gtk
126
    except RuntimeError, e:
127
        if str(e) == "could not open display":
128
            raise NoDisplayError
129
    set_ui_factory()
130
    return gtk
131
 
132
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
133
class GTKCommand(Command):
134
    """Abstract class providing GTK specific run commands."""
135
136
    def run(self):
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
137
        open_display()
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
138
        dialog = self.get_gtk_dialog(os.path.abspath('.'))
139
        dialog.run()
140
141
142
class cmd_gbranch(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
143
    """GTK+ branching.
144
    
145
    """
146
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
147
    def get_gtk_dialog(self, path):
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
148
        from bzrlib.plugins.gtk.branch import BranchDialog
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
149
        return BranchDialog(path)
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
150
151
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
152
class cmd_gcheckout(GTKCommand):
126.1.18 by Szilveszter Farkas (Phanatic)
Improved Branch dialog. Refactored Checkout dialog.
153
    """ GTK+ checkout.
154
    
155
    """
156
    
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
157
    def get_gtk_dialog(self, path):
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
158
        from bzrlib.plugins.gtk.checkout import CheckoutDialog
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
159
        return CheckoutDialog(path)
126.1.18 by Szilveszter Farkas (Phanatic)
Improved Branch dialog. Refactored Checkout dialog.
160
161
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
162
163
class cmd_gpush(GTKCommand):
126.1.19 by Szilveszter Farkas (Phanatic)
Refactored the Push dialog. Add 'gpush' command.
164
    """ GTK+ push.
165
    
166
    """
167
    takes_args = [ "location?" ]
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
168
126.1.19 by Szilveszter Farkas (Phanatic)
Refactored the Push dialog. Add 'gpush' command.
169
    def run(self, location="."):
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
170
        (br, path) = branch.Branch.open_containing(location)
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
171
        open_display()
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
172
        from push import PushDialog
233 by Jelmer Vernooij
Get rid of test button in push.
173
        dialog = PushDialog(br.repository, br.last_revision(), br)
126.1.19 by Szilveszter Farkas (Phanatic)
Refactored the Push dialog. Add 'gpush' command.
174
        dialog.run()
175
176
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
177
178
class cmd_gdiff(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
179
    """Show differences in working tree in a GTK+ Window.
180
    
181
    Otherwise, all changes for the tree are listed.
182
    """
59.2.4 by Aaron Bentley
Teach gdiff to accept a single file argument
183
    takes_args = ['filename?']
58.1.1 by Aaron Bentley
gdiff takes -r arguments
184
    takes_options = ['revision']
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
185
186
    @display_command
59.2.4 by Aaron Bentley
Teach gdiff to accept a single file argument
187
    def run(self, revision=None, filename=None):
133 by Jelmer Vernooij
Actually use the ui factory.
188
        set_ui_factory()
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
189
        wt = workingtree.WorkingTree.open_containing(".")[0]
161 by Aaron Bentley
Fix gannotate interaction with dirstate
190
        wt.lock_read()
191
        try:
192
            branch = wt.branch
193
            if revision is not None:
194
                if len(revision) == 1:
195
                    tree1 = wt
493 by Aaron Bentley
Convert remaining uses of RevisionSpec.in_history to as_revision_id
196
                    revision_id = revision[0].as_revision_id(tree1.branch)
161 by Aaron Bentley
Fix gannotate interaction with dirstate
197
                    tree2 = branch.repository.revision_tree(revision_id)
198
                elif len(revision) == 2:
493 by Aaron Bentley
Convert remaining uses of RevisionSpec.in_history to as_revision_id
199
                    revision_id_0 = revision[0].as_revision_id(branch)
161 by Aaron Bentley
Fix gannotate interaction with dirstate
200
                    tree2 = branch.repository.revision_tree(revision_id_0)
493 by Aaron Bentley
Convert remaining uses of RevisionSpec.in_history to as_revision_id
201
                    revision_id_1 = revision[1].as_revision_id(branch)
161 by Aaron Bentley
Fix gannotate interaction with dirstate
202
                    tree1 = branch.repository.revision_tree(revision_id_1)
203
            else:
58.1.1 by Aaron Bentley
gdiff takes -r arguments
204
                tree1 = wt
161 by Aaron Bentley
Fix gannotate interaction with dirstate
205
                tree2 = tree1.basis_tree()
206
207
            from diff import DiffWindow
208
            import gtk
209
            window = DiffWindow()
210
            window.connect("destroy", gtk.main_quit)
211
            window.set_diff("Working Tree", tree1, tree2)
212
            if filename is not None:
213
                tree_filename = wt.relpath(filename)
214
                try:
215
                    window.set_file(tree_filename)
216
                except NoSuchFile:
188.3.1 by John Arbash Meinel
Use tree.path2id to avoid getting 'Object Not Locked' errors.
217
                    if (tree1.path2id(tree_filename) is None and 
218
                        tree2.path2id(tree_filename) is None):
161 by Aaron Bentley
Fix gannotate interaction with dirstate
219
                        raise NotVersionedError(filename)
220
                    raise BzrCommandError('No changes found for file "%s"' % 
221
                                          filename)
222
            window.show()
223
224
            gtk.main()
225
        finally:
226
            wt.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
227
228
452.4.1 by Jelmer Vernooij
Support displaying multiple tips in viz.
229
def start_viz_window(branch, revisions, limit=None):
208.2.2 by Robert Collins
Add inspect window to bzr commity-notify.
230
    """Start viz on branch with revision revision.
231
    
232
    :return: The viz window object.
233
    """
423.2.2 by Daniel Schierbeck
Moved the branch window class to the viz package.
234
    from viz import BranchWindow
452.4.1 by Jelmer Vernooij
Support displaying multiple tips in viz.
235
    return BranchWindow(branch, revisions, limit)
208.2.2 by Robert Collins
Add inspect window to bzr commity-notify.
236
237
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
238
class cmd_visualise(Command):
239
    """Graphically visualise this branch.
240
241
    Opens a graphical window to allow you to see the history of the branch
242
    and relationships between revisions in a visual manner,
243
244
    The default starting point is latest revision on the branch, you can
245
    specify a starting point with -r revision.
246
    """
247
    takes_options = [
248
        "revision",
208.2.7 by Vincent Ladeuil
Fix option help strings to comply with the style guide.
249
        Option('limit', "Maximum number of revisions to display.",
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
250
               int, 'count')]
452.4.1 by Jelmer Vernooij
Support displaying multiple tips in viz.
251
    takes_args = [ "locations*" ]
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
252
    aliases = [ "visualize", "vis", "viz" ]
253
452.4.1 by Jelmer Vernooij
Support displaying multiple tips in viz.
254
    def run(self, locations_list, revision=None, limit=None):
133 by Jelmer Vernooij
Actually use the ui factory.
255
        set_ui_factory()
452.4.1 by Jelmer Vernooij
Support displaying multiple tips in viz.
256
        if locations_list is None:
257
            locations_list = ["."]
258
        revids = []
259
        for location in locations_list:
260
            (br, path) = branch.Branch.open_containing(location)
261
            if revision is None:
262
                revids.append(br.last_revision())
263
            else:
493 by Aaron Bentley
Convert remaining uses of RevisionSpec.in_history to as_revision_id
264
                revids.append(revision[0].as_revision_id(br))
365 by Daniel Schierbeck
Fixed locks and made tagging work.
265
        import gtk
452.4.1 by Jelmer Vernooij
Support displaying multiple tips in viz.
266
        pp = start_viz_window(br, revids, limit)
365 by Daniel Schierbeck
Fixed locks and made tagging work.
267
        pp.connect("destroy", lambda w: gtk.main_quit())
268
        pp.show()
269
        gtk.main()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
270
271
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
272
class cmd_gannotate(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
273
    """GTK+ annotate.
274
    
275
    Browse changes to FILENAME line by line in a GTK+ window.
276
    """
277
59.2.1 by Aaron Bentley
Gannotate takes a line number
278
    takes_args = ["filename", "line?"]
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
279
    takes_options = [
208.2.7 by Vincent Ladeuil
Fix option help strings to comply with the style guide.
280
        Option("all", help="Show annotations on all lines."),
281
        Option("plain", help="Don't highlight annotation lines."),
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
282
        Option("line", type=int, argname="lineno",
208.2.7 by Vincent Ladeuil
Fix option help strings to comply with the style guide.
283
               help="Jump to specified line number."),
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
284
        "revision",
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
285
    ]
286
    aliases = ["gblame", "gpraise"]
287
    
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
288
    def run(self, filename, all=False, plain=False, line='1', revision=None):
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
289
        gtk = open_display()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
290
59.2.1 by Aaron Bentley
Gannotate takes a line number
291
        try:
292
            line = int(line)
293
        except ValueError:
294
            raise BzrCommandError('Line argument ("%s") is not a number.' % 
295
                                  line)
296
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
297
        from annotate.gannotate import GAnnotateWindow
298
        from annotate.config import GAnnotateConfig
177 by Jelmer Vernooij
Register commands all at once.
299
        from bzrlib.bzrdir import BzrDir
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
300
161 by Aaron Bentley
Fix gannotate interaction with dirstate
301
        wt, br, path = BzrDir.open_containing_tree_or_branch(filename)
302
        if wt is not None:
303
            tree = wt
304
        else:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
305
            tree = br.basis_tree()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
306
66.2.18 by Aaron Bentley
Gannotate works with branches, not just trees
307
        file_id = tree.path2id(path)
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
308
309
        if file_id is None:
310
            raise NotVersionedError(filename)
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
311
        if revision is not None:
312
            if len(revision) != 1:
313
                raise BzrCommandError("Only 1 revion may be specified.")
493 by Aaron Bentley
Convert remaining uses of RevisionSpec.in_history to as_revision_id
314
            revision_id = revision[0].as_revision_id(br)
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
315
            tree = br.repository.revision_tree(revision_id)
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
316
        else:
66.2.18 by Aaron Bentley
Gannotate works with branches, not just trees
317
            revision_id = getattr(tree, 'get_revision_id', lambda: None)()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
318
473.1.1 by Andrew Bennetts
Simple hack to fix gannotate.
319
        window = GAnnotateWindow(all, plain, branch=br)
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
320
        window.connect("destroy", lambda w: gtk.main_quit())
321
        config = GAnnotateConfig(window)
322
        window.show()
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
323
        br.lock_read()
161 by Aaron Bentley
Fix gannotate interaction with dirstate
324
        if wt is not None:
325
            wt.lock_read()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
326
        try:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
327
            window.annotate(tree, br, file_id)
161 by Aaron Bentley
Fix gannotate interaction with dirstate
328
            window.jump_to_line(line)
329
            gtk.main()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
330
        finally:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
331
            br.unlock()
161 by Aaron Bentley
Fix gannotate interaction with dirstate
332
            if wt is not None:
333
                wt.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
334
335
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
336
337
class cmd_gcommit(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
338
    """GTK+ commit dialog
339
340
    Graphical user interface for committing revisions"""
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
341
145 by Jelmer Vernooij
Fix some strings, import.
342
    aliases = [ "gci" ]
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
343
    takes_args = []
344
    takes_options = []
345
346
    def run(self, filename=None):
93.1.17 by Alexander Belchenko
gcommit reworked again.
347
        import os
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
348
        open_display()
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
349
        from commit import CommitDialog
93.1.17 by Alexander Belchenko
gcommit reworked again.
350
        from bzrlib.errors import (BzrCommandError,
351
                                   NotBranchError,
178 by Jelmer Vernooij
Remove unneeded imports.
352
                                   NoWorkingTree)
93.1.17 by Alexander Belchenko
gcommit reworked again.
353
354
        wt = None
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
355
        br = None
93.1.17 by Alexander Belchenko
gcommit reworked again.
356
        try:
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
357
            (wt, path) = workingtree.WorkingTree.open_containing(filename)
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
358
            br = wt.branch
93.1.17 by Alexander Belchenko
gcommit reworked again.
359
        except NoWorkingTree, e:
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
360
            from dialog import error_dialog
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
361
            error_dialog(_i18n('Directory does not have a working tree'),
362
                         _i18n('Operation aborted.'))
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
363
            return 1 # should this be retval=3?
364
365
        # It is a good habit to keep things locked for the duration, but it
366
        # could cause difficulties if someone wants to do things in another
367
        # window... We could lock_read() until we actually go to commit
368
        # changes... Just a thought.
369
        wt.lock_write()
370
        try:
371
            dlg = CommitDialog(wt)
372
            return dlg.run()
373
        finally:
374
            wt.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
375
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
376
250 by Aaron Bentley
oops- revert status change
377
class cmd_gstatus(GTKCommand):
157 by Jelmer Vernooij
Add gstatus command.
378
    """GTK+ status dialog
379
380
    Graphical user interface for showing status 
381
    information."""
382
    
383
    aliases = [ "gst" ]
384
    takes_args = ['PATH?']
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
385
    takes_options = ['revision']
157 by Jelmer Vernooij
Add gstatus command.
386
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
387
    def run(self, path='.', revision=None):
157 by Jelmer Vernooij
Add gstatus command.
388
        import os
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
389
        gtk = open_display()
157 by Jelmer Vernooij
Add gstatus command.
390
        from status import StatusDialog
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
391
        (wt, wt_path) = workingtree.WorkingTree.open_containing(path)
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
392
        
393
        if revision is not None:
463.1.2 by Javier Derderian
Added 'Revision # doesn't exist' message
394
            try:
493 by Aaron Bentley
Convert remaining uses of RevisionSpec.in_history to as_revision_id
395
                revision_id = revision[0].as_revision_id(wt.branch)
463.1.2 by Javier Derderian
Added 'Revision # doesn't exist' message
396
            except:
397
                from bzrlib.errors import BzrError
398
                raise BzrError('Revision %r doesn\'t exist' % revision[0].user_spec )
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
399
        else:
400
            revision_id = None
401
402
        status = StatusDialog(wt, wt_path, revision_id)
157 by Jelmer Vernooij
Add gstatus command.
403
        status.connect("destroy", gtk.main_quit)
404
        status.run()
405
406
323 by Jelmer Vernooij
Add gsend command.
407
class cmd_gsend(GTKCommand):
408
    """GTK+ send merge directive.
409
410
    """
411
    def run(self):
412
        (br, path) = branch.Branch.open_containing(".")
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
413
        gtk = open_display()
323 by Jelmer Vernooij
Add gsend command.
414
        from bzrlib.plugins.gtk.mergedirective import SendMergeDirectiveDialog
324 by Jelmer Vernooij
Add very simple "Send Merge Directive" window.
415
        from StringIO import StringIO
323 by Jelmer Vernooij
Add gsend command.
416
        dialog = SendMergeDirectiveDialog(br)
324 by Jelmer Vernooij
Add very simple "Send Merge Directive" window.
417
        if dialog.run() == gtk.RESPONSE_OK:
418
            outf = StringIO()
419
            outf.writelines(dialog.get_merge_directive().to_lines())
420
            mail_client = br.get_config().get_mail_client()
421
            mail_client.compose_merge_request(dialog.get_mail_to(), "[MERGE]", 
422
                outf.getvalue())
423
424
            
323 by Jelmer Vernooij
Add gsend command.
425
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
426
427
class cmd_gconflicts(GTKCommand):
323 by Jelmer Vernooij
Add gsend command.
428
    """GTK+ conflicts.
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
429
    
242.1.2 by Adeodato Simó
Fix gconflicts docstring.
430
    Select files from the list of conflicts and run an external utility to
431
    resolve them.
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
432
    """
433
    def run(self):
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
434
        (wt, path) = workingtree.WorkingTree.open_containing('.')
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
435
        open_display()
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
436
        from bzrlib.plugins.gtk.conflicts import ConflictsDialog
437
        dialog = ConflictsDialog(wt)
438
        dialog.run()
439
157 by Jelmer Vernooij
Add gstatus command.
440
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
441
class cmd_gpreferences(GTKCommand):
171 by Jelmer Vernooij
Initial work on a preferences dialog in GTK+, including a list of plugins with metadata browser.
442
    """ GTK+ preferences dialog.
443
444
    """
445
    def run(self):
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
446
        open_display()
171 by Jelmer Vernooij
Initial work on a preferences dialog in GTK+, including a list of plugins with metadata browser.
447
        from bzrlib.plugins.gtk.preferences import PreferencesWindow
448
        dialog = PreferencesWindow()
449
        dialog.run()
450
451
175 by Jelmer Vernooij
Add very simple gmissing command.
452
class cmd_gmissing(Command):
453
    """ GTK+ missing revisions dialog.
454
455
    """
456
    takes_args = ["other_branch?"]
457
    def run(self, other_branch=None):
458
        pygtk = import_pygtk()
459
        try:
460
            import gtk
461
        except RuntimeError, e:
462
            if str(e) == "could not open display":
463
                raise NoDisplayError
464
465
        from bzrlib.plugins.gtk.missing import MissingWindow
466
        from bzrlib.branch import Branch
467
468
        local_branch = Branch.open_containing(".")[0]
469
        if other_branch is None:
470
            other_branch = local_branch.get_parent()
471
            
472
            if other_branch is None:
473
                raise errors.BzrCommandError("No peer location known or specified.")
474
        remote_branch = Branch.open_containing(other_branch)[0]
475
        set_ui_factory()
476
        local_branch.lock_read()
477
        try:
478
            remote_branch.lock_read()
479
            try:
480
                dialog = MissingWindow(local_branch, remote_branch)
481
                dialog.run()
482
            finally:
483
                remote_branch.unlock()
484
        finally:
485
            local_branch.unlock()
486
177 by Jelmer Vernooij
Register commands all at once.
487
188.1.1 by Szilveszter Farkas (Phanatic)
Inital implementation of the Initialize dialog. Not fully functional yet.
488
class cmd_ginit(GTKCommand):
489
    def run(self):
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
490
        open_display()
188.1.1 by Szilveszter Farkas (Phanatic)
Inital implementation of the Initialize dialog. Not fully functional yet.
491
        from initialize import InitDialog
492
        dialog = InitDialog(os.path.abspath(os.path.curdir))
493
        dialog.run()
494
495
190.1.1 by Szilveszter Farkas (Phanatic)
Added 'gtags' command and basic Tags window (just a skeleton).
496
class cmd_gtags(GTKCommand):
497
    def run(self):
498
        br = branch.Branch.open_containing('.')[0]
499
        
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
500
        gtk = open_display()
190.1.1 by Szilveszter Farkas (Phanatic)
Added 'gtags' command and basic Tags window (just a skeleton).
501
        from tags import TagsWindow
502
        window = TagsWindow(br)
503
        window.show()
504
        gtk.main()
505
506
177 by Jelmer Vernooij
Register commands all at once.
507
commands = [
323 by Jelmer Vernooij
Add gsend command.
508
    cmd_gannotate, 
509
    cmd_gbranch,
510
    cmd_gcheckout, 
511
    cmd_gcommit, 
512
    cmd_gconflicts, 
513
    cmd_gdiff,
514
    cmd_ginit,
177 by Jelmer Vernooij
Register commands all at once.
515
    cmd_gmissing, 
516
    cmd_gpreferences, 
323 by Jelmer Vernooij
Add gsend command.
517
    cmd_gpush, 
518
    cmd_gsend,
177 by Jelmer Vernooij
Register commands all at once.
519
    cmd_gstatus,
323 by Jelmer Vernooij
Add gsend command.
520
    cmd_gtags,
521
    cmd_visualise
177 by Jelmer Vernooij
Register commands all at once.
522
    ]
523
524
for cmd in commands:
525
    register_command(cmd)
175 by Jelmer Vernooij
Add very simple gmissing command.
526
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
527
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
528
class cmd_commit_notify(GTKCommand):
529
    """Run the bzr commit notifier.
530
531
    This is a background program which will pop up a notification on the users
532
    screen when a commit occurs.
533
    """
534
535
    def run(self):
211 by Jelmer Vernooij
Move notification area code into separate file.
536
        from notify import NotifyPopupMenu
505.1.1 by Jelmer Vernooij
Make handle-patch not dependend on the users name being abentley and install it.
537
        gtk = open_display()
211 by Jelmer Vernooij
Move notification area code into separate file.
538
        menu = NotifyPopupMenu()
399.1.19 by Jelmer Vernooij
Add utility function for finding icon paths.
539
        icon = gtk.status_icon_new_from_file(icon_path("bzr-icon-64.png"))
211 by Jelmer Vernooij
Move notification area code into separate file.
540
        icon.connect('popup-menu', menu.display)
210 by Jelmer Vernooij
Add notification area icon for commit-notify.
541
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
542
        import cgi
543
        import dbus
544
        import dbus.service
545
        import pynotify
546
        from bzrlib.bzrdir import BzrDir
547
        from bzrlib import errors
548
        from bzrlib.osutils import format_date
549
        from bzrlib.transport import get_transport
550
        if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
551
            import dbus.glib
450.2.1 by James Henstridge
Make commit-notify listen for Revision signals from any source rather
552
        BROADCAST_INTERFACE = "org.bazaarvcs.plugins.dbus.Broadcast"
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
553
        bus = dbus.SessionBus()
211 by Jelmer Vernooij
Move notification area code into separate file.
554
182.1.1 by Robert Collins
Update commit-notify to use new dbus api, and show remote URL's.
555
        def catch_branch(revision_id, urls):
556
            # TODO: show all the urls, or perhaps choose the 'best'.
557
            url = urls[0]
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
558
            try:
559
                if isinstance(revision_id, unicode):
560
                    revision_id = revision_id.encode('utf8')
561
                transport = get_transport(url)
562
                a_dir = BzrDir.open_from_transport(transport)
563
                branch = a_dir.open_branch()
564
                revno = branch.revision_id_to_revno(revision_id)
565
                revision = branch.repository.get_revision(revision_id)
566
                summary = 'New revision %d in %s' % (revno, url)
567
                body  = 'Committer: %s\n' % revision.committer
568
                body += 'Date: %s\n' % format_date(revision.timestamp,
569
                    revision.timezone)
570
                body += '\n'
571
                body += revision.message
572
                body = cgi.escape(body)
573
                nw = pynotify.Notification(summary, body)
208.2.2 by Robert Collins
Add inspect window to bzr commity-notify.
574
                def start_viz(notification=None, action=None, data=None):
575
                    """Start the viz program."""
576
                    pp = start_viz_window(branch, revision_id)
577
                    pp.show()
208.2.3 by Robert Collins
Add a Branch button to commit-notify.
578
                def start_branch(notification=None, action=None, data=None):
579
                    """Start a Branch dialog"""
580
                    from bzrlib.plugins.gtk.branch import BranchDialog
581
                    bd = BranchDialog(remote_path=url)
582
                    bd.run()
208.2.4 by Robert Collins
Unbreak inspect of commits due to misunderstanding of pynotify api.
583
                nw.add_action("inspect", "Inspect", start_viz, None)
584
                nw.add_action("branch", "Branch", start_branch, None)
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
585
                nw.set_timeout(5000)
586
                nw.show()
587
            except Exception, e:
588
                print e
589
                raise
450.2.1 by James Henstridge
Make commit-notify listen for Revision signals from any source rather
590
        bus.add_signal_receiver(catch_branch,
591
                                dbus_interface=BROADCAST_INTERFACE,
592
                                signal_name="Revision")
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
593
        pynotify.init("bzr commit-notify")
594
        gtk.main()
595
596
register_command(cmd_commit_notify)
597
598
249 by Aaron Bentley
Add gselftest command
599
class cmd_gselftest(GTKCommand):
600
    """Version of selftest that displays a notification at the end"""
601
602
    takes_args = builtins.cmd_selftest.takes_args
603
    takes_options = builtins.cmd_selftest.takes_options
604
    _see_also = ['selftest']
605
606
    def run(self, *args, **kwargs):
607
        import cgi
253 by Aaron Bentley
Avoid encoding problems from pygtk
608
        import sys
609
        default_encoding = sys.getdefaultencoding()
249 by Aaron Bentley
Add gselftest command
610
        # prevent gtk from blowing up later
611
        gtk = import_pygtk()
253 by Aaron Bentley
Avoid encoding problems from pygtk
612
        # prevent gtk from messing with default encoding
249 by Aaron Bentley
Add gselftest command
613
        import pynotify
253 by Aaron Bentley
Avoid encoding problems from pygtk
614
        if sys.getdefaultencoding() != default_encoding:
615
            reload(sys)
616
            sys.setdefaultencoding(default_encoding)
249 by Aaron Bentley
Add gselftest command
617
        result = builtins.cmd_selftest().run(*args, **kwargs)
618
        if result == 0:
619
            summary = 'Success'
620
            body = 'Selftest succeeded in "%s"' % os.getcwd()
621
        if result == 1:
622
            summary = 'Failure'
623
            body = 'Selftest failed in "%s"' % os.getcwd()
624
        pynotify.init("bzr gselftest")
625
        note = pynotify.Notification(cgi.escape(summary), cgi.escape(body))
626
        note.set_timeout(pynotify.EXPIRES_NEVER)
627
        note.show()
628
629
630
register_command(cmd_gselftest)
631
632
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
633
class cmd_test_gtk(GTKCommand):
634
    """Version of selftest that just runs the gtk test suite."""
635
636
    takes_options = ['verbose',
637
                     Option('one', short_name='1',
330.6.2 by Aaron Bentley
Fix option grammar
638
                            help='Stop when one test fails.'),
639
                     Option('benchmark', help='Run the benchmarks.'),
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
640
                     Option('lsprof-timed',
330.6.2 by Aaron Bentley
Fix option grammar
641
                     help='Generate lsprof output for benchmarked'
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
642
                          ' sections of code.'),
643
                     Option('list-only',
330.6.2 by Aaron Bentley
Fix option grammar
644
                     help='List the tests instead of running them.'),
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
645
                     Option('randomize', type=str, argname="SEED",
330.6.2 by Aaron Bentley
Fix option grammar
646
                     help='Randomize the order of tests using the given'
647
                          ' seed or "now" for the current time.'),
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
648
                    ]
649
    takes_args = ['testspecs*']
650
651
    def run(self, verbose=None, one=False, benchmark=None,
652
            lsprof_timed=None, list_only=False, randomize=None,
653
            testspecs_list=None):
654
        from bzrlib import __path__ as bzrlib_path
655
        from bzrlib.tests import selftest
656
657
        print '%10s: %s' % ('bzrlib', bzrlib_path[0])
658
        if benchmark:
659
            print 'No benchmarks yet'
660
            return 3
661
662
            test_suite_factory = bench_suite
663
            if verbose is None:
664
                verbose = True
665
            # TODO: should possibly lock the history file...
666
            benchfile = open(".perf_history", "at", buffering=1)
667
        else:
668
            test_suite_factory = test_suite
669
            if verbose is None:
670
                verbose = False
671
            benchfile = None
672
673
        if testspecs_list is not None:
674
            pattern = '|'.join(testspecs_list)
675
        else:
676
            pattern = ".*"
677
678
        try:
679
            result = selftest(verbose=verbose,
680
                              pattern=pattern,
681
                              stop_on_failure=one,
682
                              test_suite_factory=test_suite_factory,
683
                              lsprof_timed=lsprof_timed,
684
                              bench_history=benchfile,
685
                              list_only=list_only,
686
                              random_seed=randomize,
687
                             )
688
        finally:
689
            if benchfile is not None:
690
                benchfile.close()
691
692
register_command(cmd_test_gtk)
693
694
424 by Aaron Bentley
Add ghandle-patch
695
152 by Jelmer Vernooij
Cleanup some more code.
696
import gettext
697
gettext.install('olive-gtk')
698
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
699
# Let's create a specialized alias to protect '_' from being erased by other
700
# uses of '_' as an anonymous variable (think pdb for one).
701
_i18n = gettext.gettext
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
702
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
703
class NoDisplayError(BzrCommandError):
704
    """gtk could not find a proper display"""
705
706
    def __str__(self):
133 by Jelmer Vernooij
Actually use the ui factory.
707
        return "No DISPLAY. Unable to run GTK+ application."
708
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
709
140 by Jelmer Vernooij
add framework for tests.
710
def test_suite():
711
    from unittest import TestSuite
712
    import tests
163 by Aaron Bentley
Prevent test suite from causing default-encoding changes
713
    import sys
714
    default_encoding = sys.getdefaultencoding()
715
    try:
716
        result = TestSuite()
330.6.4 by Aaron Bentley
Allow test suite to run without pygtk
717
        try:
718
            import_pygtk()
719
        except errors.BzrCommandError:
720
            return result
163 by Aaron Bentley
Prevent test suite from causing default-encoding changes
721
        result.addTest(tests.test_suite())
722
    finally:
170.1.2 by Aaron Bentley
Test suite only fixes encoding if it's changed. Fixes test_selftest bug.
723
        if sys.getdefaultencoding() != default_encoding:
724
            reload(sys)
725
            sys.setdefaultencoding(default_encoding)
140 by Jelmer Vernooij
add framework for tests.
726
    return result