/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-05-04 18:16:01 UTC
  • Revision ID: jelmer@samba.org-20080504181601-u5gh89q8l2we201l
Fix display of children in branchview.

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, 'rc', 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':
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
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
 
 
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()
 
134
        return gtk
 
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):
87
143
    """GTK+ branching.
88
144
    
89
145
    """
90
146
 
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
 
 
 
147
    def get_gtk_dialog(self, path):
99
148
        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):
 
149
        return BranchDialog(path)
 
150
 
 
151
 
 
152
class cmd_gcheckout(GTKCommand):
108
153
    """ GTK+ checkout.
109
154
    
110
155
    """
111
156
    
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
 
 
 
157
    def get_gtk_dialog(self, path):
120
158
        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):
 
159
        return CheckoutDialog(path)
 
160
 
 
161
 
 
162
 
 
163
class cmd_gpush(GTKCommand):
129
164
    """ GTK+ push.
130
165
    
131
166
    """
132
167
    takes_args = [ "location?" ]
133
 
    
 
168
 
134
169
    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
 
 
 
170
        (br, path) = branch.Branch.open_containing(location)
 
171
        self.open_display()
144
172
        from push import PushDialog
145
 
 
146
 
        set_ui_factory()
147
 
        dialog = PushDialog(branch)
 
173
        dialog = PushDialog(br.repository, br.last_revision(), br)
148
174
        dialog.run()
149
175
 
150
 
register_command(cmd_gpush)
151
 
 
152
 
class cmd_gdiff(Command):
 
176
 
 
177
 
 
178
class cmd_gdiff(GTKCommand):
153
179
    """Show differences in working tree in a GTK+ Window.
154
180
    
155
181
    Otherwise, all changes for the tree are listed.
160
186
    @display_command
161
187
    def run(self, revision=None, filename=None):
162
188
        set_ui_factory()
163
 
        wt = WorkingTree.open_containing(".")[0]
164
 
        branch = wt.branch
165
 
        if revision is not None:
166
 
            if len(revision) == 1:
 
189
        wt = workingtree.WorkingTree.open_containing(".")[0]
 
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:
167
204
                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 diff import DiffWindow
180
 
        import gtk
181
 
        window = DiffWindow()
182
 
        window.connect("destroy", 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)
 
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:
 
217
                    if (tree1.path2id(tree_filename) is None and 
 
218
                        tree2.path2id(tree_filename) is None):
 
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()
 
227
 
 
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
 
199
237
 
200
238
class cmd_visualise(Command):
201
239
    """Graphically visualise this branch.
208
246
    """
209
247
    takes_options = [
210
248
        "revision",
211
 
        Option('limit', "maximum number of revisions to display",
 
249
        Option('limit', "Maximum number of revisions to display.",
212
250
               int, 'count')]
213
 
    takes_args = [ "location?" ]
 
251
    takes_args = [ "locations*" ]
214
252
    aliases = [ "visualize", "vis", "viz" ]
215
253
 
216
 
    def run(self, location=".", revision=None, limit=None):
 
254
    def run(self, locations_list, revision=None, limit=None):
217
255
        set_ui_factory()
218
 
        (branch, path) = Branch.open_containing(location)
219
 
        branch.lock_read()
220
 
        branch.repository.lock_read()
221
 
        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)
222
261
            if revision is None:
223
 
                revid = branch.last_revision()
224
 
                if revid is None:
225
 
                    return
 
262
                revids.append(br.last_revision())
226
263
            else:
227
 
                (revno, revid) = revision[0].in_history(branch)
228
 
 
229
 
            from viz.branchwin import BranchWindow
230
 
            import gtk
231
 
                
232
 
            pp = BranchWindow()
233
 
            pp.set_branch(branch, revid, limit)
234
 
            pp.connect("destroy", lambda w: gtk.main_quit())
235
 
            pp.show()
236
 
            gtk.main()
237
 
        finally:
238
 
            branch.repository.unlock()
239
 
            branch.unlock()
240
 
 
241
 
 
242
 
register_command(cmd_visualise)
243
 
 
244
 
class cmd_gannotate(Command):
 
264
                (revno, revid) = revision[0].in_history(br)
 
265
                revids.append(revid)
 
266
        import gtk
 
267
        pp = start_viz_window(br, revids, limit)
 
268
        pp.connect("destroy", lambda w: gtk.main_quit())
 
269
        pp.show()
 
270
        gtk.main()
 
271
 
 
272
 
 
273
class cmd_gannotate(GTKCommand):
245
274
    """GTK+ annotate.
