/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. 
432 by Aaron Bentley
Misc updates
25
ghandle-patch     Display and optionally merge a merge directive or patch.
208.2.1 by Robert Collins
Better module docstring.
26
ginit             Initialise a new branch.
27
gmissing          GTK+ missing revisions dialog. 
28
gpreferences      GTK+ preferences dialog. 
323 by Jelmer Vernooij
Add gsend command.
29
gpush             GTK+ push.
30
gsend             GTK+ send merge directive.
31
gstatus           GTK+ status dialog.
208.2.1 by Robert Collins
Better module docstring.
32
gtags             Manage branch tags.
33
visualise         Graphically visualise this branch. 
34
"""
73 by Jelmer Vernooij
Release 0.9, list myself as maintainer.
35
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
36
import sys
37
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
38
import bzrlib
39
416 by Szilveszter Farkas (Phanatic)
Start working on 0.94
40
version_info = (0, 94, 0, 'dev', 0)
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
41
287 by Jelmer Vernooij
Use standard version tuple.
42
if version_info[3] == 'final':
43
    version_string = '%d.%d.%d' % version_info[:3]
44
else:
45
    version_string = '%d.%d.%d%s%d' % version_info
46
__version__ = version_string
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
47
451.1.1 by Daniel Schierbeck
Bumped required version of bzrlib to 1.3.
48
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
49
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
50
def check_bzrlib_version(desired):
51
    """Check that bzrlib is compatible.
52
53
    If version is < bzr-gtk version, assume incompatible.
54
    """
55
    bzrlib_version = bzrlib.version_info[:2]
56
    try:
57
        from bzrlib.trace import warning
58
    except ImportError:
59
        # get the message out any way we can
60
        from warnings import warn as warning
61
    if bzrlib_version < desired:
207 by Aaron Bentley
Import BzrError before using it
62
        from bzrlib.errors import BzrError
271 by Jelmer Vernooij
Add common widget for selecting branches.
63
        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).
64
                ' %s.' % (bzrlib.__version__, __version__))
287 by Jelmer Vernooij
Use standard version tuple.
65
        raise BzrError('Version mismatch: %r, %r' % (version_info, bzrlib.version_info) )
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
66
67
287 by Jelmer Vernooij
Use standard version tuple.
68
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
69
    check_bzrlib_version(required_bzrlib)
137 by Jelmer Vernooij
Warn about incompatible versions (taken from bzrtools, thanks Aaron).
70
146 by Jelmer Vernooij
Move more code to top-level directory.
71
from bzrlib.trace import warning
72
if __name__ != 'bzrlib.plugins.gtk':
73
    warning("Not running as bzrlib.plugins.gtk, things may break.")
74
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
75
from bzrlib.lazy_import import lazy_import
76
lazy_import(globals(), """
77
from bzrlib import (
78
    branch,
249 by Aaron Bentley
Add gselftest command
79
    builtins,
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
80
    errors,
426 by Aaron Bentley
Start support for Merge Directives
81
    merge_directive,
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
82
    workingtree,
83
    )
