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.
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.
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
23
from bzrlib.commands import (
27
from bzrlib.errors import (
32
from bzrlib.option import Option
34
from bzrlib.plugins.gtk import (
40
class GTKCommand(Command):
41
"""Abstract class providing GTK specific run commands."""
45
dialog = self.get_gtk_dialog(os.path.abspath('.'))
49
class cmd_gbranch(GTKCommand):
54
def get_gtk_dialog(self, path):
55
from bzrlib.plugins.gtk.branch import BranchDialog
56
return BranchDialog(path)
59
class cmd_gcheckout(GTKCommand):
64
def get_gtk_dialog(self, path):
65
from bzrlib.plugins.gtk.checkout import CheckoutDialog
66
return CheckoutDialog(path)
70
class cmd_gpush(GTKCommand):
74
takes_args = [ "location?" ]
76
def run(self, location="."):
77
(br, path) = branch.Branch.open_containing(location)
79
from bzrlib.plugins.gtk.push import PushDialog
80
dialog = PushDialog(br.repository, br.last_revision(), br)
84
class cmd_gloom(GTKCommand):
88
takes_args = [ "location?" ]
90
def run(self, location="."):
92
(tree, path) = workingtree.WorkingTree.open_containing(location)
94
except NoWorkingTree, e:
95
(br, path) = branch.Branch.open_containing(location)
98
from bzrlib.plugins.gtk.loom import LoomDialog
99
dialog = LoomDialog(br, tree)
103
class cmd_gdiff(GTKCommand):
104
"""Show differences in working tree in a GTK+ Window.
106
Otherwise, all changes for the tree are listed.
108
takes_args = ['filename?']
109
takes_options = ['revision']
112
def run(self, revision=None, filename=None):
114
wt = workingtree.WorkingTree.open_containing(".")[0]
118
if revision is not None:
119
if len(revision) == 1:
121
revision_id = revision[0].as_revision_id(tree1.branch)
122
tree2 = branch.repository.revision_tree(revision_id)
123
elif len(revision) == 2:
124
revision_id_0 = revision[0].as_revision_id(branch)
125
tree2 = branch.repository.revision_tree(revision_id_0)
126
revision_id_1 = revision[1].as_revision_id(branch)
127
tree1 = branch.repository.revision_tree(revision_id_1)
130
tree2 = tree1.basis_tree()
132
from diff import DiffWindow
134
window = DiffWindow()
135
window.connect("destroy", gtk.main_quit)
136
window.set_diff("Working Tree", tree1, tree2)
137
if filename is not None:
138
tree_filename = wt.relpath(filename)
140
window.set_file(tree_filename)
142
if (tree1.path2id(tree_filename) is None and
143
tree2.path2id(tree_filename) is None):
144
raise NotVersionedError(filename)
145
raise BzrCommandError('No changes found for file "%s"' %
154
def start_viz_window(branch, revisions, limit=None):
155
"""Start viz on branch with revision revision.
157
:return: The viz window object.
159
from bzrlib.plugins.gtk.viz import BranchWindow
160
return BranchWindow(branch, revisions, limit)
163
class cmd_visualise(Command):
164
"""Graphically visualise this branch.
166
Opens a graphical window to allow you to see the history of the branch
167
and relationships between revisions in a visual manner,
169
The default starting point is latest revision on the branch, you can
170
specify a starting point with -r revision.
174
Option('limit', "Maximum number of revisions to display.",
176
takes_args = [ "locations*" ]
177
aliases = [ "visualize", "vis", "viz" ]
179
def run(self, locations_list, revision=None, limit=None):
181
if locations_list is None:
182
locations_list = ["."]
184
for location in locations_list:
185
(br, path) = branch.Branch.open_containing(location)
187
revids.append(br.last_revision())
189
revids.append(revision[0].as_revision_id(br))
191
pp = start_viz_window(br, revids, limit)
192
pp.connect("destroy", lambda w: gtk.main_quit())
197
class cmd_gannotate(GTKCommand):
200
Browse changes to FILENAME line by line in a GTK+ window.
203
takes_args = ["filename", "line?"]
205
Option("all", help="Show annotations on all lines."),
206
Option("plain", help="Don't highlight annotation lines."),
207
Option("line", type=int, argname="lineno",
208
help="Jump to specified line number."),
211
aliases = ["gblame", "gpraise"]
213
def run(self, filename, all=False, plain=False, line='1', revision=None):
219
raise BzrCommandError('Line argument ("%s") is not a number.' %
222
from annotate.gannotate import GAnnotateWindow
223
from annotate.config import GAnnotateConfig
224
from bzrlib.bzrdir import BzrDir
226
wt, br, path = BzrDir.open_containing_tree_or_branch(filename)
230
tree = br.basis_tree()
232
file_id = tree.path2id(path)
235
raise NotVersionedError(filename)
236
if revision is not None:
237
if len(revision) != 1:
238
raise BzrCommandError("Only 1 revion may be specified.")
239
revision_id = revision[0].as_revision_id(br)
240
tree = br.repository.revision_tree(revision_id)
242
revision_id = getattr(tree, 'get_revision_id', lambda: None)()
244
window = GAnnotateWindow(all, plain, branch=br)
245
window.connect("destroy", lambda w: gtk.main_quit())
246
config = GAnnotateConfig(window)
252
window.annotate(tree, br, file_id)
253
window.jump_to_line(line)
262
class cmd_gcommit(GTKCommand):
263
"""GTK+ commit dialog
265
Graphical user interface for committing revisions"""
271
def run(self, filename=None):
274
from commit import CommitDialog
275
from bzrlib.errors import (BzrCommandError,
282
(wt, path) = workingtree.WorkingTree.open_containing(filename)
284
except NoWorkingTree, e:
285
from dialog import error_dialog
286
error_dialog(_i18n('Directory does not have a working tree'),
287
_i18n('Operation aborted.'))
288
return 1 # should this be retval=3?
290
# It is a good habit to keep things locked for the duration, but it
291
# could cause difficulties if someone wants to do things in another
292
# window... We could lock_read() until we actually go to commit
293
# changes... Just a thought.
296
dlg = CommitDialog(wt)
302
class cmd_gstatus(GTKCommand):
303
"""GTK+ status dialog
305
Graphical user interface for showing status
309
takes_args = ['PATH?']
310
takes_options = ['revision']
312
def run(self, path='.', revision=None):
315
from bzrlib.plugins.gtk.status import StatusWindow
316
(wt, wt_path) = workingtree.WorkingTree.open_containing(path)
318
if revision is not None:
320
revision_id = revision[0].as_revision_id(wt.branch)
322
from bzrlib.errors import BzrError
323
raise BzrError('Revision %r doesn\'t exist'
324
% revision[0].user_spec )
328
status = StatusWindow(wt, wt_path, revision_id)
329
status.connect("destroy", gtk.main_quit)
334
class cmd_gsend(GTKCommand):
335
"""GTK+ send merge directive.
339
(br, path) = branch.Branch.open_containing(".")
341
from bzrlib.plugins.gtk.mergedirective import SendMergeDirectiveDialog
342
from StringIO import StringIO
343
dialog = SendMergeDirectiveDialog(br)
344
if dialog.run() == gtk.RESPONSE_OK:
346
outf.writelines(dialog.get_merge_directive().to_lines())
347
mail_client = br.get_config().get_mail_client()
348
mail_client.compose_merge_request(dialog.get_mail_to(), "[MERGE]",
354
class cmd_gconflicts(GTKCommand):
357
Select files from the list of conflicts and run an external utility to
361
(wt, path) = workingtree.WorkingTree.open_containing('.')
363
from bzrlib.plugins.gtk.conflicts import ConflictsDialog
364
dialog = ConflictsDialog(wt)
368
class cmd_gpreferences(GTKCommand):
369
""" GTK+ preferences dialog.
374
from bzrlib.plugins.gtk.preferences import PreferencesWindow
375
dialog = PreferencesWindow()
379
class cmd_ginfo(Command):
384
from bzrlib import workingtree
385
from bzrlib.plugins.gtk.olive.info import InfoDialog
386
wt = workingtree.WorkingTree.open_containing('.')[0]
387
info = InfoDialog(wt.branch)
392
class cmd_gmerge(Command):
393
""" GTK+ merge dialog
396
takes_args = ["merge_from_path?"]
397
def run(self, merge_from_path=None):
398
from bzrlib.plugins.gtk.dialog import error_dialog
399
from bzrlib.plugins.gtk.merge import MergeDialog
401
(wt, path) = workingtree.WorkingTree.open_containing('.')
402
old_tree = wt.branch.repository.revision_tree(wt.branch.last_revision())
403
delta = wt.changes_from(old_tree)
404
if len(delta.added) or len(delta.removed) or len(delta.renamed) or len(delta.modified):
405
error_dialog(_i18n('There are local changes in the branch'),
406
_i18n('Please commit or revert the changes before merging.'))
408
parent_branch_path = wt.branch.get_parent()
409
merge = MergeDialog(wt, path, parent_branch_path)
410
response = merge.run()
414
class cmd_gmissing(Command):
415
""" GTK+ missing revisions dialog.
418
takes_args = ["other_branch?"]
419
def run(self, other_branch=None):
420
pygtk = import_pygtk()
423
except RuntimeError, e:
424
if str(e) == "could not open display":
427
from bzrlib.plugins.gtk.missing import MissingWindow
428
from bzrlib.branch import Branch
430
local_branch = Branch.open_containing(".")[0]
431
if other_branch is None:
432
other_branch = local_branch.get_parent()
434
if other_branch is None:
435
raise errors.BzrCommandError("No peer location known or specified.")
436
remote_branch = Branch.open_containing(other_branch)[0]
438
local_branch.lock_read()
440
remote_branch.lock_read()
442
dialog = MissingWindow(local_branch, remote_branch)
445
remote_branch.unlock()
447
local_branch.unlock()
450
class cmd_ginit(GTKCommand):
453
from initialize import InitDialog
454
dialog = InitDialog(os.path.abspath(os.path.curdir))
458
class cmd_gtags(GTKCommand):
460
br = branch.Branch.open_containing('.')[0]
463
from tags import TagsWindow
464
window = TagsWindow(br)
469
class cmd_gselftest(GTKCommand):
470
"""Version of selftest that displays a notification at the end"""
472
takes_args = builtins.cmd_selftest.takes_args
473
takes_options = builtins.cmd_selftest.takes_options
474
_see_also = ['selftest']
476
def run(self, *args, **kwargs):
479
default_encoding = sys.getdefaultencoding()
480
# prevent gtk from blowing up later
482
# prevent gtk from messing with default encoding
484
if sys.getdefaultencoding() != default_encoding:
486
sys.setdefaultencoding(default_encoding)
487
result = builtins.cmd_selftest().run(*args, **kwargs)
490
body = 'Selftest succeeded in "%s"' % os.getcwd()
493
body = 'Selftest failed in "%s"' % os.getcwd()
494
pynotify.init("bzr gselftest")
495
note = pynotify.Notification(cgi.escape(summary), cgi.escape(body))
496
note.set_timeout(pynotify.EXPIRES_NEVER)