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