246
275
    
247
276
    Browse changes to FILENAME line by line in a GTK+ window.
249
278
 
250
279
    takes_args = ["filename", "line?"]
251
280
    takes_options = [
252
 
        Option("all", help="show annotations on all lines"),
253
 
        Option("plain", help="don't highlight annotation lines"),
 
281
        Option("all", help="Show annotations on all lines."),
 
282
        Option("plain", help="Don't highlight annotation lines."),
254
283
        Option("line", type=int, argname="lineno",
255
 
               help="jump to specified line number"),
 
284
               help="Jump to specified line number."),
256
285
        "revision",
257
286
    ]
258
287
    aliases = ["gblame", "gpraise"]
259
288
    
260
289
    def run(self, filename, all=False, plain=False, line='1', revision=None):
261
 
        pygtk = import_pygtk()
262
 
 
263
 
        try:
264
 
            import gtk
265
 
        except RuntimeError, e:
266
 
            if str(e) == "could not open display":
267
 
                raise NoDisplayError
268
 
        set_ui_factory()
 
290
        gtk = self.open_display()
269
291
 
270
292
        try:
271
293
            line = int(line)
275
297
 
276
298
        from annotate.gannotate import GAnnotateWindow
277
299
        from annotate.config import GAnnotateConfig
 
300
        from bzrlib.bzrdir import BzrDir
278
301
 
279
 
        try:
280
 
            (tree, path) = WorkingTree.open_containing(filename)
281
 
            branch = tree.branch
282
 
        except errors.NoWorkingTree:
283
 
            (branch, path) = Branch.open_containing(filename)
284
 
            tree = branch.basis_tree()
 
302
        wt, br, path = BzrDir.open_containing_tree_or_branch(filename)
 
303
        if wt is not None:
 
304
            tree = wt
 
305
        else:
 
306
            tree = br.basis_tree()
285
307
 
286
308
        file_id = tree.path2id(path)
287
309
 
290
312
        if revision is not None:
291
313
            if len(revision) != 1:
292
314
                raise BzrCommandError("Only 1 revion may be specified.")
293
 
            revision_id = revision[0].in_history(branch).rev_id
294
 
            tree = branch.repository.revision_tree(revision_id)
 
315
            revision_id = revision[0].in_history(br).rev_id
 
316
            tree = br.repository.revision_tree(revision_id)
295
317
        else:
296
318
            revision_id = getattr(tree, 'get_revision_id', lambda: None)()
297
319
 
298
 
        window = GAnnotateWindow(all, plain)
 
320
        window = GAnnotateWindow(all, plain, branch=br)
299
321
        window.connect("destroy", lambda w: gtk.main_quit())
300
 
        window.set_title(path + " - gannotate")
301
322
        config = GAnnotateConfig(window)
302
323
        window.show()
303
 
        branch.lock_read()
 
324
        br.lock_read()
 
325
        if wt is not None:
 
326
            wt.lock_read()
304
327
        try:
305
 
            window.annotate(tree, branch, file_id)
 
328
            window.annotate(tree, br, file_id)
 
329
            window.jump_to_line(line)
 
330
            gtk.main()
306
331
        finally:
307
 
            branch.unlock()
308
 
        window.jump_to_line(line)
309
 
        
310
 
        gtk.main()
311
 
 
312
 
register_command(cmd_gannotate)
313
 
 
314
 
class cmd_gcommit(Command):
 
332
            br.unlock()
 
333
            if wt is not None:
 
334
                wt.unlock()
 
335
 
 
336
 
 
337
 
 
338
class cmd_gcommit(GTKCommand):
315
339
    """GTK+ commit dialog
316
340
 
317
341
    Graphical user interface for committing revisions"""
318
 
    
 
342
 
319
343
    aliases = [ "gci" ]
320
344
    takes_args = []
321
345
    takes_options = []
322
346
 
323
347
    def run(self, filename=None):
324
348
        import os
325
 
        pygtk = import_pygtk()
326
 
 
327
 
        try:
