/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: Vincent Ladeuil
  • Date: 2008-06-10 15:25:47 UTC
  • mto: This revision was merged to the branch mainline in revision 504.
  • Revision ID: v.ladeuil+lp@free.fr-20080610152547-dwmil1p8pd0mfpnl
Fix third failing test (thanks to jam).

* tests/test_commit.py:
(TestPendingRevisions.test_pending_revisions_multi_merge): Fix
provided by jam: bzr we now filter the pending merges so that only
the 'heads()' are included. We just ensure that the pending merges
contain the unique tips for the ancestries.

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.17.0'
20
 
version_info = tuple(int(n) for n in __version__.split('.'))
21
 
 
 
40
version_info = (0, 95, 0, 'dev', 1)
 
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, 3)
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':
60
76
lazy_import(globals(), """
61
77
from bzrlib import (
62
78
    branch,
 
79
    builtins,
63
80
    errors,
 
81
    merge_directive,
64
82
    workingtree,
65
83
    )
66
84
""")
87
105
    bzrlib.ui.ui_factory = GtkUIFactory()
88
106
 
89
107
 
 
108
def data_path():
 
109
    return os.path.dirname(__file__)
 
110
 
 
111
 
 
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
 
90
123
class GTKCommand(Command):
91
124
    """Abstract class providing GTK specific run commands."""
92
125
 
137
170
        (br, path) = branch.Branch.open_containing(location)
138
171
        self.open_display()
139
172
        from push import PushDialog
140
 
        dialog = PushDialog(br)
 
173
        dialog = PushDialog(br.repository, br.last_revision(), br)
141
174
        dialog.run()
142
175
 
143
176
 
160
193
            if revision is not None:
161
194
                if len(revision) == 1:
162
195
                    tree1 = wt
163
 
                    revision_id = revision[0].in_history(branch).rev_id
 
196
                    revision_id = revision[0].as_revision_id(tree1.branch)
164
197
                    tree2 = branch.repository.revision_tree(revision_id)
165
198
                elif len(revision) == 2:
166
 
                    revision_id_0 = revision[0].in_history(branch).rev_id
 
199
                    revision_id_0 = revision[0].as_revision_id(branch)
167
200
                    tree2 = branch.repository.revision_tree(revision_id_0)
168
 
                    revision_id_1 = revision[1].in_history(branch).rev_id
 
201
                    revision_id_1 = revision[1].as_revision_id(branch)
169
202
                    tree1 = branch.repository.revision_tree(revision_id_1)
170
203
            else:
171
204
                tree1 = wt
193
226
            wt.unlock()
194
227
 
195
228
 
 
229
def start_viz_window(branch, revisions, limit=None):
 
230
    """Start viz on branch with revision revision.
 
231
    
 
232
    :return: The viz window object.
 
233
    """
 
234
    from viz import BranchWindow
 
235
    return BranchWindow(branch, revisions, limit)
 
236
 
 
237
 
196
238
class cmd_visualise(Command):
197
239
    """Graphically visualise this branch.
198
240
 
204
246
    """
205
247
    takes_options = [
206
248
        "revision",
207
 
        Option('limit', "maximum number of revisions to display",
 
249
        Option('limit', "Maximum number of revisions to display.",
208
250
               int, 'count')]
209
 
    takes_args = [ "location?" ]
 
251
    takes_args = [ "locations*" ]
210
252
    aliases = [ "visualize", "vis", "viz" ]
211
253
 
212
 
    def run(self, location=".", revision=None, limit=None):
 
254
    def run(self, locations_list, revision=None, limit=None):
213
255
        set_ui_factory()
214
 
        (br, path) = branch.Branch.open_containing(location)
215
 
        br.lock_read()
216
 
        br.repository.lock_read()
217
 
        try:
 
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)
218
261
            if revision is None:
219
 
                revid = br.last_revision()
220
 
                if revid is None:
221
 
                    return
 
262
                revids.append(br.last_revision())
222
263
            else:
