/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to __init__.py

  • Committer: Jelmer Vernooij
  • Date: 2008-03-09 13:47:52 UTC
  • mto: This revision was merged to the branch mainline in revision 447.
  • Revision ID: jelmer@samba.org-20080309134752-syf9kwzy6e919jhj
Add note about python-nautilus requiring a libpythonXX.so symlink.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
# along with this program; if not, write to the Free Software
13
13
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14
14
 
15
 
"""GTK+ frontends to Bazaar commands """
 
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. 
 
22
gcommit           GTK+ commit dialog.
 
23
gconflicts        GTK+ conflicts. 
 
24
gdiff             Show differences in working tree in a GTK+ Window. 
 
25
ghandle-patch     Display and optionally merge a merge directive or patch.
 
26
ginit             Initialise a new branch.
 
27
gmissing          GTK+ missing revisions dialog. 
 
28
gpreferences      GTK+ preferences dialog. 
 
29
gpush             GTK+ push.
 
30
gsend             GTK+ send merge directive.
 
31
gstatus           GTK+ status dialog.
 
32
gtags             Manage branch tags.
 
33
visualise         Graphically visualise this branch. 
 
34
"""
 
35
 
 
36
import sys
16
37
 
17
38
import bzrlib
18
39
 
19
 
__version__ = '0.15.0'
20
 
version_info = tuple(int(n) for n in __version__.split('.'))
21
 
 
 
40
version_info = (0, 94, 0, 'dev', 0)
 
41
 
 
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
 
47
 
 
48
required_bzrlib = (1, 0)
22
49
 
23
50
def check_bzrlib_version(desired):
24
51
    """Check that bzrlib is compatible.
25
52
 
26
53
    If version is < bzr-gtk version, assume incompatible.
27
 
    If version == bzr-gtk version, assume completely compatible
28
 
    If version == bzr-gtk version + 1, assume compatible, with deprecations
29
 
    Otherwise, assume incompatible.
30
54
    """
31
 
    desired_plus = (desired[0], desired[1]+1)
32
55
    bzrlib_version = bzrlib.version_info[:2]
33
 
    if bzrlib_version == desired:
34
 
        return
35
56
    try:
36
57
        from bzrlib.trace import warning
37
58
    except ImportError:
38
59
        # get the message out any way we can
39
60
        from warnings import warn as warning
40
61
    if bzrlib_version < desired:
41
 
        warning('Installed bzr version %s is too old to be used with bzr-gtk'
 
62
        from bzrlib.errors import BzrError
 
63
        warning('Installed Bazaar version %s is too old to be used with bzr-gtk'
42
64
                ' %s.' % (bzrlib.__version__, __version__))
43
 
        # Not using BzrNewError, because it may not exist.
44
 
        raise Exception, ('Version mismatch', version_info)
45
 
    else:
46
 
        warning('bzr-gtk is not up to date with installed bzr version %s.'
47
 
                ' \nThere should be a newer version available, e.g. %i.%i.' 
48
 
                % (bzrlib.__version__, bzrlib_version[0], bzrlib_version[1]))
49
 
        if bzrlib_version != desired_plus:
50
 
            raise Exception, 'Version mismatch'
51
 
 
52
 
 
53
 
check_bzrlib_version(version_info[:2])
 
65
        raise BzrError('Version mismatch: %r, %r' % (version_info, bzrlib.version_info) )
 
66
 
 
67
 
 
68
if version_info[2] == "final":
 
69
    check_bzrlib_version(required_bzrlib)
54
70
 
55
71
from bzrlib.trace import warning
56
72
if __name__ != 'bzrlib.plugins.gtk':
57
73
    warning("Not running as bzrlib.plugins.gtk, things may break.")
58
74
 
59
 
from bzrlib import errors
 
75
from bzrlib.lazy_import import lazy_import
 
76
lazy_import(globals(), """
 
77
from bzrlib import (
 
78
    branch,
 
79
    builtins,
 
80
    errors,
 
81
    merge_directive,
 
82
    workingtree,
 
83
    )
 