328
 
            import gtk
329
 
        except RuntimeError, e:
330
 
            if str(e) == "could not open display":
331
 
                raise NoDisplayError
332
 
 
333
 
        set_ui_factory()
 
349
        self.open_display()
334
350
        from commit import CommitDialog
335
 
        from bzrlib.commit import Commit
336
351
        from bzrlib.errors import (BzrCommandError,
337
352
                                   NotBranchError,
338
 
                                   NoWorkingTree,
339
 
                                   PointlessCommit,
340
 
                                   ConflictsInTree,
341
 
                                   StrictCommitFailed)
 
353
                                   NoWorkingTree)
342
354
 
343
355
        wt = None
344
 
        branch = None
 
356
        br = None
345
357
        try:
346
 
            (wt, path) = WorkingTree.open_containing(filename)
347
 
            branch = wt.branch
348
 
        except NotBranchError, e:
349
 
            path = e.path
 
358
            (wt, path) = workingtree.WorkingTree.open_containing(filename)
 
359
            br = wt.branch
350
360
        except NoWorkingTree, e:
351
 
            path = e.base
352
 
            try:
353
 
                (branch, path) = Branch.open_containing(path)
354
 
            except NotBranchError, e:
355
 
                path = e.path
356
 
 
357
 
 
358
 
        commit = CommitDialog(wt, path, not branch)
359
 
        commit.run()
360
 
 
361
 
register_command(cmd_gcommit)
 
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()
 
376
 
 
377
 
 
378
class cmd_gstatus(GTKCommand):
 
379
    """GTK+ status dialog
 
380
 
 
381
    Graphical user interface for showing status 
 
382
    information."""
 
383
    
 
384
    aliases = [ "gst" ]
 
385
    takes_args = ['PATH?']
 
386
    takes_options = ['revision']
 
387
 
 
388
    def run(self, path='.', revision=None):
 
389
        import os
 
390
        gtk = self.open_display()
 
391
        from status import StatusDialog
 
392
        (wt, wt_path) = workingtree.WorkingTree.open_containing(path)
 
393
        
 
394
        if revision is not None:
 
395
            try:
 
396
                revision_id = revision[0].in_history(wt.branch).rev_id
 
397
            except:
 
398
                from bzrlib.errors import BzrError
 
399
                raise BzrError('Revision %r doesn\'t exist' % revision[0].user_spec )
 
400
        else:
 
401
            revision_id = None
 
402
 
 
403
        status = StatusDialog(wt, wt_path, revision_id)
 
404
        status.connect("destroy", gtk.main_quit)
 
405
        status.run()
 
406
 
 
407
 
 
408
class cmd_gsend(GTKCommand):
 
409
    """GTK+ send merge directive.
 
410
 
 
411
    """
 
412
    def run(self):
 
413
        (br, path) = branch.Branch.open_containing(".")
 
414
        gtk = self.open_display()
 
415
        from bzrlib.plugins.gtk.mergedirective import SendMergeDirectiveDialog
 
416
        from StringIO import StringIO
 
417
        dialog = SendMergeDirectiveDialog(br)
 
418
        if dialog.run() == gtk.RESPONSE_OK:
 
419
            outf = StringIO()
 
420
            outf.writelines(dialog.get_merge_directive().to_lines())
 
421
            mail_client = br.get_config().get_mail_client()
 
422
            mail_client.compose_merge_request(dialog.get_mail_to(), "[MERGE]", 
 
423
                outf.getvalue())
 
424
 
 
425
            
 
426
 
 
427
 
 
428
class cmd_gconflicts(GTKCommand):
 
429
    """GTK+ conflicts.
 
430
    
 
431
    Select files from the list of conflicts and run an external utility to
 
432
    resolve them.
 
433
    """
 
434
    def run(self):
 
435
        (wt, path) = workingtree.WorkingTree.open_containing('.')
 
436
        self.open_display()
 
437
        from bzrlib.plugins.gtk.conflicts import ConflictsDialog
 
438
        dialog = ConflictsDialog(wt)
 
439
        dialog.run()
 
440
 
 
441
 
 
442
class cmd_gpreferences(GTKCommand):
 
443
    """ GTK+ preferences dialog.
 
444
 
 
445
    """
 
446
    def run(self):
 
447
        self.open_display()
 