84
""")
85
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
86
from bzrlib.commands import Command, register_command, display_command
59.2.4 by Aaron Bentley
Teach gdiff to accept a single file argument
87
from bzrlib.errors import NotVersionedError, BzrCommandError, NoSuchFile
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
88
from bzrlib.option import Option
89
126.1.5 by Szilveszter Farkas (Phanatic)
bzr gbranch should work now (Fixed: #77751)
90
import os.path
91
66.2.20 by Aaron Bentley
Nicer error when PyGTK not installed
92
def import_pygtk():
93
    try:
94
        import pygtk
95
    except ImportError:
96
        raise errors.BzrCommandError("PyGTK not installed.")
97
    pygtk.require('2.0')
98
    return pygtk
99
100
133 by Jelmer Vernooij
Actually use the ui factory.
101
def set_ui_factory():
177 by Jelmer Vernooij
Register commands all at once.
102
    import_pygtk()
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
103
    from ui import GtkUIFactory
133 by Jelmer Vernooij
Actually use the ui factory.
104
    import bzrlib.ui
105
    bzrlib.ui.ui_factory = GtkUIFactory()
106
107
247 by Jelmer Vernooij
Use application path to find icons.
108
def data_path():
109
    return os.path.dirname(__file__)
110
111
399.1.19 by Jelmer Vernooij
Add utility function for finding icon paths.
112
def icon_path(*args):
113
    basedirs = [os.path.join(data_path()),
114
             "/usr/share/bzr-gtk", 
115
             "/usr/local/share/bzr-gtk"]
116
    for basedir in basedirs:
117
        path = os.path.join(basedir, 'icons', *args)
118
        if os.path.exists(path):
119
            return path
120
    return None
121
122
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
123
class GTKCommand(Command):
124
    """Abstract class providing GTK specific run commands."""
125
126
    def open_display(self):
127
        pygtk = import_pygtk()
128
        try:
129
            import gtk
130
        except RuntimeError, e:
131
            if str(e) == "could not open display":
132
                raise NoDisplayError
133
        set_ui_factory()
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
134
        return gtk
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
135
136
    def run(self):
137
        self.open_display()
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)
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
171
        self.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
196
                    revision_id = revision[0].in_history(branch).rev_id
197
                    tree2 = branch.repository.revision_tree(revision_id)
198
                elif len(revision) == 2:
199
                    revision_id_0 = revision[0].in_history(branch).rev_id
200
                    tree2 = branch.repository.revision_tree(revision_id_0)
201
                    revision_id_1 = revision[1].in_history(branch).rev_id
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:
264
                (revno, revid) = revision[0].in_history(br)
265
                revids.append(revid)
365 by Daniel Schierbeck
Fixed locks and made tagging work.
266
        import gtk
452.4.1 by Jelmer Vernooij
Support displaying multiple tips in viz.
267
        pp = start_viz_window(br, revids, limit)
365 by Daniel Schierbeck
Fixed locks and made tagging work.
268
        pp.connect("destroy", lambda w: gtk.main_quit())
269
        pp.show()
270
        gtk.main()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
271
272
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
273
class cmd_gannotate(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
274
    """GTK+ annotate.
275
    
276
    Browse changes to FILENAME line by line in a GTK+ window.
277
    """
278
59.2.1 by Aaron Bentley
Gannotate takes a line number
279
    takes_args = ["filename", "line?"]
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
280
    takes_options = [
208.2.7 by Vincent Ladeuil
Fix option help strings to comply with the style guide.
281
        Option("all", help="Show annotations on all lines."),
282
        Option("plain", help="Don't highlight annotation lines."),
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
283
        Option("line", type=int, argname="lineno",
208.2.7 by Vincent Ladeuil
Fix option help strings to comply with the style guide.
284
               help="Jump to specified line number."),
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
285
        "revision",
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
286
    ]
287
    aliases = ["gblame", "gpraise"]
288
    
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
289
    def run(self, filename, all=False, plain=False, line='1', revision=None):
187 by Jelmer Vernooij
Fix gannotate.
290
        gtk = self.open_display()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
291
59.2.1 by Aaron Bentley
Gannotate takes a line number
292
        try:
293
            line = int(line)
294
        except ValueError:
295
            raise BzrCommandError('Line argument ("%s") is not a number.' % 
296
                                  line)
297
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
298
        from annotate.gannotate import GAnnotateWindow
299
        from annotate.config import GAnnotateConfig
177 by Jelmer Vernooij
Register commands all at once.
300
        from bzrlib.bzrdir import BzrDir
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
301
161 by Aaron Bentley
Fix gannotate interaction with dirstate
302
        wt, br, path = BzrDir.open_containing_tree_or_branch(filename)
303
        if wt is not None:
304
            tree = wt
305
        else:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
306
            tree = br.basis_tree()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
307
66.2.18 by Aaron Bentley
Gannotate works with branches, not just trees
308
        file_id = tree.path2id(path)
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
309
310
        if file_id is None:
311
            raise NotVersionedError(filename)
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
312
        if revision is not None:
313
            if len(revision) != 1:
314
                raise BzrCommandError("Only 1 revion may be specified.")
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
315
            revision_id = revision[0].in_history(br).rev_id
316
            tree = br.repository.revision_tree(revision_id)
66.2.1 by Aaron Bentley
Gannotate takes a revision argument
317
        else:
66.2.18 by Aaron Bentley
Gannotate works with branches, not just trees
318
            revision_id = getattr(tree, 'get_revision_id', lambda: None)()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
319
320
        window = GAnnotateWindow(all, plain)
321
        window.connect("destroy", lambda w: gtk.main_quit())
322
        config = GAnnotateConfig(window)
323
        window.show()
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
324
        br.lock_read()
161 by Aaron Bentley
Fix gannotate interaction with dirstate
325
        if wt is not None:
326
            wt.lock_read()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
327
        try:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
328
            window.annotate(tree, br, file_id)
161 by Aaron Bentley
Fix gannotate interaction with dirstate
329
            window.jump_to_line(line)
330
            gtk.main()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
331
        finally:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
332
            br.unlock()
161 by Aaron Bentley
Fix gannotate interaction with dirstate
333
            if wt is not None:
334
                wt.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
335
336
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
337
338
class cmd_gcommit(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
339
    """GTK+ commit dialog
