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