84
""")
 
85
 
60
86
from bzrlib.commands import Command, register_command, display_command
61
87
from bzrlib.errors import NotVersionedError, BzrCommandError, NoSuchFile
62
 
from bzrlib.commands import Command, register_command
63
88
from bzrlib.option import Option
64
 
from bzrlib.branch import Branch
65
 
from bzrlib.workingtree import WorkingTree
66
 
from bzrlib.bzrdir import BzrDir
67
89
 
68
90
import os.path
69
91
 
77
99
 
78
100
 
79
101
def set_ui_factory():
80
 
    pygtk = import_pygtk()
 
102
    import_pygtk()
81
103
    from ui import GtkUIFactory
82
104
    import bzrlib.ui
83
105
    bzrlib.ui.ui_factory = GtkUIFactory()
84
106
 
85
107
 
86
 
class cmd_gbranch(Command):
 
108
def data_path():
 
109
    return os.path.dirname(__file__)
 
110
 
 
111
 
 
112
class GTKCommand(Command):
 
113
    """Abstract class providing GTK specific run commands."""
 
114
 
 
115
    def open_display(self):
 
116
        pygtk = import_pygtk()
 
117
        try:
 
118
            import gtk
 
119
        except RuntimeError, e:
 
120
            if str(e) == "could not open display":
 
121
                raise NoDisplayError
 
122
        set_ui_factory()
 
123
        return gtk
 
124
 
 
125
    def run(self):
 
126
        self.open_display()
 
127
        dialog = self.get_gtk_dialog(os.path.abspath('.'))
 
128
        dialog.run()
 
129
 
 
130
 
 
131
class cmd_gbranch(GTKCommand):
87
132
    """GTK+ branching.
88
133
    
89
134
    """
90
135
 
91
 
    def run(self):
92
 
        pygtk = import_pygtk()
93
 
        try:
94
 
            import gtk
95
 
        except RuntimeError, e:
96
 
            if str(e) == "could not open display":
97
 
                raise NoDisplayError
98
 
 
 
136
    def get_gtk_dialog(self, path):
99
137
        from bzrlib.plugins.gtk.branch import BranchDialog
100
 
 
101
 
        set_ui_factory()
102
 
        dialog = BranchDialog(os.path.abspath('.'))
103
 
        dialog.run()
104
 
 
105
 
register_command(cmd_gbranch)
106
 
 
107
 
class cmd_gcheckout(Command):
 
138
        return BranchDialog(path)
 
139
 
 
140
 
 
141
class cmd_gcheckout(GTKCommand):
108
142
    """ GTK+ checkout.
109
143
    
110
144
    """
111
145
    
112
 
    def run(self):
113
 
        pygtk = import_pygtk()
114
 
        try:
115
 
            import gtk
116
 
        except RuntimeError, e:
117
 
            if str(e) == "could not open display":
118
 
                raise NoDisplayError
119
 
 
 
146
    def get_gtk_dialog(self, path):
120
147
        from bzrlib.plugins.gtk.checkout import CheckoutDialog
121
 
 
122
 
        set_ui_factory()
123
 
        dialog = CheckoutDialog(os.path.abspath('.'))
124
 
        dialog.run()
125
 
 
126
 
register_command(cmd_gcheckout)
127
 
 
128
 
class cmd_gpush(Command):
 
148
        return CheckoutDialog(path)
 
149
 
 
150
 
 
151
 
 
152
class cmd_gpush(GTKCommand):
129
153
    """ GTK+ push.
130
154
    
131
155
    """
132
156
    takes_args = [ "location?" ]
133
 
    
 
157
 
134
158
    def run(self, location="."):
135
 
        (branch, path) = Branch.open_containing(location)
136
 
        
137
 
        pygtk = import_pygtk()
138
 
        try:
139
 
            import gtk
140
 
        except RuntimeError, e:
141
 
            if str(e) == "could not open display":
142
 
                raise NoDisplayError
143
 
 
 
159
        (br, path) = branch.Branch.open_containing(location)
 
160
        self.open_display()
144
161
        from push import PushDialog
145
 
 
146
 
        set_ui_factory()
147
 
        dialog = PushDialog(branch)
 
162
        dialog = PushDialog(br.repository, br.last_revision(), br)
148
163
        dialog.run()
149
164
 
150
 
register_command(cmd_gpush)
151
 
 
152
 
class cmd_gdiff(Command):
 
165
 
 
166
 
 
167
class cmd_gdiff(GTKCommand):
153
168
    """Show differences in working tree in a GTK+ Window.
154
169
    
155
170
    Otherwise, all changes for the tree are listed.
160
175
    @display_command
161
176
    def run(self, revision=None, filename=None):
162
177
        set_ui_factory()
163
 
        wt = WorkingTree.open_containing(".")[0]
164
 
        branch = wt.branch
165
 
        if revision is not None:
166
 
            if len(revision) == 1:
 