223
 
                (revno, revid) = revision[0].in_history(br)
224
 
 
225
 
            from viz.branchwin import BranchWindow
226
 
            import gtk
227
 
                
228
 
            pp = BranchWindow()
229
 
            pp.set_branch(br, revid, limit)
230
 
            pp.connect("destroy", lambda w: gtk.main_quit())
231
 
            pp.show()
232
 
            gtk.main()
233
 
        finally:
234
 
            br.repository.unlock()
235
 
            br.unlock()
 
264
                revids.append(revision[0].as_revision_id(br))
 
265
        import gtk
 
266
        pp = start_viz_window(br, revids, limit)
 
267
        pp.connect("destroy", lambda w: gtk.main_quit())
 
268
        pp.show()
 
269
        gtk.main()
236
270
 
237
271
 
238
272
class cmd_gannotate(GTKCommand):
243
277
 
244
278
    takes_args = ["filename", "line?"]
245
279
    takes_options = [
246
 
        Option("all", help="show annotations on all lines"),
247
 
        Option("plain", help="don't highlight annotation lines"),
 
280
        Option("all", help="Show annotations on all lines."),
 
281
        Option("plain", help="Don't highlight annotation lines."),
248
282
        Option("line", type=int, argname="lineno",
249
 
               help="jump to specified line number"),
 
283
               help="Jump to specified line number."),
250
284
        "revision",
251
285
    ]
252
286
    aliases = ["gblame", "gpraise"]
277
311
        if revision is not None:
278
312
            if len(revision) != 1:
279
313
                raise BzrCommandError("Only 1 revion may be specified.")
280
 
            revision_id = revision[0].in_history(br).rev_id
 
314
            revision_id = revision[0].as_revision_id(br)
281
315
            tree = br.repository.revision_tree(revision_id)
282
316
        else:
283
317
            revision_id = getattr(tree, 'get_revision_id', lambda: None)()
284
318
 
285
 
        window = GAnnotateWindow(all, plain)
 
319
        window = GAnnotateWindow(all, plain, branch=br)
286
320
        window.connect("destroy", lambda w: gtk.main_quit())
287
 
        window.set_title(path + " - gannotate")
288
321
        config = GAnnotateConfig(window)
289
322
        window.show()
290
323
        br.lock_read()
305
338
    """GTK+ commit dialog
306
339
 
307
340
    Graphical user interface for committing revisions"""
308
 
    
 
341
 
309
342
    aliases = [ "gci" ]
310
343
    takes_args = []
311
344
    takes_options = []
324
357
            (wt, path) = workingtree.WorkingTree.open_containing(filename)
325
358
            br = wt.branch
326
359
        except NoWorkingTree, e:
327
 
            path = e.base
328
 
            (br, path) = branch.Branch.open_containing(path)
329
 
 
330
 
        commit = CommitDialog(wt, path, not br)
331
 
        commit.run()
332
 
 
 
360
            from dialog import error_dialog
 
361
            error_dialog(_i18n('Directory does not have a working tree'),
 
362
                         _i18n('Operation aborted.'))
 
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()
333
375
 
334
376
 
335
377
class cmd_gstatus(GTKCommand):
340
382
    
341
383
    aliases = [ "gst" ]
342
384
    takes_args = ['PATH?']
343
 
    takes_options = []
 
385
    takes_options = ['revision']
344
386
 
345
 
    def run(self, path='.'):
 
387
    def run(self, path='.', revision=None):
346
388
        import os
347
389
        gtk = self.open_display()
348
390
        from status import StatusDialog
349
391
        (wt, wt_path) = workingtree.WorkingTree.open_containing(path)
350
 
        status = StatusDialog(wt, wt_path)
 
392
        
 
393
        if revision is not None:
 
394
            try:
 
395
                revision_id = revision[0].as_revision_id(wt.branch)
 
396
            except:
 
397
                from bzrlib.errors import BzrError
 
398
                raise BzrError('Revision %r doesn\'t exist' % revision[0].user_spec )
 
399
        else:
 