448
        from bzrlib.plugins.gtk.preferences import PreferencesWindow
 
449
        dialog = PreferencesWindow()
 
450
        dialog.run()
 
451
 
 
452
 
 
453
class cmd_gmissing(Command):
 
454
    """ GTK+ missing revisions dialog.
 
455
 
 
456
    """
 
457
    takes_args = ["other_branch?"]
 
458
    def run(self, other_branch=None):
 
459
        pygtk = import_pygtk()
 
460
        try:
 
461
            import gtk
 
462
        except RuntimeError, e:
 
463
            if str(e) == "could not open display":
 
464
                raise NoDisplayError
 
465
 
 
466
        from bzrlib.plugins.gtk.missing import MissingWindow
 
467
        from bzrlib.branch import Branch
 
468
 
 
469
        local_branch = Branch.open_containing(".")[0]
 
470
        if other_branch is None:
 
471
            other_branch = local_branch.get_parent()
 
472
            
 
473
            if other_branch is None:
 
474
                raise errors.BzrCommandError("No peer location known or specified.")
 
475
        remote_branch = Branch.open_containing(other_branch)[0]
 
476
        set_ui_factory()
 
477
        local_branch.lock_read()
 
478
        try:
 
479
            remote_branch.lock_read()
 
480
            try:
 
481
                dialog = MissingWindow(local_branch, remote_branch)
 
482
                dialog.run()
 
483
            finally:
 
484
                remote_branch.unlock()
 
485
        finally:
 
486
            local_branch.unlock()
 
487
 
 
488
 
 
489
class cmd_ginit(GTKCommand):
 
490
    def run(self):
 
491
        self.open_display()
 
492
        from initialize import InitDialog
 
493
        dialog = InitDialog(os.path.abspath(os.path.curdir))
 
494
        dialog.run()
 
495
 
 
496
 
 
497
class cmd_gtags(GTKCommand):
 
498
    def run(self):
 
499
        br = branch.Branch.open_containing('.')[0]
 
500
        
 
501
        gtk = self.open_display()
 
502
        from tags import TagsWindow
 
503
        window = TagsWindow(br)
 
504
        window.show()
 
505
        gtk.main()
 
506
 
 
507
 
 
508
commands = [
 
509
    cmd_gannotate, 
 
510
    cmd_gbranch,
 
511
    cmd_gcheckout, 
 
512
    cmd_gcommit, 
 
513
    cmd_gconflicts, 
 
514
    cmd_gdiff,
 
515
    cmd_ginit,
 
516
    cmd_gmissing, 
 
517
    cmd_gpreferences, 
 
518
    cmd_gpush, 
 
519
    cmd_gsend,
 
520
    cmd_gstatus,
 
521
    cmd_gtags,
 
522
    cmd_visualise
 
523
    ]
 
524
 
 
525
for cmd in commands:
 
526
    register_command(cmd)
 
527
 
 
528
 
 
529
class cmd_commit_notify(GTKCommand):
 
530
    """Run the bzr commit notifier.
 
531
 
 
532
    This is a background program which will pop up a notification on the users
 
533
    screen when a commit occurs.
 
534
    """
 
535
 
 
536
    def run(self):
 
537
        from notify import NotifyPopupMenu
 
538
        gtk = self.open_display()
 
539
        menu = NotifyPopupMenu()
 
540
        icon = gtk.status_icon_new_from_file(icon_path("bzr-icon-64.png"))
 
541
        icon.connect('popup-menu', menu.display)
 
542
 
 
543
        import cgi
 
544
        import dbus
 
545
        import dbus.service
 
546
        import pynotify
 
547
        from bzrlib.bzrdir import BzrDir
 
548
        from bzrlib import errors
 
549
        from bzrlib.osutils import format_date
 
550
        from bzrlib.transport import get_transport
 
551
        if getattr(dbus, 'version', (0,0,0)) >= (0,41,0):
 
552
            import dbus.glib
 
553
        BROADCAST_INTERFACE = "org.bazaarvcs.plugins.dbus.Broadcast"
 
554
        bus = dbus.SessionBus()
 
555
 
 
556
        def catch_branch(revision_id, urls):
 
557
            # TODO: show all the urls, or perhaps choose the 'best'.
 
558
            url = urls[0]
 