340
341
    Graphical user interface for committing revisions"""
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
342
145 by Jelmer Vernooij
Fix some strings, import.
343
    aliases = [ "gci" ]
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
344
    takes_args = []
345
    takes_options = []
346
347
    def run(self, filename=None):
93.1.17 by Alexander Belchenko
gcommit reworked again.
348
        import os
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
349
        self.open_display()
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
350
        from commit import CommitDialog
93.1.17 by Alexander Belchenko
gcommit reworked again.
351
        from bzrlib.errors import (BzrCommandError,
352
                                   NotBranchError,
178 by Jelmer Vernooij
Remove unneeded imports.
353
                                   NoWorkingTree)
93.1.17 by Alexander Belchenko
gcommit reworked again.
354
355
        wt = None
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
356
        br = None
93.1.17 by Alexander Belchenko
gcommit reworked again.
357
        try:
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
358
            (wt, path) = workingtree.WorkingTree.open_containing(filename)
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
359
            br = wt.branch
93.1.17 by Alexander Belchenko
gcommit reworked again.
360
        except NoWorkingTree, e:
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
361
            from dialog import error_dialog
362
            error_dialog(_('Directory does not have a working tree'),
363
                         _('Operation aborted.'))
364
            return 1 # should this be retval=3?
365
366
        # It is a good habit to keep things locked for the duration, but it
367
        # could cause difficulties if someone wants to do things in another
368
        # window... We could lock_read() until we actually go to commit
369
        # changes... Just a thought.
370
        wt.lock_write()
371
        try:
372
            dlg = CommitDialog(wt)
373
            return dlg.run()
374
        finally:
375
            wt.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
376
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
377
250 by Aaron Bentley
oops- revert status change
378
class cmd_gstatus(GTKCommand):
157 by Jelmer Vernooij
Add gstatus command.
379
    """GTK+ status dialog
380
381
    Graphical user interface for showing status 
382
    information."""
383
    
384
    aliases = [ "gst" ]
385
    takes_args = ['PATH?']
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
386
    takes_options = ['revision']
157 by Jelmer Vernooij
Add gstatus command.
387
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
388
    def run(self, path='.', revision=None):
157 by Jelmer Vernooij
Add gstatus command.
389
        import os
184 by Jelmer Vernooij
Fix gstatus
390
        gtk = self.open_display()
157 by Jelmer Vernooij
Add gstatus command.
391
        from status import StatusDialog
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
392
        (wt, wt_path) = workingtree.WorkingTree.open_containing(path)
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
393
        
394
        if revision is not None:
395
            revision_id = revision[0].in_history(wt.branch).rev_id
396
        else:
397
            revision_id = None
398
399
        status = StatusDialog(wt, wt_path, revision_id)
157 by Jelmer Vernooij
Add gstatus command.
400
        status.connect("destroy", gtk.main_quit)
401
        status.run()
402
403
323 by Jelmer Vernooij
Add gsend command.
404
class cmd_gsend(GTKCommand):
405
    """GTK+ send merge directive.