400
            revision_id = None
 
401
 
 
402
        status = StatusDialog(wt, wt_path, revision_id)
351
403
        status.connect("destroy", gtk.main_quit)
352
404
        status.run()
353
405
 
354
406
 
 
407
class cmd_gsend(GTKCommand):
 
408
    """GTK+ send merge directive.
 
409
 
 
410
    """
 
411
    def run(self):
 
412
        (br, path) = branch.Branch.open_containing(".")
 
413
        gtk = self.open_display()
 
414
        from bzrlib.plugins.gtk.mergedirective import SendMergeDirectiveDialog
 
415
        from StringIO import StringIO
 
416
        dialog = SendMergeDirectiveDialog(br)
 
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
            
 
425
 
355
426
 
356
427
class cmd_gconflicts(GTKCommand):
357
 
    """ GTK+ push.
 
428
    """GTK+ conflicts.
358
429
    
 
430
    Select files from the list of conflicts and run an external utility to
 
431
    resolve them.
359
432
    """
360
433
    def run(self):
361
434
        (wt, path) = workingtree.WorkingTree.open_containing('.')
365
438
        dialog.run()
366
439
 
367
440
 
368
 
 
369
441
class cmd_gpreferences(GTKCommand):
370
442
    """ GTK+ preferences dialog.
371
443
 
377
449
        dialog.run()
378
450
 
379
451
 
380
 
 
381
452
class cmd_gmissing(Command):
382
453
    """ GTK+ missing revisions dialog.
383
454
 
434
505
 
435
506
 
436
507
commands = [
 
508
    cmd_gannotate, 
 
509
    cmd_gbranch,
 
510
    cmd_gcheckout, 
 
511
    cmd_gcommit, 
 
512
    cmd_gconflicts, 
 
513
    cmd_gdiff,
 
514
    cmd_ginit,
437
515
    cmd_gmissing, 
438
516
    cmd_gpreferences, 
439
 
    cmd_gconflicts, 
 
517
    cmd_gpush, 
 
518
    cmd_gsend,
440
519
    cmd_gstatus,
441
 
    cmd_gcommit, 
442
 
    cmd_gannotate, 
443
 
    cmd_visualise, 
444
 
    cmd_gdiff,
445
 
    cmd_gpush, 
446
 
    cmd_gcheckout, 
447
 
    cmd_gbranch,
448
 
    cmd_ginit,
449
 
    cmd_gtags
 
520
    cmd_gtags,
 
521
    cmd_visualise
450
522
    ]
451
523
 
452
524
for cmd in commands:
461
533
    """
462
534
 
463
535
    def run(self):
 
536
        from notify import NotifyPopupMenu
464
537
        gtk = self.open_display()
 
538
        menu = NotifyPopupMenu()
 
539
        icon = gtk.status_icon_new_from_file(icon_path("bzr-icon-64.png"))
 
540
        icon.connect('popup-menu', menu.display)
 
541
 
465
542
        import cgi
466
543
        import dbus
467
544
        import dbus.service
472
549
        from bzrlib.transport import get_transport
473
550
        if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
474
551
            import dbus.glib
475
 
        from bzrlib.plugins.dbus import activity
 
552
        BROADCAST_INTERFACE = "org.bazaarvcs.plugins.dbus.Broadcast"
476
553
        bus = dbus.SessionBus()
477
 
        # get the object so we can subscribe to callbacks from it.
478
 
        broadcast_service = bus.get_object(
479
 
            activity.Broadcast.DBUS_NAME,
480
 
            activity.Broadcast.DBUS_PATH)
 
554
 
481
555
        def catch_branch(revision_id, urls):
482
556
            # TODO: show all the urls, or perhaps choose the 'best'.
483
557
            url = urls[0]
497
571
                body += revision.message
498
572
                body = cgi.escape(body)
499
573
                nw = pynotify.Notification(summary, body)
 
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()
 
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()
 
583
                nw.add_action("inspect", "Inspect", start_viz, None)
 