559
            try:
 
560
                if isinstance(revision_id, unicode):
 
561
                    revision_id = revision_id.encode('utf8')
 
562
                transport = get_transport(url)
 
563
                a_dir = BzrDir.open_from_transport(transport)
 
564
                branch = a_dir.open_branch()
 
565
                revno = branch.revision_id_to_revno(revision_id)
 
566
                revision = branch.repository.get_revision(revision_id)
 
567
                summary = 'New revision %d in %s' % (revno, url)
 
568
                body  = 'Committer: %s\n' % revision.committer
 
569
                body += 'Date: %s\n' % format_date(revision.timestamp,
 
570
                    revision.timezone)
 
571
                body += '\n'
 
572
                body += revision.message
 
573
                body = cgi.escape(body)
 
574
                nw = pynotify.Notification(summary, body)
 
575
                def start_viz(notification=None, action=None, data=None):
 
576
                    """Start the viz program."""
 
577
                    pp = start_viz_window(branch, revision_id)
 
578
                    pp.show()
 
579
                def start_branch(notification=None, action=None, data=None):
 
580
                    """Start a Branch dialog"""
 
581
                    from bzrlib.plugins.gtk.branch import BranchDialog
 
582
                    bd = BranchDialog(remote_path=url)
 
583
                    bd.run()
 
584
                nw.add_action("inspect", "Inspect", start_viz, None)
 
585
                nw.add_action("branch", "Branch", start_branch, None)
 
586
                nw.set_timeout(5000)
 
587
                nw.show()
 
588
            except Exception, e:
 
589
                print e
 
590
                raise
 
591
        bus.add_signal_receiver(catch_branch,
 
592
                                dbus_interface=BROADCAST_INTERFACE,
 
593
                                signal_name="Revision")
 
594
        pynotify.init("bzr commit-notify")
 
595
        gtk.main()
 
596
 
 
597
register_command(cmd_commit_notify)
 
598
 
 
599
 
 
600
class cmd_gselftest(GTKCommand):
 
601
    """Version of selftest that displays a notification at the end"""
 
602
 
 
603
    takes_args = builtins.cmd_selftest.takes_args
 
604
    takes_options = builtins.cmd_selftest.takes_options
 
605
    _see_also = ['selftest']
 
606
 
 
607
    def run(self, *args, **kwargs):
 
608
        import cgi
 
609
        import sys
 
610
        default_encoding = sys.getdefaultencoding()
 
611
        # prevent gtk from blowing up later
 
612
        gtk = import_pygtk()
 
613
        # prevent gtk from messing with default encoding
 
614
        import pynotify
 
615
        if sys.getdefaultencoding() != default_encoding:
 
616
            reload(sys)
 
617
            sys.setdefaultencoding(default_encoding)
 
618
        result = builtins.cmd_selftest().run(*args, **kwargs)
 
619
        if result == 0:
 
620
            summary = 'Success'
 
621
            body = 'Selftest succeeded in "%s"' % os.getcwd()
 
622
        if result == 1:
 
623
            summary = 'Failure'
 
624
            body = 'Selftest failed in "%s"' % os.getcwd()
 
625
        pynotify.init("bzr gselftest")
 
626
        note = pynotify.Notification(cgi.escape(summary), cgi.escape(body))
 
627
        note.set_timeout(pynotify.EXPIRES_NEVER)
 
628
        note.show()
 
629
 
 
630
 
 
631
register_command(cmd_gselftest)
 
632
 
 
633
 
 
634
class cmd_test_gtk(GTKCommand):
 
635
    """Version of selftest that just runs the gtk test suite."""
 
636
 
 
637
    takes_options = ['verbose',
 
638
                     Option('one', short_name='1',
 
639
                            help='Stop when one test fails.'),
 
640
                     Option('benchmark', help='Run the benchmarks.'),
 
641
                     Option('lsprof-timed',
 
642
                     help='Generate lsprof output for benchmarked'
 
643
                          ' sections of code.'),
 
644
                     Option('list-only',
 
645
                     help='List the tests instead of running them.'),
 
646
                     Option('randomize', type=str, argname="SEED",
 
647
                     help='Randomize the order of tests using the given'
 
648
                          ' seed or "now" for the current time.'),
 
649
                    ]
 
