/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
487 by Jelmer Vernooij
Start working on 0.95.0.
40
version_info = (0, 95, 0, 'dev', 1)
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
473.1.1 by Andrew Bennetts
Simple hack to fix gannotate.
320
        window = GAnnotateWindow(all, plain, branch=br)
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
321
        window.connect("destroy", lambda w: gtk.main_quit())
322
        config = GAnnotateConfig(window)
323
        window.show()
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
324
        br.lock_read()
161 by Aaron Bentley
Fix gannotate interaction with dirstate
325
        if wt is not None:
326
            wt.lock_read()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
327
        try:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
328
            window.annotate(tree, br, file_id)
161 by Aaron Bentley
Fix gannotate interaction with dirstate
329
            window.jump_to_line(line)
330
            gtk.main()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
331
        finally:
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
332
            br.unlock()
161 by Aaron Bentley
Fix gannotate interaction with dirstate
333
            if wt is not None:
334
                wt.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
335
336
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
337
338
class cmd_gcommit(GTKCommand):
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
339
    """GTK+ commit dialog
340
341
    Graphical user interface for committing revisions"""
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
342
145 by Jelmer Vernooij
Fix some strings, import.
343
    aliases = [ "gci" ]
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
344
    takes_args = []
345
    takes_options = []
346
347
    def run(self, filename=None):
93.1.17 by Alexander Belchenko
gcommit reworked again.
348
        import os
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
349
        self.open_display()
142 by Jelmer Vernooij
Move some files to the top-level directory, add first test.
350
        from commit import CommitDialog
93.1.17 by Alexander Belchenko
gcommit reworked again.
351
        from bzrlib.errors import (BzrCommandError,
352
                                   NotBranchError,
178 by Jelmer Vernooij
Remove unneeded imports.
353
                                   NoWorkingTree)
93.1.17 by Alexander Belchenko
gcommit reworked again.
354
355
        wt = None
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
356
        br = None
93.1.17 by Alexander Belchenko
gcommit reworked again.
357
        try:
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
358
            (wt, path) = workingtree.WorkingTree.open_containing(filename)
157.2.1 by Vincent Ladeuil
Rename variable 'branch' to 'br' where it conflicts with 'branch' module
359
            br = wt.branch
93.1.17 by Alexander Belchenko
gcommit reworked again.
360
        except NoWorkingTree, e:
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
361
            from dialog import error_dialog
362
            error_dialog(_('Directory does not have a working tree'),
363
                         _('Operation aborted.'))
364
            return 1 # should this be retval=3?
365
366
        # It is a good habit to keep things locked for the duration, but it
367
        # could cause difficulties if someone wants to do things in another
368
        # window... We could lock_read() until we actually go to commit
369
        # changes... Just a thought.
370
        wt.lock_write()
371
        try:
372
            dlg = CommitDialog(wt)
373
            return dlg.run()
374
        finally:
375
            wt.unlock()
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
376
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
377
250 by Aaron Bentley
oops- revert status change
378
class cmd_gstatus(GTKCommand):
157 by Jelmer Vernooij
Add gstatus command.
379
    """GTK+ status dialog
380
381
    Graphical user interface for showing status 
382
    information."""
383
    
384
    aliases = [ "gst" ]
385
    takes_args = ['PATH?']
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
386
    takes_options = ['revision']
157 by Jelmer Vernooij
Add gstatus command.
387
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
388
    def run(self, path='.', revision=None):
157 by Jelmer Vernooij
Add gstatus command.
389
        import os
184 by Jelmer Vernooij
Fix gstatus
390
        gtk = self.open_display()
157 by Jelmer Vernooij
Add gstatus command.
391
        from status import StatusDialog
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
392
        (wt, wt_path) = workingtree.WorkingTree.open_containing(path)
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
393
        
394
        if revision is not None:
463.1.2 by Javier Derderian
Added 'Revision # doesn't exist' message
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 )
463.1.1 by Javier Derderian
Added revision option to gstatus. Bug #136530
400
        else:
401
            revision_id = None
402
403
        status = StatusDialog(wt, wt_path, revision_id)
157 by Jelmer Vernooij
Add gstatus command.
404
        status.connect("destroy", gtk.main_quit)
405
        status.run()
406
407
323 by Jelmer Vernooij
Add gsend command.
408
class cmd_gsend(GTKCommand):
409
    """GTK+ send merge directive.
410
411
    """
412
    def run(self):
413
        (br, path) = branch.Branch.open_containing(".")
324 by Jelmer Vernooij
Add very simple "Send Merge Directive" window.
414
        gtk = self.open_display()
323 by Jelmer Vernooij
Add gsend command.
415
        from bzrlib.plugins.gtk.mergedirective import SendMergeDirectiveDialog
324 by Jelmer Vernooij
Add very simple "Send Merge Directive" window.
416
        from StringIO import StringIO