406
407
    """
408
    def run(self):
409
        (br, path) = branch.Branch.open_containing(".")
324 by Jelmer Vernooij
Add very simple "Send Merge Directive" window.
410
        gtk = self.open_display()
323 by Jelmer Vernooij
Add gsend command.
411
        from bzrlib.plugins.gtk.mergedirective import SendMergeDirectiveDialog
324 by Jelmer Vernooij
Add very simple "Send Merge Directive" window.
412
        from StringIO import StringIO
323 by Jelmer Vernooij
Add gsend command.
413
        dialog = SendMergeDirectiveDialog(br)
324 by Jelmer Vernooij
Add very simple "Send Merge Directive" window.
414
        if dialog.run() == gtk.RESPONSE_OK:
415
            outf = StringIO()
416
            outf.writelines(dialog.get_merge_directive().to_lines())
417
            mail_client = br.get_config().get_mail_client()
418
            mail_client.compose_merge_request(dialog.get_mail_to(), "[MERGE]", 
419
                outf.getvalue())
420
421
            
323 by Jelmer Vernooij
Add gsend command.
422
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
423
424
class cmd_gconflicts(GTKCommand):
323 by Jelmer Vernooij
Add gsend command.
425
    """GTK+ conflicts.
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
426
    
242.1.2 by Adeodato Simó
Fix gconflicts docstring.
427
    Select files from the list of conflicts and run an external utility to
428
    resolve them.
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
429
    """
430
    def run(self):
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
431
        (wt, path) = workingtree.WorkingTree.open_containing('.')
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
432
        self.open_display()
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
433
        from bzrlib.plugins.gtk.conflicts import ConflictsDialog
434
        dialog = ConflictsDialog(wt)
435
        dialog.run()
436
157 by Jelmer Vernooij
Add gstatus command.
437
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
438
class cmd_gpreferences(GTKCommand):
171 by Jelmer Vernooij
Initial work on a preferences dialog in GTK+, including a list of plugins with metadata browser.
439
    """ GTK+ preferences dialog.
440
441
    """
442
    def run(self):
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
443
        self.open_display()
171 by Jelmer Vernooij
Initial work on a preferences dialog in GTK+, including a list of plugins with metadata browser.
444
        from bzrlib.plugins.gtk.preferences import PreferencesWindow
445
        dialog = PreferencesWindow()
446
        dialog.run()
447
448
175 by Jelmer Vernooij
Add very simple gmissing command.
449
class cmd_gmissing(Command):
450
    """ GTK+ missing revisions dialog.
