/b-gtk/fix-viz

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