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