451
452
    """
453
    takes_args = ["other_branch?"]
454
    def run(self, other_branch=None):
455
        pygtk = import_pygtk()
456
        try:
457
            import gtk
458
        except RuntimeError, e:
459
            if str(e) == "could not open display":
460
                raise NoDisplayError
461
462
        from bzrlib.plugins.gtk.missing import MissingWindow
463
        from bzrlib.branch import Branch
464
465
        local_branch = Branch.open_containing(".")[0]
466
        if other_branch is None:
467
            other_branch = local_branch.get_parent()
468
            
469
            if other_branch is None:
470
                raise errors.BzrCommandError("No peer location known or specified.")
471
        remote_branch = Branch.open_containing(other_branch)[0]
472
        set_ui_factory()
473
        local_branch.lock_read()
474
        try:
475
            remote_branch.lock_read()
476
            try:
477
                dialog = MissingWindow(local_branch, remote_branch)
478
                dialog.run()
479
            finally:
480
                remote_branch.unlock()
481
        finally:
482
            local_branch.unlock()
483
177 by Jelmer Vernooij
Register commands all at once.
484
188.1.1 by Szilveszter Farkas (Phanatic)
Inital implementation of the Initialize dialog. Not fully functional yet.
485
class cmd_ginit(GTKCommand):
486
    def run(self):
487
        self.open_display()
488
        from initialize import InitDialog
489
        dialog = InitDialog(os.path.abspath(os.path.curdir))
490
        dialog.run()
491
492
190.1.1 by Szilveszter Farkas (Phanatic)
Added 'gtags' command and basic Tags window (just a skeleton).
493
class cmd_gtags(GTKCommand):
494
    def run(self):
495
        br = branch.Branch.open_containing('.')[0]
496
        
497
        gtk = self.open_display()
498
        from tags import TagsWindow
499
        window = TagsWindow(br)
500
        window.show()
501
        gtk.main()
502
503
177 by Jelmer Vernooij
Register commands all at once.
504
commands = [
323 by Jelmer Vernooij
Add gsend command.
505
    cmd_gannotate, 
506
    cmd_gbranch,
507
    cmd_gcheckout, 
508
    cmd_gcommit, 
509
    cmd_gconflicts, 
510
    cmd_gdiff,
511
    cmd_ginit,
177 by Jelmer Vernooij
Register commands all at once.
512
    cmd_gmissing, 
513
    cmd_gpreferences, 
323 by Jelmer Vernooij
Add gsend command.
514
    cmd_gpush, 
515
    cmd_gsend,
177 by Jelmer Vernooij
Register commands all at once.
516
    cmd_gstatus,
323 by Jelmer Vernooij
Add gsend command.
517
    cmd_gtags,
518
    cmd_visualise
177 by Jelmer Vernooij
Register commands all at once.
519
    ]
520
521
for cmd in commands:
522
    register_command(cmd)
175 by Jelmer Vernooij
Add very simple gmissing command.
523
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
524
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
525
class cmd_commit_notify(GTKCommand):
526
    """Run the bzr commit notifier.
527
528
    This is a background program which will pop up a notification on the users
529
    screen when a commit occurs.