323 by Jelmer Vernooij
Add gsend command.
417
        dialog = SendMergeDirectiveDialog(br)
324 by Jelmer Vernooij
Add very simple "Send Merge Directive" window.
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
            
323 by Jelmer Vernooij
Add gsend command.
426
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
427
428
class cmd_gconflicts(GTKCommand):
323 by Jelmer Vernooij
Add gsend command.
429
    """GTK+ conflicts.
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
430
    
242.1.2 by Adeodato Simó
Fix gconflicts docstring.
431
    Select files from the list of conflicts and run an external utility to
432
    resolve them.
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
433
    """
434
    def run(self):
157.1.5 by Aaron Bentley
Use lazy_import to reduce rocks time by .015s
435
        (wt, path) = workingtree.WorkingTree.open_containing('.')
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
436
        self.open_display()
126.1.24 by Szilveszter Farkas (Phanatic)
Implemented Conflicts dialog. Added gconflicts command.
437
        from bzrlib.plugins.gtk.conflicts import ConflictsDialog
438
        dialog = ConflictsDialog(wt)
439
        dialog.run()
440
157 by Jelmer Vernooij
Add gstatus command.
441
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
442
class cmd_gpreferences(GTKCommand):
171 by Jelmer Vernooij
Initial work on a preferences dialog in GTK+, including a list of plugins with metadata browser.
443
    """ GTK+ preferences dialog.
444
445
    """
446
    def run(self):
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
447
        self.open_display()
171 by Jelmer Vernooij
Initial work on a preferences dialog in GTK+, including a list of plugins with metadata browser.
448
        from bzrlib.plugins.gtk.preferences import PreferencesWindow
449
        dialog = PreferencesWindow()
450
        dialog.run()
451
452
175 by Jelmer Vernooij
Add very simple gmissing command.
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
177 by Jelmer Vernooij
Register commands all at once.
488
188.1.1 by Szilveszter Farkas (Phanatic)
Inital implementation of the Initialize dialog. Not fully functional yet.
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
190.1.1 by Szilveszter Farkas (Phanatic)
Added 'gtags' command and basic Tags window (just a skeleton).
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
177 by Jelmer Vernooij
Register commands all at once.
508
commands = [
323 by Jelmer Vernooij
Add gsend command.
509
    cmd_gannotate, 
510
    cmd_gbranch,
511
    cmd_gcheckout, 
512
    cmd_gcommit, 
513
    cmd_gconflicts, 
514
    cmd_gdiff,
515
    cmd_ginit,
177 by Jelmer Vernooij
Register commands all at once.
516
    cmd_gmissing, 
517
    cmd_gpreferences, 
323 by Jelmer Vernooij
Add gsend command.
518
    cmd_gpush, 
519
    cmd_gsend,
177 by Jelmer Vernooij
Register commands all at once.
520
    cmd_gstatus,
323 by Jelmer Vernooij
Add gsend command.
521
    cmd_gtags,
522
    cmd_visualise
177 by Jelmer Vernooij
Register commands all at once.
523
    ]
524
525
for cmd in commands:
526
    register_command(cmd)
175 by Jelmer Vernooij
Add very simple gmissing command.
527
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
528
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
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):
211 by Jelmer Vernooij
Move notification area code into separate file.
537
        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.
538
        gtk = self.open_display()
211 by Jelmer Vernooij
Move notification area code into separate file.
539
        menu = NotifyPopupMenu()
399.1.19 by Jelmer Vernooij
Add utility function for finding icon paths.
540
        icon = gtk.status_icon_new_from_file(icon_path("bzr-icon-64.png"))
211 by Jelmer Vernooij
Move notification area code into separate file.
541
        icon.connect('popup-menu', menu.display)
210 by Jelmer Vernooij
Add notification area icon for commit-notify.
542
173.1.3 by Robert Collins
Add new command 'commit-notify' to listen for commits on dbus and show them via pynotify.
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
450.2.1 by James Henstridge
Make commit-notify listen for Revision signals from any source rather
553
        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.
554
        bus = dbus.SessionBus()
211 by Jelmer Vernooij
Move notification area code into separate file.
555
182.1.1 by Robert Collins
Update commit-notify to use new dbus api, and show remote URL's.
556
        def catch_branch(revision_id, urls):
557
            # TODO: show all the urls, or perhaps choose the 'best'.
558
            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.
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)
208.2.2 by Robert Collins
Add inspect window to bzr commity-notify.
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()
208.2.3 by Robert Collins
Add a Branch button to commit-notify.
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()
208.2.4 by Robert Collins
Unbreak inspect of commits due to misunderstanding of pynotify api.
584
                nw.add_action("inspect", "Inspect", start_viz, None)
585
                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.
586
                nw.set_timeout(5000)
587
                nw.show()
588
            except Exception, e:
589
                print e
590
                raise