650
    takes_args = ['testspecs*']
 
651
 
 
652
    def run(self, verbose=None, one=False, benchmark=None,
 
653
            lsprof_timed=None, list_only=False, randomize=None,
 
654
            testspecs_list=None):
 
655
        from bzrlib import __path__ as bzrlib_path
 
656
        from bzrlib.tests import selftest
 
657
 
 
658
        print '%10s: %s' % ('bzrlib', bzrlib_path[0])
 
659
        if benchmark:
 
660
            print 'No benchmarks yet'
 
661
            return 3
 
662
 
 
663
            test_suite_factory = bench_suite
 
664
            if verbose is None:
 
665
                verbose = True
 
666
            # TODO: should possibly lock the history file...
 
667
            benchfile = open(".perf_history", "at", buffering=1)
 
668
        else:
 
669
            test_suite_factory = test_suite
 
670
            if verbose is None:
 
671
                verbose = False
 
672
            benchfile = None
 
673
 
 
674
        if testspecs_list is not None:
 
675
            pattern = '|'.join(testspecs_list)
 
676
        else:
 
677
            pattern = ".*"
 
678
 
 
679
        try:
 
680
            result = selftest(verbose=verbose,
 
681
                              pattern=pattern,
 
682
                              stop_on_failure=one,
 
683
                              test_suite_factory=test_suite_factory,
 
684
                              lsprof_timed=lsprof_timed,
 
685
                              bench_history=benchfile,
 
686
                              list_only=list_only,
 
687
                              random_seed=randomize,
 
688
                             )
 
689
        finally:
 
690
            if benchfile is not None:
 
691
                benchfile.close()
 
692
 
 
693
register_command(cmd_test_gtk)
 
694
 
 
695
 
 
696
class cmd_ghandle_patch(GTKCommand):
 
697
    """Display a patch or merge directive, possibly merging.
 
698
 
 
699
    This is a helper, meant to be launched from other programs like browsers
 
700
    or email clients.  Since these programs often do not allow parameters to
 
701
    be provided, a "handle-patch" script is included.
 
702
    """
 
703
 
 
704
    takes_args = ['path']
 
705
 
 
706
    def run(self, path):
 
707
        try:
 
708
            from bzrlib.plugins.gtk.diff import (DiffWindow,
 
709
                                                 MergeDirectiveWindow)
 
710
            lines = open(path, 'rb').readlines()
 
711
            lines = [l.replace('\r\n', '\n') for l in lines]
 
712
            try:
 
713
                directive = merge_directive.MergeDirective.from_lines(lines)
 
714
            except errors.NotAMergeDirective:
 
715
                window = DiffWindow()
 
716
                window.set_diff_text(path, lines)
 
717
            else:
 
718
                window = MergeDirectiveWindow(directive, path)
 
719
                window.set_diff_text(path, directive.patch.splitlines(True))
 
720
            window.show()
 
721
            gtk = self.open_display()
 
722
            window.connect("destroy", gtk.main_quit)
 
723
        except Exception, e:
 
724
            from dialog import error_dialog
 
725
            error_dialog('Error', str(e))
 
726
            raise
 
727
        gtk.main()
 
728
 
 
729
 
 
730
register_command(cmd_ghandle_patch)
 
731
 
362
732
 
363
733
import gettext
364
734
gettext.install('olive-gtk')
365
735
 
 
736
 
366
737
class NoDisplayError(BzrCommandError):
367
738
    """gtk could not find a proper display"""
368
739
 
369
740
    def __str__(self):
370
741
        return "No DISPLAY. Unable to run GTK+ application."
371
742
 
 
743
 
372
744
def test_suite():
373
745
    from unittest import TestSuite
374
746
    import tests
375
 
    result = TestSuite()
376
 
    result.addTest(tests.test_suite())
 
747
    import sys
 
748
    default_encoding = sys.getdefaultencoding()
 
749
    try:
 
750
        result = TestSuite()
 
751
        try:
 
752
            import_pygtk()
 
753
        except errors.BzrCommandError:
 
754
            return result
 
755
        result.addTest(tests.test_suite())
 
756
    finally:
 
757
        if sys.getdefaultencoding() != default_encoding:
 
758
            reload(sys)
 
759
            sys.setdefaultencoding(default_encoding)
377
760
    return result