530
    """
531
532
    def run(self):
211 by Jelmer Vernooij
Move notification area code into separate file.
533
        from notify import NotifyPopupMenu
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
534
        gtk = self.open_display()
211 by Jelmer Vernooij
Move notification area code into separate file.
535
        menu = NotifyPopupMenu()
399.1.19 by Jelmer Vernooij
Add utility function for finding icon paths.
536
        icon = gtk.status_icon_new_from_file(icon_path("bzr-icon-64.png"))
211 by Jelmer Vernooij
Move notification area code into separate file.
537
        icon.connect('popup-menu', menu.display)
210 by Jelmer Vernooij
Add notification area icon for commit-notify.
538
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
539
        import cgi
540
        import dbus
541
        import dbus.service
542
        import pynotify
543
        from bzrlib.bzrdir import BzrDir
544
        from bzrlib import errors
545
        from bzrlib.osutils import format_date
546
        from bzrlib.transport import get_transport
547
        if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
548
            import dbus.glib
450.2.1 by James Henstridge
Make commit-notify listen for Revision signals from any source rather
549
        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.
550
        bus = dbus.SessionBus()
211 by Jelmer Vernooij
Move notification area code into separate file.
551
182.1.1 by Robert Collins
Update commit-notify to use new dbus api, and show remote URL's.
552
        def catch_branch(revision_id, urls):
553
            # TODO: show all the urls, or perhaps choose the 'best'.
554
            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.
555
            try:
556
                if isinstance(revision_id, unicode):
557
                    revision_id = revision_id.encode('utf8')
558
                transport = get_transport(url)
559
                a_dir = BzrDir.open_from_transport(transport)
560
                branch = a_dir.open_branch()
561
                revno = branch.revision_id_to_revno(revision_id)
562
                revision = branch.repository.get_revision(revision_id)
563
                summary = 'New revision %d in %s' % (revno, url)
564
                body  = 'Committer: %s\n' % revision.committer
565
                body += 'Date: %s\n' % format_date(revision.timestamp,
566
                    revision.timezone)
567
                body += '\n'
568
                body += revision.message
569
                body = cgi.escape(body)
570
                nw = pynotify.Notification(summary, body)
208.2.2 by Robert Collins
Add inspect window to bzr commity-notify.
571
                def start_viz(notification=None, action=None, data=None):
572
                    """Start the viz program."""
573
                    pp = start_viz_window(branch, revision_id)
574
                    pp.show()
208.2.3 by Robert Collins
Add a Branch button to commit-notify.
575
                def start_branch(notification=None, action=None, data=None):
576
                    """Start a Branch dialog"""
577
                    from bzrlib.plugins.gtk.branch import BranchDialog
578
                    bd = BranchDialog(remote_path=url)
579
                    bd.run()
208.2.4 by Robert Collins
Unbreak inspect of commits due to misunderstanding of pynotify api.
580
                nw.add_action("inspect", "Inspect", start_viz, None)
581
                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.
582
                nw.set_timeout(5000)
583
                nw.show()
584
            except Exception, e:
585
                print e
586
                raise
450.2.1 by James Henstridge
Make commit-notify listen for Revision signals from any source rather
587
        bus.add_signal_receiver(catch_branch,
588
                                dbus_interface=BROADCAST_INTERFACE,
589
                                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.
590
        pynotify.init("bzr commit-notify")
591
        gtk.main()
592
593
register_command(cmd_commit_notify)
594
595
249 by Aaron Bentley
Add gselftest command
596
class cmd_gselftest(GTKCommand):
597
    """Version of selftest that displays a notification at the end"""
598
599
    takes_args = builtins.cmd_selftest.takes_args
600
    takes_options = builtins.cmd_selftest.takes_options
601
    _see_also = ['selftest']
602
603
    def run(self, *args, **kwargs):
604
        import cgi
253 by Aaron Bentley
Avoid encoding problems from pygtk
605
        import sys
606
        default_encoding = sys.getdefaultencoding()
249 by Aaron Bentley
Add gselftest command
607
        # prevent gtk from blowing up later
608
        gtk = import_pygtk()
253 by Aaron Bentley
Avoid encoding problems from pygtk
609
        # prevent gtk from messing with default encoding
249 by Aaron Bentley
Add gselftest command
610
        import pynotify
253 by Aaron Bentley
Avoid encoding problems from pygtk
611
        if sys.getdefaultencoding() != default_encoding:
612
            reload(sys)
613
            sys.setdefaultencoding(default_encoding)
249 by Aaron Bentley
Add gselftest command
614
        result = builtins.cmd_selftest().run(*args, **kwargs)
615
        if result == 0:
616
            summary = 'Success'
617
            body = 'Selftest succeeded in "%s"' % os.getcwd()
618
        if result == 1:
619
            summary = 'Failure'
620
            body = 'Selftest failed in "%s"' % os.getcwd()
621
        pynotify.init("bzr gselftest")
622
        note = pynotify.Notification(cgi.escape(summary), cgi.escape(body))
623
        note.set_timeout(pynotify.EXPIRES_NEVER)
624
        note.show()
625
626
627
register_command(cmd_gselftest)
628
629
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
630
class cmd_test_gtk(GTKCommand):
631
    """Version of selftest that just runs the gtk test suite."""
632
633
    takes_options = ['verbose',
634
                     Option('one', short_name='1',
330.6.2 by Aaron Bentley
Fix option grammar
635
                            help='Stop when one test fails.'),
636
                     Option('benchmark', help='Run the benchmarks.'),
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
637
                     Option('lsprof-timed',
330.6.2 by Aaron Bentley
Fix option grammar
638
                     help='Generate lsprof output for benchmarked'
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
639
                          ' sections of code.'),
640
                     Option('list-only',
330.6.2 by Aaron Bentley
Fix option grammar
641
                     help='List the tests instead of running them.'),
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
642
                     Option('randomize', type=str, argname="SEED",
330.6.2 by Aaron Bentley
Fix option grammar
643
                     help='Randomize the order of tests using the given'
644
                          ' seed or "now" for the current time.'),
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
645
                    ]
646
    takes_args = ['testspecs*']
647
648
    def run(self, verbose=None, one=False, benchmark=None,
649
            lsprof_timed=None, list_only=False, randomize=None,
650
            testspecs_list=None):
651
        from bzrlib import __path__ as bzrlib_path
652
        from bzrlib.tests import selftest
653
654
        print '%10s: %s' % ('bzrlib', bzrlib_path[0])
655
        if benchmark:
656
            print 'No benchmarks yet'
657
            return 3
658
659
            test_suite_factory = bench_suite
660
            if verbose is None:
661
                verbose = True
662
            # TODO: should possibly lock the history file...
663
            benchfile = open(".perf_history", "at", buffering=1)
664
        else:
665
            test_suite_factory = test_suite
666
            if verbose is None:
667
                verbose = False
668
            benchfile = None
669
670
        if testspecs_list is not None:
671
            pattern = '|'.join(testspecs_list)
672
        else:
673
            pattern = ".*"
674
675
        try:
676
            result = selftest(verbose=verbose,
677
                              pattern=pattern,
678
                              stop_on_failure=one,
679
                              test_suite_factory=test_suite_factory,
680
                              lsprof_timed=lsprof_timed,
681
                              bench_history=benchfile,
682
                              list_only=list_only,
683
                              random_seed=randomize,
684
                             )
685
        finally:
686
            if benchfile is not None:
687
                benchfile.close()
688
689
register_command(cmd_test_gtk)
690
691
424 by Aaron Bentley
Add ghandle-patch
692
class cmd_ghandle_patch(GTKCommand):
432 by Aaron Bentley
Misc updates
693
    """Display a patch or merge directive, possibly merging.