178
        wt = workingtree.WorkingTree.open_containing(".")[0]
 
179
        wt.lock_read()
 
180
        try:
 
181
            branch = wt.branch
 
182
            if revision is not None:
 
183
                if len(revision) == 1:
 
184
                    tree1 = wt
 
185
                    revision_id = revision[0].in_history(branch).rev_id
 
186
                    tree2 = branch.repository.revision_tree(revision_id)
 
187
                elif len(revision) == 2:
 
188
                    revision_id_0 = revision[0].in_history(branch).rev_id
 
189
                    tree2 = branch.repository.revision_tree(revision_id_0)
 
190
                    revision_id_1 = revision[1].in_history(branch).rev_id
 
191
                    tree1 = branch.repository.revision_tree(revision_id_1)
 
192
            else:
167
193
                tree1 = wt
168
 
                revision_id = revision[0].in_history(branch).rev_id
169
 
                tree2 = branch.repository.revision_tree(revision_id)
170
 
            elif len(revision) == 2:
171
 
                revision_id_0 = revision[0].in_history(branch).rev_id
172
 
                tree2 = branch.repository.revision_tree(revision_id_0)
173
 
                revision_id_1 = revision[1].in_history(branch).rev_id
174
 
                tree1 = branch.repository.revision_tree(revision_id_1)
175
 
        else:
176
 
            tree1 = wt
177
 
            tree2 = tree1.basis_tree()
178
 
 
179
 
        from viz.diff import DiffWindow
180
 
        import gtk
181
 
        window = DiffWindow()
182
 
        window.connect("destroy", lambda w: gtk.main_quit())
183
 
        window.set_diff("Working Tree", tree1, tree2)
184
 
        if filename is not None:
185
 
            tree_filename = wt.relpath(filename)
186
 
            try:
187
 
                window.set_file(tree_filename)
188
 
            except NoSuchFile:
189
 
                if (tree1.inventory.path2id(tree_filename) is None and 
190
 
                    tree2.inventory.path2id(tree_filename) is None):
191
 
                    raise NotVersionedError(filename)
192
 
                raise BzrCommandError('No changes found for file "%s"' % 
193
 
                                      filename)
194
 
        window.show()
195
 
 
196
 
        gtk.main()
197
 
 
198
 
register_command(cmd_gdiff)
 
194
                tree2 = tree1.basis_tree()
 
195
 
 
196
            from diff import DiffWindow
 
197
            import gtk
 
198
            window = DiffWindow()
 
199
            window.connect("destroy", gtk.main_quit)
 
200
            window.set_diff("Working Tree", tree1, tree2)
 
201
            if filename is not None:
 
202
                tree_filename = wt.relpath(filename)
 
203
                try:
 
204
                    window.set_file(tree_filename)
 
205
                except NoSuchFile:
 
206
                    if (tree1.path2id(tree_filename) is None and 
 
207
                        tree2.path2id(tree_filename) is None):
 
208
                        raise NotVersionedError(filename)
 
209
                    raise BzrCommandError('No changes found for file "%s"' % 
 
210
                                          filename)
 
211
            window.show()
 
212
 
 
213
            gtk.main()
 
214
        finally:
 
215
            wt.unlock()
 
216
 
 
217
 
 
218
def start_viz_window(branch, revision, limit=None):
 
219
    """Start viz on branch with revision revision.
 
220
    
 
221
    :return: The viz window object.
 
222
    """
 
223
    from viz import BranchWindow
 
224
    return BranchWindow(branch, revision, limit)
 
225
 
199
226
 
200
227
class cmd_visualise(Command):
201
228
    """Graphically visualise this branch.
208
235
    """
