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