694
695
    This is a helper, meant to be launched from other programs like browsers
696
    or email clients.  Since these programs often do not allow parameters to
697
    be provided, a "handle-patch" script is included.
698
    """
424 by Aaron Bentley
Add ghandle-patch
699
700
    takes_args = ['path']
701
702
    def run(self, path):
426 by Aaron Bentley
Start support for Merge Directives
703
        try:
434 by Aaron Bentley
Better errors, merge directive saving
704
            from bzrlib.plugins.gtk.diff import (DiffWindow,
705
                                                 MergeDirectiveWindow)
706
            lines = open(path, 'rb').readlines()
707
            lines = [l.replace('\r\n', '\n') for l in lines]
708
            try:
709
                directive = merge_directive.MergeDirective.from_lines(lines)
710
            except errors.NotAMergeDirective:
711
                window = DiffWindow()
712
                window.set_diff_text(path, lines)
713
            else:
714
                window = MergeDirectiveWindow(directive, path)
715
                window.set_diff_text(path, directive.patch.splitlines(True))
716
            window.show()
717
            gtk = self.open_display()
718
            window.connect("destroy", gtk.main_quit)
719
        except Exception, e:
720
            from dialog import error_dialog
721
            error_dialog('Error', str(e))
722
            raise
424 by Aaron Bentley
Add ghandle-patch
723
        gtk.main()
724
725
726
register_command(cmd_ghandle_patch)
727
728
152 by Jelmer Vernooij
Cleanup some more code.
729
import gettext
730
gettext.install('olive-gtk')
731
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
732
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
733
class NoDisplayError(BzrCommandError):
734
    """gtk could not find a proper display"""
735
736
    def __str__(self):
133 by Jelmer Vernooij
Actually use the ui factory.
737
        return "No DISPLAY. Unable to run GTK+ application."
738
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
739
140 by Jelmer Vernooij
add framework for tests.
740
def test_suite():
741
    from unittest import TestSuite
742
    import tests
163 by Aaron Bentley
Prevent test suite from causing default-encoding changes
743
    import sys
744
    default_encoding = sys.getdefaultencoding()
745
    try:
746
        result = TestSuite()
330.6.4 by Aaron Bentley
Allow test suite to run without pygtk
747
        try:
748
            import_pygtk()
749
        except errors.BzrCommandError:
750
            return result
163 by Aaron Bentley
Prevent test suite from causing default-encoding changes
751
        result.addTest(tests.test_suite())
752
    finally:
170.1.2 by Aaron Bentley
Test suite only fixes encoding if it's changed. Fixes test_selftest bug.
753
        if sys.getdefaultencoding() != default_encoding:
754
            reload(sys)
755
            sys.setdefaultencoding(default_encoding)
140 by Jelmer Vernooij
add framework for tests.
756
    return result