209
236
    takes_options = [
210
237
        "revision",
211
 
        Option('limit', "maximum number of revisions to display",
 
238
        Option('limit', "Maximum number of revisions to display.",
212
239
               int, 'count')]
213
240
    takes_args = [ "location?" ]
214
241
    aliases = [ "visualize", "vis", "viz" ]
215
242
 
216
243
    def run(self, location=".", revision=None, limit=None):
217
244
        set_ui_factory()
218
 
        (branch, path) = Branch.open_containing(location)
219
 
        branch.lock_read()
220
 
        branch.repository.lock_read()
221
 
        try:
222
 
            if revision is None:
223
 
                revid = branch.last_revision()
224
 
                if revid is None:
225
 
                    return
226
 
            else:
227
 
                (revno, revid) = revision[0].in_history(branch)
228
 
 
229
 
            from viz.bzrkapp import BzrkApp
230
 
                
231
 
            app = BzrkApp()
232
 
            app.show(branch, revid, limit)
233
 
        finally:
234
 
            branch.repository.unlock()
235
 
            branch.unlock()
236
 
        app.main()
237
 
 
238
 
 
239
 
register_command(cmd_visualise)
240
 
 
241
 
class cmd_gannotate(Command):
 
245
        (br, path) = branch.Branch.open_containing(location)
 
246
        if revision is None:
 
247
            revid = br.last_revision()
 
248
            if revid is None:
 
249
                return
 
250
        else:
 
251
            (revno, revid) = revision[0].in_history(br)
 
252
 
 
253
        import gtk
 
254
        pp = start_viz_window(br, revid, limit)
 
255
        pp.connect("destroy", lambda w: gtk.main_quit())
 
256
        pp.show()
 
257
        gtk.main()
 
258
 
 
259
 
 
260
class cmd_gannotate(GTKCommand):
242
261
    """GTK+ annotate.
243
262
    
244
263
    Browse changes to FILENAME line by line in a GTK+ window.
246
265
 
247
266
    takes_args = ["filename", "line?"]
248
267
    takes_options = [
249
 
        Option("all", help="show annotations on all lines"),
250
 
        Option("plain", help="don't highlight annotation lines"),
 
268
        Option("all", help="Show annotations on all lines."),
 
269
        Option("plain", help="Don't highlight annotation lines."),
251
270
        Option("line", type=int, argname="lineno",
252
 
               help="jump to specified line number"),
 
271
               help="Jump to specified line number."),
253
272
        "revision",
254
273
    ]
255
274
    aliases = ["gblame", "gpraise"]
256
275
    
257
276
    def run(self, filename, all=False, plain=False, line='1', revision=None):
258
 
        pygtk = import_pygtk()
259
 
 
260
 
        try:
261
 
            import gtk
262
 
        except RuntimeError, e:
263
 
            if str(e) == "could not open display":
264
 
                raise NoDisplayError
265
 
        set_ui_factory()
 
277
        gtk = self.open_display()
266
278
 
267
279
        try:
268
280
            line = int(line)
272
284
 
273
285
        from annotate.gannotate import GAnnotateWindow
274
286
        from annotate.config import GAnnotateConfig
 
287
        from bzrlib.bzrdir import BzrDir
275
288
 
276
 
        try:
277
 
            (tree, path) = WorkingTree.open_containing(filename)
278
 
            branch = tree.branch
279
 
        except errors.NoWorkingTree:
280
 
            (branch, path) = Branch.open_containing(filename)
281
 
            tree = branch.basis_tree()
 
289
        wt, br, path = BzrDir.open_containing_tree_or_branch(filename)
 
290
        if wt is not None:
 
291
            tree = wt
 
292
        else:
 
293
            tree = br.basis_tree()
282
294
 
283
295
        file_id = tree.path2id(path)
284
296
 
287
299
        if revision is not None:
288
300
            if len(revision) != 1:
289
301
                raise BzrCommandError("Only 1 revion may be specified.")
290
 
            revision_id = revision[0].in_history(branch).rev_id
291
 
            tree = branch.repository.revision_tree(revision_id)
 
302
            revision_id = revision[0].in_history(br).rev_id
 
303
            tree = br.repository.revision_tree(revision_id)
292
304
        else:
293
305
            revision_id = getattr(tree, 'get_revision_id', lambda: None)()
294
306
 
295
307
        window = GAnnotateWindow(all, plain)
296
308
        window.connect("destroy", lambda w: gtk.main_quit())
297
 
        window.set_title(path + " - gannotate")
298
309
        config = GAnnotateConfig(window)
299
310
        window.show()
300
 
        branch.lock_read()
 
311
        br.lock_read()
 
312
        if wt is not None:
 
313
            wt.lock_read()
301
314
        try:
302
 
            window.annotate(tree, branch, file_id)
 
315
            window.annotate(tree, br, file_id)
 
316
            window.jump_to_line(line)
 
317
            gtk.main()
303
318
        finally:
304
 
            branch.unlock()
305
 
        window.jump_to_line(line)
306
 
        
307
 
        gtk.main()
308
 
 
309
 
register_command(cmd_gannotate)
310
 
 
311
 
class cmd_gcommit(Command):
 
319
            br.unlock()
 
320
            if wt is not None:
 
321
                wt.unlock()
 
322
 
 
323
 
 
324
 
 
325
class cmd_gcommit(GTKCommand):
312
326
    """GTK+ commit dialog
313
327
 
314
328
    Graphical user interface for committing revisions"""
315
 
    
 
329
 
316
330
    aliases = [ "gci" ]
317
331
    takes_args = []
318
332
    takes_options = []
319
333
 
320
334
    def run(self, filename=None):
321
335
        import os
322
 
        pygtk = import_pygtk()
323
 
 
324
 
        try:
325
 
            import gtk
326
 
        except RuntimeError, e:
327
 
            if str(e) == "could not open display":
328
 
                raise NoDisplayError
329
 
 
330
 
        set_ui_factory()
 
336
        self.open_display()
331
337
        from commit import CommitDialog
332
 
        from bzrlib.commit import Commit
333
338
        from bzrlib.errors import (BzrCommandError,
334
339
                                   NotBranchError,
335
 
                                   NoWorkingTree,
336
 
                                   PointlessCommit,
337
 
                                   ConflictsInTree,
338
 
                                   StrictCommitFailed)
 
340
                                   NoWorkingTree)
339
341
 
340
342
        wt = None
341
 
        branch = None
 
343
        br = None
342
344
        try:
343
 
            (wt, path) = WorkingTree.open_containing(filename)
344
 
            branch = wt.branch
345
 
        except NotBranchError, e:
346
 
            path = e.path
 
345
            (wt, path) = workingtree.WorkingTree.open_containing(filename)
 
346
            br = wt.branch
347
347
        except NoWorkingTree, e:
348
 
            path = e.base
349
 
            try:
350
 
                (branch, path) = Branch.open_containing(path)
351
 
            except NotBranchError, e:
352
 
                path = e.path
353
 
 
354
 
 
355
 
        commit = CommitDialog(wt, path, not branch)
356
 
        commit.run()
357
 
 
358
 
register_command(cmd_gcommit)
 
348
            from dialog import error_dialog
 
349
            error_dialog(_('Directory does not have a working tree'),
 
350
                         _('Operation aborted.'))
 
351
            return 1 # should this be retval=3?
 
352
 
 
353
        # It is a good habit to keep things locked for the duration, but it
 
354
        # could cause difficulties if someone wants to do things in another
 
355
        # window... We could lock_read() until we actually go to commit
 
356
        # changes... Just a thought.
 
357
        wt.lock_write()
 
358
        try:
 
359
            dlg = CommitDialog(wt)
 
360
            return dlg.run()
 
361
        finally:
 
362
            wt.unlock()
 
363
 
 
364
 
 
365
class cmd_gstatus(GTKCommand):
 
366
    """GTK+ status dialog
 
367
 
 
368
    Graphical user interface for showing status 
 
369
    information."""
 
370
    
 
371
    aliases = [ "gst" ]
 
372
    takes_args = ['PATH?']
 
373
    takes_options = []
 
374
 
 
375
    def run(self, path='.'):
 
376
        import os
 
377
        gtk = self.open_display()
 
378
        from status import StatusDialog
 
379
        (wt, wt_path) = workingtree.WorkingTree.open_containing(path)
 
380
        status = StatusDialog(wt, wt_path)
 
381
        status.connect("destroy", gtk.main_quit)
 
382
        status.run()
 
383
 
 
384
 
 
385
class cmd_gsend(GTKCommand):
 
386
    """GTK+ send merge directive.
 
387
 
 
388
    """
 
389
    def run(self):
 
390
        (br, path) = branch.Branch.open_containing(".")
 
391
        gtk = self.open_display()
 
392
        from bzrlib.plugins.gtk.mergedirective import SendMergeDirectiveDialog
 
393
        from StringIO import StringIO
 
394
        dialog = SendMergeDirectiveDialog(br)
 
395
        if dialog.run() == gtk.RESPONSE_OK:
 
396
            outf = StringIO()
 
397
            outf.writelines(dialog.get_merge_directive().to_lines())
 
398
            mail_client = br.get_config().get_mail_client()
 
399
            mail_client.compose_merge_request(dialog.get_mail_to(), "[MERGE]", 
 
400
                outf.getvalue())
 
401
 
 
402
            
 
403
 
 
404
 
 
405
class cmd_gconflicts(GTKCommand):
 
406
    """GTK+ conflicts.
 
407
    
 
408
    Select files from the list of conflicts and run an external utility to
 
409
    resolve them.
 
410
    """
 
411
    def run(self):
 
412
        (wt, path) = workingtree.WorkingTree.open_containing('.')
 
413
        self.open_display()
 
414
        from bzrlib.plugins.gtk.conflicts import ConflictsDialog
 
415
        dialog = ConflictsDialog(wt)
 
416
        dialog.run()
 
417
 
 
418
 
 
419
class cmd_gpreferences(GTKCommand):
 
420
    """ GTK+ preferences dialog.
 
421
 
 
422
    """
 
423
    def run(self):
 
424
        self.open_display()
 
425
        from bzrlib.plugins.gtk.preferences import PreferencesWindow
 
426
        dialog = PreferencesWindow()
 
427
        dialog.run()
 
428
 
 
429
 
 
430
class cmd_gmissing(Command):
 
431
    """ GTK+ missing revisions dialog.
 
432
 
 
433
    """
 
434
    takes_args = ["other_branch?"]
 
435
    def run(self, other_branch=None):
 
436
        pygtk = import_pygtk()
 
437
        try:
 
438
            import gtk
 
439
        except RuntimeError, e:
 
440
            if str(e) == "could not open display":
 
441
                raise NoDisplayError
 
442
 
 
443
        from bzrlib.plugins.gtk.missing import MissingWindow
 
444
        from bzrlib.branch import Branch
 
445
 
 
446
        local_branch = Branch.open_containing(".")[0]
 
447
        if other_branch is None:
 
448
            other_branch = local_branch.get_parent()
 
449
            
 
450
            if other_branch is None:
 
451
                raise errors.BzrCommandError("No peer location known or specified.")
 
452
        remote_branch = Branch.open_containing(other_branch)[0]
 
453
        set_ui_factory()
 
454
        local_branch.lock_read()
 
455
        try:
 
456
            remote_branch.lock_read()
 
457
            try:
 
458
                dialog = MissingWindow(local_branch, remote_branch)
 
459
                dialog.run()
 
460
            finally:
 
461
                remote_branch.unlock()
 
462
        finally:
 
463
            local_branch.unlock()
 
464
 
 
465
 
 
466
class cmd_ginit(GTKCommand):
 
467
    def run(self):
 
468
        self.open_display()
 
469
        from initialize import InitDialog
 
470
        dialog = InitDialog(os.path.abspath(os.path.curdir))
 
471
        dialog.run()
 
472
 
 
473
 
 
474
class cmd_gtags(GTKCommand):
 
475
    def run(self):
 
476
        br = branch.Branch.open_containing('.')[0]
 
477
        
 
478
        gtk = self.open_display()
 
479
        from tags import TagsWindow
 
480
        window = TagsWindow(br)
 
481
        window.show()
 
482
        gtk.main()
 
483
 
 
484
 
 
485
commands = [
 
486
    cmd_gannotate, 
 
487
    cmd_gbranch,
 
488
    cmd_gcheckout, 
 
489
    cmd_gcommit, 
 
490
    cmd_gconflicts, 
 
491
    cmd_gdiff,
 
492
    cmd_ginit,
 
493
    cmd_gmissing, 
 
494
    cmd_gpreferences, 
 
495
    cmd_gpush, 
 
496
    cmd_gsend,
 
497
    cmd_gstatus,
 
498
    cmd_gtags,
 
499
    cmd_visualise
 
500
    ]
 
501
 
 
502
for cmd in commands:
 
503
    register_command(cmd)
 
504
 
 
505
 
 
506
class cmd_commit_notify(GTKCommand):
 
507
    """Run the bzr commit notifier.
 
508
 
 
509
    This is a background program which will pop up a notification on the users
 
510
    screen when a commit occurs.
 
511
    """
 
512
 
 
513
    def run(self):
 
514
        from notify import NotifyPopupMenu
 
515
        gtk = self.open_display()
 
516
        menu = NotifyPopupMenu()
 
517
        icon = gtk.status_icon_new_from_file(os.path.join(data_path(), "bzr-icon-64.png"))
 
518
        icon.connect('popup-menu', menu.display)
 
519
 
 
520
        import cgi
 
521
        import dbus
 
522
        import dbus.service
 
523
        import pynotify
 
524
        from bzrlib.bzrdir import BzrDir
 
525
        from bzrlib import errors
 
526
        from bzrlib.osutils import format_date
 
527
        from bzrlib.transport import get_transport
 
528
        if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
 
529
            import dbus.glib
 
530
        from bzrlib.plugins.dbus import activity
 
531
        bus = dbus.SessionBus()
 
532
        # get the object so we can subscribe to callbacks from it.
 
533
        broadcast_service = bus.get_object(
 
534
            activity.Broadcast.DBUS_NAME,
 
535
            activity.Broadcast.DBUS_PATH)
 
536
 
 
537
        def catch_branch(revision_id, urls):
 
538
            # TODO: show all the urls, or perhaps choose the 'best'.
 
539
            url = urls[0]
 
540
            try:
 
541
                if isinstance(revision_id, unicode):
 
542
                    revision_id = revision_id.encode('utf8')
 
543
                transport = get_transport(url)
 
544
                a_dir = BzrDir.open_from_transport(transport)
 
545
                branch = a_dir.open_branch()
 
546
                revno = branch.revision_id_to_revno(revision_id)
 
547
                revision = branch.repository.get_revision(revision_id)
 
548
                summary = 'New revision %d in %s' % (revno, url)
 
549
                body  = 'Committer: %s\n' % revision.committer
 
550
                body += 'Date: %s\n' % format_date(revision.timestamp,
 
551
                    revision.timezone)
 
552
                body += '\n'
 
553
                body += revision.message
 
554
                body = cgi.escape(body)
 
555
                nw = pynotify.Notification(summary, body)
 
556
                def start_viz(notification=None, action=None, data=None):
 
557
                    """Start the viz program."""
 
558
                    pp = start_viz_window(branch, revision_id)
 
559
                    pp.show()
 
560
                def start_branch(notification=None, action=None, data=None):
 
561
                    """Start a Branch dialog"""
 
562
                    from bzrlib.plugins.gtk.branch import BranchDialog
 
563
                    bd = BranchDialog(remote_path=url)
 
564
                    bd.run()
 
565
                nw.add_action("inspect", "Inspect", start_viz, None)
 
566
                nw.add_action("branch", "Branch", start_branch, None)
 
567
                nw.set_timeout(5000)
 
568
                nw.show()
 
569
            except Exception, e:
 
570
                print e
 
571
                raise
 
572
        broadcast_service.connect_to_signal("Revision", catch_branch,
 
573
            dbus_interface=activity.Broadcast.DBUS_INTERFACE)
 
574
        pynotify.init("bzr commit-notify")
 
575
        gtk.main()
 
576
 
 
577
register_command(cmd_commit_notify)
 
578
 
 
579
 
 
580
class cmd_gselftest(GTKCommand):
 
581
    """Version of selftest that displays a notification at the end"""
 
582
 
 
583
    takes_args = builtins.cmd_selftest.takes_args
 
584
    takes_options = builtins.cmd_selftest.takes_options
 
585
    _see_also = ['selftest']
 
586
 
 
587
    def run(self, *args, **kwargs):
 
588
        import cgi
 
589
        import sys
 
590
        default_encoding = sys.getdefaultencoding()
 
591
        # prevent gtk from blowing up later
 
592
        gtk = import_pygtk()
 
593
        # prevent gtk from messing with default encoding
 
594
        import pynotify
 
595
        if sys.getdefaultencoding() != default_encoding:
 
596
            reload(sys)
 
597
            sys.setdefaultencoding(default_encoding)
 
598
        result = builtins.cmd_selftest().run(*args, **kwargs)
 
599
        if result == 0:
 
600
            summary = 'Success'
 
601
            body = 'Selftest succeeded in "%s"' % os.getcwd()
 
602
        if result == 1:
 
603
            summary = 'Failure'
 
604
            body = 'Selftest failed in "%s"' % os.getcwd()
 
605
        pynotify.init("bzr gselftest")
 
606
        note = pynotify.Notification(cgi.escape(summary), cgi.escape(body))
 
607
        note.set_timeout(pynotify.EXPIRES_NEVER)
 
608
        note.show()
 
609
 
 
610
 
 
611
register_command(cmd_gselftest)
 
612
 
 
613
 
 
614
class cmd_test_gtk(GTKCommand):
 
615
    """Version of selftest that just runs the gtk test suite."""
 
616
 
 
617
    takes_options = ['verbose',
 
618
                     Option('one', short_name='1',
 
619
                            help='Stop when one test fails.'),
 
620
                     Option('benchmark', help='Run the benchmarks.'),
 
621
                     Option('lsprof-timed',
 
622
                     help='Generate lsprof output for benchmarked'
 
623
                          ' sections of code.'),
 
624
                     Option('list-only',
 
625
                     help='List the tests instead of running them.'),
 
626
                     Option('randomize', type=str, argname="SEED",
 
627
                     help='Randomize the order of tests using the given'
 
628
                          ' seed or "now" for the current time.'),
 
629
                    ]
 
630
    takes_args = ['testspecs*']
 
631
 
 
632
    def run(self, verbose=None, one=False, benchmark=None,
 
633
            lsprof_timed=None, list_only=False, randomize=None,
 
634
            testspecs_list=None):
 
635
        from bzrlib import __path__ as bzrlib_path
 
636
        from bzrlib.tests import selftest
 
637
 
 
638
        print '%10s: %s' % ('bzrlib', bzrlib_path[0])
 
639
        if benchmark:
 
640
            print 'No benchmarks yet'
 
641
            return 3
 
642
 
 
643
            test_suite_factory = bench_suite
 
644
            if verbose is None:
 
645
                verbose = True
 
646
            # TODO: should possibly lock the history file...
 
647
            benchfile = open(".perf_history", "at", buffering=1)
 
648
        else:
 
649
            test_suite_factory = test_suite
 
650
            if verbose is None:
 
651
                verbose = False
 
652
            benchfile = None
 
653
 
 
654
        if testspecs_list is not None:
 
655
            pattern = '|'.join(testspecs_list)
 
656
        else:
 
657
            pattern = ".*"
 
658
 
 
659
        try:
 
660
            result = selftest(verbose=verbose,
 
661
                              pattern=pattern,
 
662
                              stop_on_failure=one,
 
663
                              test_suite_factory=test_suite_factory,
 
664
                              lsprof_timed=lsprof_timed,
 
665
                              bench_history=benchfile,
 
666
                              list_only=list_only,
 
667
                              random_seed=randomize,
 
668
                             )
 
669
        finally:
 
670
            if benchfile is not None:
 
671
                benchfile.close()
 
672
 
 
673
register_command(cmd_test_gtk)
 
674
 
 
675
 
 
676
class cmd_ghandle_patch(GTKCommand):
 
677
    """Display a patch or merge directive, possibly merging.
 
678
 
 
679
    This is a helper, meant to be launched from other programs like browsers
 
680
    or email clients.  Since these programs often do not allow parameters to
 
681
    be provided, a "handle-patch" script is included.
 
682
    """
 
683
 
 
684
    takes_args = ['path']
 
685
 
 
686
    def run(self, path):
 
687
        try:
 
688
            from bzrlib.plugins.gtk.diff import (DiffWindow,
 
689
                                                 MergeDirectiveWindow)
 
690
            lines = open(path, 'rb').readlines()
 
691
            lines = [l.replace('\r\n', '\n') for l in lines]
 
692
            try:
 
693
                directive = merge_directive.MergeDirective.from_lines(lines)
 
694
            except errors.NotAMergeDirective:
 
695
                window = DiffWindow()
 
696
                window.set_diff_text(path, lines)
 
697
            else:
 
698
                window = MergeDirectiveWindow(directive, path)
 
699
                window.set_diff_text(path, directive.patch.splitlines(True))
 
700
            window.show()
 
701
            gtk = self.open_display()
 
702
            window.connect("destroy", gtk.main_quit)
 
703
        except Exception, e:
 
704
            from dialog import error_dialog
 
705
            error_dialog('Error', str(e))
 
706
            raise
 
707
        gtk.main()
 
708
 
 
709
 
 
710
register_command(cmd_ghandle_patch)
 
711
 
 
712
 
 
713
import gettext
 
714
gettext.install('olive-gtk')
 
715
 
359
716
 
360
717
class NoDisplayError(BzrCommandError):
361
718
    """gtk could not find a proper display"""
363
720
    def __str__(self):
364
721
        return "No DISPLAY. Unable to run GTK+ application."
365
722
 
 
723
 
366
724
def test_suite():
367
725
    from unittest import TestSuite
368
726
    import tests
369
 
    result = TestSuite()
370
 
    result.addTest(tests.test_suite())
 
727
    import sys
 
728
    default_encoding = sys.getdefaultencoding()
 
729
    try:
 
730
        result = TestSuite()
 
731
        try:
 
732
            import_pygtk()
 
733
        except errors.BzrCommandError:
 
734
            return result
 
735
        result.addTest(tests.test_suite())
 
736
    finally:
 
737
        if sys.getdefaultencoding() != default_encoding:
 
738
            reload(sys)
 
739
            sys.setdefaultencoding(default_encoding)
371
740
    return result