2
3
Various useful plugins for working with bzr.
11
version_info = tuple(int(n) for n in __version__.split('.'))
14
def check_bzrlib_version(desired):
15
"""Check that bzrlib is compatible.
17
If version is < bzrtools version, assume incompatible.
18
If version == bzrtools version, assume completely compatible
19
If version == bzrtools version + 1, assume compatible, with deprecations
20
Otherwise, assume incompatible.
22
desired_plus = (desired[0], desired[1]+1)
23
bzrlib_version = bzrlib.version_info[:2]
24
if bzrlib_version == desired:
27
from bzrlib.trace import warning
29
# get the message out any way we can
30
from warnings import warn as warning
31
if bzrlib_version < desired:
32
warning('Installed bzr version %s is too old to be used with bzrtools'
33
' %s.' % (bzrlib.__version__, __version__))
34
# Not using BzrNewError, because it may not exist.
35
raise Exception, ('Version mismatch', version_info)
37
warning('Bzrtools is not up to date with installed bzr version %s.'
38
' \nThere should be a newer version available, e.g. %i.%i.'
39
% (bzrlib.__version__, bzrlib_version[0], bzrlib_version[1]))
40
if bzrlib_version != desired_plus:
41
raise Exception, 'Version mismatch'
44
check_bzrlib_version(version_info[:2])
48
from errors import CommandError, NoPyBaz
7
from errors import CommandError
49
8
from patchsource import BzrPatchSource
50
9
from shelf import Shelf
51
from switch import cmd_switch
55
import bzrlib.builtins
12
from bzrlib.option import Option
56
13
import bzrlib.branch
57
import bzrlib.commands
58
from bzrlib.commands import get_cmd_object
59
14
from bzrlib.errors import BzrCommandError
60
from bzrlib.help import command_usage
62
from bzrlib.option import Option
15
from reweave_inventory import cmd_fix
63
16
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__),
66
bzrlib.ignores.add_runtime_ignores(['./.shelf'])
18
from bzrlib import DEFAULT_IGNORE
21
DEFAULT_IGNORE.append('./.shelf')
22
DEFAULT_IGNORE.append('./.bzr-shelf*')
25
Option.OPTIONS['ignored'] = Option('ignored',
26
help='delete all ignored files.')
27
Option.OPTIONS['detritus'] = Option('detritus',
28
help='delete conflict files merge backups, and failed selftest dirs.' +
29
'(*.THIS, *.BASE, *.OTHER, *~, *.tmp')
30
Option.OPTIONS['dry-run'] = Option('dry-run',
31
help='show files to delete instead of deleting them.')
69
33
class cmd_clean_tree(bzrlib.commands.Command):
70
34
"""Remove unwanted files from working tree.
72
By default, only unknown files, not ignored files, are deleted. Versioned
73
files are never deleted.
75
Another class is 'detritus', which includes files emitted by bzr during
76
normal operations and selftests. (The value of these files decreases with
79
If no options are specified, unknown files are deleted. Otherwise, option
80
flags are respected, and may be combined.
82
To check what clean-tree will do, use --dry-run.
35
Normally, ignored files are left alone.
84
takes_options = [Option('ignored', help='delete all ignored files.'),
85
Option('detritus', help='delete conflict files, merge'
86
' backups, and failed selftest dirs.'),
88
help='delete files unknown to bzr. (default)'),
89
Option('dry-run', help='show files to delete instead of'
91
def run(self, unknown=False, ignored=False, detritus=False, dry_run=False):
37
takes_options = ['ignored', 'detritus', 'dry-run']
38
def run(self, ignored=False, detritus=False, dry_run=False):
92
39
from clean_tree import clean_tree
93
if not (unknown or ignored or detritus):
95
clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
40
clean_tree('.', ignored=ignored, detritus=detritus, dry_run=dry_run)
42
Option.OPTIONS['merge-branch'] = Option('merge-branch',type=str)
99
44
class cmd_graph_ancestry(bzrlib.commands.Command):
100
45
"""Produce ancestry graphs using dot.
229
163
source = BzrPatchSource(revision, file_list)
230
164
s = Shelf(source.base)
231
s.shelve(source, all, message, no_color)
165
s.shelve(source, all, message)
235
# The following classes are only used as subcommands for 'shelf', they're
236
# not to be registered directly with bzr.
238
class cmd_shelf_list(bzrlib.commands.Command):
239
"""List the patches on the current shelf."""
240
aliases = ['list', 'ls']
245
class cmd_shelf_delete(bzrlib.commands.Command):
246
"""Delete the patch from the current shelf."""
247
aliases = ['delete', 'del']
248
takes_args = ['patch']
249
def run(self, patch):
250
self.shelf.delete(patch)
253
class cmd_shelf_switch(bzrlib.commands.Command):
254
"""Switch to the other shelf, create it if necessary."""
256
takes_args = ['othershelf']
257
def run(self, othershelf):
258
s = Shelf(self.shelf.base, othershelf)
262
class cmd_shelf_show(bzrlib.commands.Command):
263
"""Show the contents of the specified or topmost patch."""
264
aliases = ['show', 'cat', 'display']
265
takes_args = ['patch?']
266
def run(self, patch=None):
267
self.shelf.display(patch)
270
class cmd_shelf_upgrade(bzrlib.commands.Command):
271
"""Upgrade old format shelves."""
272
aliases = ['upgrade']
277
168
class cmd_shelf(bzrlib.commands.Command):
278
"""Perform various operations on your shelved patches. See also shelve."""
169
"""Perform various operations on your shelved patches. See also shelve.
172
list (ls) List the patches on the current shelf.
173
delete (del) <patch> Delete a patch from the current shelf.
174
switch <shelf> Switch to the named shelf, create it if necessary.
175
show <patch> Show the contents of the specified patch.
176
upgrade Upgrade old format shelves.
279
178
takes_args = ['subcommand', 'args*']
281
subcommands = [cmd_shelf_list, cmd_shelf_delete, cmd_shelf_switch,
282
cmd_shelf_show, cmd_shelf_upgrade]
284
180
def run(self, subcommand, args_list):
287
cmd = self._get_cmd_object(subcommand)
288
183
source = BzrPatchSource()
289
184
s = Shelf(source.base)
291
return cmd.run_argv_aliases(args_list)
293
def _get_cmd_object(self, cmd_name):
294
for cmd_class in self.subcommands:
295
for alias in cmd_class.aliases:
296
if alias == cmd_name:
298
raise CommandError("Unknown shelf subcommand '%s'" % cmd_name)
301
text = ["%s\n\nSubcommands:\n" % self.__doc__]
303
for cmd_class in self.subcommands:
304
text.extend(self.sub_help(cmd_class) + ['\n'])
308
def sub_help(self, cmd_class):
310
cmd_obj = cmd_class()
313
usage = command_usage(cmd_obj)
314
usage = usage.replace('bzr shelf-', '')
315
text.append('%s%s\n' % (indent, usage))
317
text.append('%s%s\n' % (2 * indent, cmd_class.__doc__))
319
# Somewhat copied from bzrlib.help.help_on_command_options
321
for option_name, option in sorted(cmd_obj.options().items()):
322
if option_name == 'help':
324
option_help.append('%s--%s' % (3 * indent, option_name))
325
if option.type is not None:
326
option_help.append(' %s' % option.argname.upper())
327
if option.short_name():
328
option_help.append(', -%s' % option.short_name())
329
option_help.append('%s%s\n' % (2 * indent, option.help))
331
if len(option_help) > 0:
332
text.append('%soptions:\n' % (2 * indent))
333
text.extend(option_help)
186
if subcommand == 'ls' or subcommand == 'list':
187
self.__check_no_args(args_list, "shelf list takes no arguments!")
189
elif subcommand == 'delete' or subcommand == 'del':
190
self.__check_one_arg(args_list, "shelf delete takes one argument!")
191
s.delete(args_list[0])
192
elif subcommand == 'switch':
193
self.__check_one_arg(args_list, "shelf switch takes one argument!")
194
s = Shelf(source.base, args_list[0])
196
elif subcommand == 'show':
197
self.__check_one_arg(args_list, "shelf show takes one argument!")
198
s.display(args_list[0])
199
elif subcommand == 'upgrade':
200
self.__check_no_args(args_list, "shelf upgrade takes no arguments!")
203
print subcommand, args_list
204
print >>sys.stderr, "Unknown shelf subcommand '%s'" % subcommand
206
def __check_one_arg(self, args, msg):
207
if args is None or len(args) != 1:
208
raise CommandError(msg)
210
def __check_no_args(self, args, msg):
212
raise CommandError(msg)
338
215
class cmd_unshelve(bzrlib.commands.Command):
339
"""Restore shelved changes.
341
By default the most recently shelved changes are restored. However if you
342
specify a patch by name those changes will be restored instead.
216
"""Restore the most recently shelved changes to the current tree.
344
217
See 'shelve' for more information.
346
219
takes_options = [
347
220
Option('all', help='Unshelve all changes without prompting'),
348
221
Option('force', help='Force unshelving even if errors occur'),
349
Option('no-color', help='Never display changes in color')
351
takes_args = ['patch?']
352
def run(self, patch=None, all=False, force=False, no_color=False):
223
def run(self, all=False, force=False):
353
224
source = BzrPatchSource()
354
225
s = Shelf(source.base)
355
s.unshelve(source, patch, all, force, no_color)
226
s.unshelve(source, all, force)
392
262
from branchhistory import branch_history
393
263
return branch_history(branch)
396
class cmd_zap(bzrlib.commands.Command):
398
Remove a lightweight checkout, if it can be done safely.
400
This command will remove a lightweight checkout without losing data. That
401
means it only removes lightweight checkouts, and only if they have no
404
If --branch is specified, the branch will be deleted too, but only if the
405
the branch has no new commits (relative to its parent).
407
takes_options = [Option("branch", help="Remove associtated branch from"
409
takes_args = ["checkout"]
410
def run(self, checkout, branch=False):
412
return zap(checkout, remove_branch=branch)
415
class cmd_cbranch(bzrlib.commands.Command):
417
Create a new checkout, associated with a new repository branch.
419
When you cbranch, bzr looks up the repository associated with your current
420
directory in locations.conf. It creates a new branch in that repository
421
with the same name and relative path as the checkout you request.
423
The locations.conf parameter is "cbranch_root". So if you want
424
cbranch operations in /home/jrandom/bigproject to produce branches in
425
/home/jrandom/bigproject/repository, you'd add this:
427
[/home/jrandom/bigproject]
428
cbranch_root = /home/jrandom/bigproject/repository
430
Note that if "/home/jrandom/bigproject/repository" isn't a repository,
431
standalone branches will be produced. Standalone branches will also
432
be produced if the source branch is in 0.7 format (or earlier).
434
takes_options = [Option("lightweight",
435
help="Create a lightweight checkout"), 'revision']
436
takes_args = ["source", "target?"]
437
def run(self, source, target=None, lightweight=False, revision=None):
438
from cbranch import cbranch
439
return cbranch(source, target, lightweight=lightweight,
443
class cmd_branches(bzrlib.commands.Command):
444
"""Scan a location for branches"""
445
takes_args = ["location?"]
446
def run(self, location=None):
447
from branches import branches
448
return branches(location)
451
class cmd_multi_pull(bzrlib.commands.Command):
452
"""Pull all the branches under a location, e.g. a repository.
454
Both branches present in the directory and the branches of checkouts are
457
takes_args = ["location?"]
458
def run(self, location=None):
459
from bzrlib.branch import Branch
460
from bzrlib.transport import get_transport
461
from bzrtools import iter_branch_tree
464
t = get_transport(location)
466
print "Can't list this type of location."
468
for branch, wt in iter_branch_tree(t):
473
parent = branch.get_parent()
480
if base.startswith(t.base):
481
relpath = base[len(t.base):].rstrip('/')
484
print "Pulling %s from %s" % (relpath, parent)
486
pullable.pull(Branch.open(parent))
491
class cmd_branch_mark(bzrlib.commands.Command):
493
Add, view or list branch markers <EXPERIMENTAL>
495
To add a mark, do 'bzr branch-mark MARK'.
496
To list marks, do 'bzr branch-mark' (this lists all marks for the branch's
498
To delete a mark, do 'bzr branch-mark --delete MARK'
500
These marks can be used to track a branch's status.
502
takes_args = ['mark?', 'branch?']
503
takes_options = [Option('delete', help='Delete this mark')]
504
def run(self, mark=None, branch=None, delete=False):
505
from branch_mark import branch_mark
506
branch_mark(mark, branch, delete)
509
class cmd_import(bzrlib.commands.Command):
510
"""Import sources from a tarball
512
This command will import a tarball into a bzr tree, replacing any versioned
513
files already present. If a directory is specified, it is used as the
514
target. If the directory does not exist, or is not versioned, it is
517
Tarballs may be gzip or bzip2 compressed. This is autodetected.
519
If the tarball has a single root directory, that directory is stripped
520
when extracting the tarball.
523
takes_args = ['source', 'tree?']
524
def run(self, source, tree=None):
525
from upstream_import import do_import
526
do_import(source, tree)
529
class cmd_cdiff(bzrlib.commands.Command):
530
"""A color version of bzr's diff"""
531
takes_args = property(lambda x: get_cmd_object('diff').takes_args)
532
takes_options = property(lambda x: get_cmd_object('diff').takes_options)
533
def run(*args, **kwargs):
534
from colordiff import colordiff
535
colordiff(*args, **kwargs)
538
class cmd_baz_import(bzrlib.commands.Command):
539
"""Import an Arch or Baz archive into a bzr repository.
541
This command should be used on local archives (or mirrors) only. It is
542
quite slow on remote archives.
544
reuse_history allows you to specify any previous imports you
545
have done of different archives, which this archive has branches
546
tagged from. This will dramatically reduce the time to convert
547
the archive as it will not have to convert the history already
548
converted in that other branch.
550
If you specify prefixes, only branches whose names start with that prefix
551
will be imported. Skipped branches will be listed, so you can import any
552
branches you missed by accident. Here's an example of doing a partial
553
import from thelove@canonical.com:
554
bzr baz-import thelove thelove@canonical.com --prefixes dists:talloc-except
556
takes_args = ['to_root_dir', 'from_archive', 'reuse_history*']
557
takes_options = ['verbose', Option('prefixes', type=str,
558
help="Prefixes of branches to import, colon-separated")]
560
def run(self, to_root_dir, from_archive, verbose=False,
561
reuse_history_list=[], prefixes=None):
562
from errors import NoPyBaz
565
baz_import.baz_import(to_root_dir, from_archive,
566
verbose, reuse_history_list, prefixes)
568
print "This command is disabled. Please install PyBaz."
571
class cmd_baz_import_branch(bzrlib.commands.Command):
572
"""Import an Arch or Baz branch into a bzr branch."""
573
takes_args = ['to_location', 'from_branch?', 'reuse_history*']
574
takes_options = ['verbose', Option('max-count', type=int)]
576
def run(self, to_location, from_branch=None, fast=False, max_count=None,
577
verbose=False, dry_run=False, reuse_history_list=[]):
578
from errors import NoPyBaz
581
baz_import.baz_import_branch(to_location, from_branch, fast,
582
max_count, verbose, dry_run,
585
print "This command is disabled. Please install PyBaz."
590
cmd_baz_import_branch,
610
commands.append(rspush.cmd_rspush)
265
commands = [cmd_shelve, cmd_unshelve, cmd_shelf, cmd_clean_tree,
266
cmd_graph_ancestry, cmd_fetch_ghosts, cmd_patch, cmd_shell,
267
cmd_fix, cmd_branch_history]
269
command_decorators = []
271
command_decorators = []
273
import bzrlib.builtins
274
if not hasattr(bzrlib.builtins, "cmd_push"):
275
commands.append(push.cmd_push)
277
command_decorators.append(push.cmd_push)
279
from errors import NoPyBaz
282
commands.append(baz_import.cmd_baz_import_branch)
283
commands.append(baz_import.cmd_baz_import)
286
class cmd_baz_import_branch(bzrlib.commands.Command):
287
"""Disabled. (Requires PyBaz)"""
288
takes_args = ['to_location?', 'from_branch?', 'reuse_history*']
289
takes_options = ['verbose', Option('max-count', type=int)]
290
def run(self, to_location=None, from_branch=None, fast=False,
291
max_count=None, verbose=False, dry_run=False,
292
reuse_history_list=[]):
293
print "This command is disabled. Please install PyBaz."
296
class cmd_baz_import(bzrlib.commands.Command):
297
"""Disabled. (Requires PyBaz)"""
298
takes_args = ['to_root_dir?', 'from_archive?', 'reuse_history*']
299
takes_options = ['verbose', Option('prefixes', type=str,
300
help="Prefixes of branches to import")]
301
def run(self, to_root_dir=None, from_archive=None, verbose=False,
302
reuse_history_list=[], prefixes=None):
303
print "This command is disabled. Please install PyBaz."
304
commands.extend((cmd_baz_import_branch, cmd_baz_import))
612
307
if hasattr(bzrlib.commands, 'register_command'):
613
308
for command in commands:
614
309
bzrlib.commands.register_command(command)
310
for command in command_decorators:
311
command._original_command = bzrlib.commands.register_command(
617
315
def test_suite():
618
317
from bzrlib.tests.TestUtil import TestLoader
620
319
from doctest import DocTestSuite, ELLIPSIS
621
320
from unittest import TestSuite
622
import tests.clean_tree
623
import upstream_import
625
import tests.blackbox
626
import tests.shelf_tests
627
324
result = TestSuite()
628
325
result.addTest(DocTestSuite(bzrtools, optionflags=ELLIPSIS))
629
result.addTest(tests.clean_tree.test_suite())
632
result.addTest(DocTestSuite(baz_import))
326
result.addTest(clean_tree.test_suite())
327
result.addTest(DocTestSuite(baz_import))
635
328
result.addTest(tests.test_suite())
636
result.addTest(TestLoader().loadTestsFromModule(tests.shelf_tests))
637
result.addTest(tests.blackbox.test_suite())
638
result.addTest(upstream_import.test_suite())
639
result.addTest(zap.test_suite())
329
result.addTest(TestLoader().loadTestsFromModule(shelf_tests))
330
result.addTest(blackbox.test_suite())