450.2.1 by James Henstridge
Make commit-notify listen for Revision signals from any source rather
591
        bus.add_signal_receiver(catch_branch,
592
                                dbus_interface=BROADCAST_INTERFACE,
593
                                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.
594
        pynotify.init("bzr commit-notify")
595
        gtk.main()
596
597
register_command(cmd_commit_notify)
598
599
249 by Aaron Bentley
Add gselftest command
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
253 by Aaron Bentley
Avoid encoding problems from pygtk
609
        import sys
610
        default_encoding = sys.getdefaultencoding()
249 by Aaron Bentley
Add gselftest command
611
        # prevent gtk from blowing up later
612
        gtk = import_pygtk()
253 by Aaron Bentley
Avoid encoding problems from pygtk
613
        # prevent gtk from messing with default encoding
249 by Aaron Bentley
Add gselftest command
614
        import pynotify
253 by Aaron Bentley
Avoid encoding problems from pygtk
615
        if sys.getdefaultencoding() != default_encoding:
616
            reload(sys)
617
            sys.setdefaultencoding(default_encoding)
249 by Aaron Bentley
Add gselftest command
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
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
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',
330.6.2 by Aaron Bentley
Fix option grammar
639
                            help='Stop when one test fails.'),
640
                     Option('benchmark', help='Run the benchmarks.'),
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
641
                     Option('lsprof-timed',
330.6.2 by Aaron Bentley
Fix option grammar
642
                     help='Generate lsprof output for benchmarked'
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
643
                          ' sections of code.'),
644
                     Option('list-only',
330.6.2 by Aaron Bentley
Fix option grammar
645
                     help='List the tests instead of running them.'),
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
646
                     Option('randomize', type=str, argname="SEED",
330.6.2 by Aaron Bentley
Fix option grammar
647
                     help='Randomize the order of tests using the given'
648
                          ' seed or "now" for the current time.'),
278.1.22 by John Arbash Meinel
Add a test-gtk command to make testing faster
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
424 by Aaron Bentley
Add ghandle-patch
696
class cmd_ghandle_patch(GTKCommand):
432 by Aaron Bentley
Misc updates
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
    """
424 by Aaron Bentley
Add ghandle-patch
703
704
    takes_args = ['path']
705
706
    def run(self, path):
426 by Aaron Bentley
Start support for Merge Directives
707
        try:
487.2.2 by Aaron Bentley
Unify MergeDirectiveWindow and DiffWindow
708
            from bzrlib.plugins.gtk.diff import (DiffController,
487.2.1 by Aaron Bentley
Refactor merge directive window into MergeController
709
                                                 MergeDirectiveController)
434 by Aaron Bentley
Better errors, merge directive saving
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:
487.2.2 by Aaron Bentley
Unify MergeDirectiveWindow and DiffWindow
715
                controller = DiffController(path, lines)
434 by Aaron Bentley
Better errors, merge directive saving
716
            else:
487.2.2 by Aaron Bentley
Unify MergeDirectiveWindow and DiffWindow
717
                controller = MergeDirectiveController(path, directive)
718
            window = controller.window
434 by Aaron Bentley
Better errors, merge directive saving
719
            window.show()
720
            gtk = self.open_display()
721
            window.connect("destroy", gtk.main_quit)
722
        except Exception, e:
723
            from dialog import error_dialog
724
            error_dialog('Error', str(e))
725
            raise
424 by Aaron Bentley
Add ghandle-patch
726
        gtk.main()
727
728
729
register_command(cmd_ghandle_patch)
730
731
152 by Jelmer Vernooij
Cleanup some more code.
732
import gettext
733
gettext.install('olive-gtk')
734
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
735
55.1.2 by Jelmer Vernooij
Move commands to top-level __init__
736
class NoDisplayError(BzrCommandError):
737
    """gtk could not find a proper display"""
738
739
    def __str__(self):
133 by Jelmer Vernooij
Actually use the ui factory.
740
        return "No DISPLAY. Unable to run GTK+ application."
741
173.1.2 by Robert Collins
Minor refactoring of __init__ to have less duplication.
742
140 by Jelmer Vernooij
add framework for tests.
743
def test_suite():
744
    from unittest import TestSuite
745
    import tests
163 by Aaron Bentley
Prevent test suite from causing default-encoding changes
746
    import sys
747
    default_encoding = sys.getdefaultencoding()
748
    try:
749
        result = TestSuite()
330.6.4 by Aaron Bentley
Allow test suite to run without pygtk
750
        try:
751
            import_pygtk()
752
        except errors.BzrCommandError:
753
            return result
163 by Aaron Bentley
Prevent test suite from causing default-encoding changes
754
        result.addTest(tests.test_suite())
755
    finally:
170.1.2 by Aaron Bentley
Test suite only fixes encoding if it's changed. Fixes test_selftest bug.
756
        if sys.getdefaultencoding() != default_encoding:
757
            reload(sys)
758
            sys.setdefaultencoding(default_encoding)
140 by Jelmer Vernooij
add framework for tests.
759
    return result