584
                nw.add_action("branch", "Branch", start_branch, None)
500
585
                nw.set_timeout(5000)
501
586
                nw.show()
502
587
            except Exception, e:
503
588
                print e
504
589
                raise
505
 
        broadcast_service.connect_to_signal("Revision", catch_branch,
506
 
            dbus_interface=activity.Broadcast.DBUS_INTERFACE)
 
590
        bus.add_signal_receiver(catch_branch,
 
591
                                dbus_interface=BROADCAST_INTERFACE,
 
592
                                signal_name="Revision")
507
593
        pynotify.init("bzr commit-notify")
508
594
        gtk.main()
509
595
 
510
596
register_command(cmd_commit_notify)
511
597
 
512
598
 
 
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
 
608
        import sys
 
609
        default_encoding = sys.getdefaultencoding()
 
610
        # prevent gtk from blowing up later
 
611
        gtk = import_pygtk()
 
612
        # prevent gtk from messing with default encoding
 
613
        import pynotify
 
614
        if sys.getdefaultencoding() != default_encoding:
 
615
            reload(sys)
 
616
            sys.setdefaultencoding(default_encoding)
 
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
 
 
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',
 
638
                            help='Stop when one test fails.'),
 
639
                     Option('benchmark', help='Run the benchmarks.'),
 
640
                     Option('lsprof-timed',
 
641
                     help='Generate lsprof output for benchmarked'
 
642
                          ' sections of code.'),
 
643
                     Option('list-only',
 
644
                     help='List the tests instead of running them.'),
 
645
                     Option('randomize', type=str, argname="SEED",
 
646
                     help='Randomize the order of tests using the given'
 
647
                          ' seed or "now" for the current time.'),
 
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
 
 
695
class cmd_ghandle_patch(GTKCommand):
 
696
    """Display a patch or merge directive, possibly merging.
 
697
 
 
698
    This is a helper, meant to be launched from other programs like browsers
 
699
    or email clients.  Since these programs often do not allow parameters to
 
700
    be provided, a "handle-patch" script is included.
 
701
    """
 
702
 
 
703
    takes_args = ['path']
 
704
 
 
705
    def run(self, path):
 
706
        try:
 
707
            from bzrlib.plugins.gtk.diff import (DiffController,
 
708
                                                 MergeDirectiveController)
 
709
            if path == '-':
 
710
                lines = sys.stdin.readlines()
 
711
            else:
 
712
                lines = open(path, 'rb').readlines()
 
713
            lines = [l.replace('\r\n', '\n') for l in lines]
 
714
            try:
 
715
                directive = merge_directive.MergeDirective.from_lines(lines)
 
716
            except errors.NotAMergeDirective:
 
717
                controller = DiffController(path, lines)
 
718
            else:
 
719
                controller = MergeDirectiveController(path, directive)
 
720
            window = controller.window
 
721
            window.show()
 
722
            gtk = self.open_display()
 
723
            window.connect("destroy", gtk.main_quit)
 
724
        except Exception, e:
 
725
            from dialog import error_dialog
 
726
            error_dialog('Error', str(e))
 
727
            raise
 
728
        gtk.main()
 
729
 
 
730
 
 
731
register_command(cmd_ghandle_patch)
 
732
 
 
733
 
513
734
import gettext
514
735
gettext.install('olive-gtk')
515
736
 
 
737
# Let's create a specialized alias to protect '_' from being erased by other
 
738
# uses of '_' as an anonymous variable (think pdb for one).
 
739
_i18n = gettext.gettext
516
740
 
517
741
class NoDisplayError(BzrCommandError):
518
742
    """gtk could not find a proper display"""
528
752
    default_encoding = sys.getdefaultencoding()
529
753
    try:
530
754
        result = TestSuite()
 
755
        try:
 
756
            import_pygtk()
 
757
        except errors.BzrCommandError:
 
758
            return result
531
759
        result.addTest(tests.test_suite())
532
760
    finally:
533
761
        if sys.getdefaultencoding() != default_encoding: