26
__version__ = '0.15.0'
29
version_info = tuple(int(n) for n in __version__.split('.'))
32
def check_bzrlib_version(desired):
33
"""Check that bzrlib is compatible.
35
If version is < bzrtools version, assume incompatible.
36
If version == bzrtools version, assume completely compatible
37
If version == bzrtools version + 1, assume compatible, with deprecations
38
Otherwise, assume incompatible.
40
desired_plus = (desired[0], desired[1]+1)
41
bzrlib_version = bzrlib.version_info[:2]
42
if bzrlib_version == desired:
45
from bzrlib.trace import warning
47
# get the message out any way we can
48
from warnings import warn as warning
49
if bzrlib_version < desired:
50
warning('Installed Bazzar version %s is too old to be used with'
52
'"Bzrtools" %s.' % (bzrlib.__version__, __version__))
53
# Not using BzrNewError, because it may not exist.
54
raise Exception, ('Version mismatch', version_info)
56
warning('Plugin "Bzrtools" is not up to date with installed Bazaar'
58
' There should be a newer version of Bzrtools available, e.g.'
60
% (bzrlib.__version__, bzrlib_version[0], bzrlib_version[1]))
61
if bzrlib_version != desired_plus:
62
raise Exception, 'Version mismatch'
65
check_bzrlib_version(version_info[:2])
68
from errors import CommandError, NoPyBaz
25
from bzrlib.lazy_import import lazy_import
26
lazy_import(globals(), """
27
from bzrlib import help, urlutils
31
from version import version_info, __version__
32
from command import BzrToolsCommand
33
from errors import CommandError
69
34
from patchsource import BzrPatchSource
70
from shelf import Shelf
74
38
import bzrlib.builtins
75
39
import bzrlib.commands
40
from bzrlib.branch import Branch
41
from bzrlib.bzrdir import BzrDir
76
42
from bzrlib.commands import get_cmd_object
77
43
from bzrlib.errors import BzrCommandError
78
from bzrlib.help import command_usage
79
44
import bzrlib.ignores
45
from bzrlib.trace import note
80
46
from bzrlib.option import Option
81
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__),
48
from command import BzrToolsCommand
86
50
bzrlib.ignores.add_runtime_ignores(['./.shelf'])
89
class cmd_clean_tree(bzrlib.commands.Command):
53
class cmd_clean_tree(BzrToolsCommand):
90
54
"""Remove unwanted files from working tree.
92
56
By default, only unknown files, not ignored files, are deleted. Versioned
102
66
To check what clean-tree will do, use --dry-run.
104
takes_options = [Option('ignored', help='delete all ignored files.'),
105
Option('detritus', help='delete conflict files, merge'
106
' backups, and failed selftest dirs.'),
108
help='delete files unknown to bzr. (default)'),
109
Option('dry-run', help='show files to delete instead of'
68
takes_options = [Option('ignored', help='Delete all ignored files.'),
69
Option('detritus', help='Delete conflict files, merge'
70
' backups, and failed selftest dirs.'),
72
help='Delete files unknown to bzr (default).'),
73
Option('dry-run', help='Show files to delete instead of'
110
74
' deleting them.')]
111
75
def run(self, unknown=False, ignored=False, detritus=False, dry_run=False):
112
76
from clean_tree import clean_tree
151
115
If available, rsvg is used to antialias PNG and JPEG output, but this can
152
116
be disabled with --no-antialias.
154
takes_args = ['branch', 'file']
155
takes_options = [Option('no-collapse', help="Do not skip simple nodes"),
118
takes_args = ['file', 'merge_branch?']
119
takes_options = [Option('no-collapse', help="Do not skip simple nodes."),
156
120
Option('no-antialias',
157
help="Do not use rsvg to produce antialiased output"),
158
Option('merge-branch', type=str,
159
help="Use this branch to calcuate a merge base"),
121
help="Do not use rsvg to produce antialiased output."),
122
Option('merge-branch', type=str,
123
help="Use this branch to calcuate a merge base."),
160
124
Option('cluster', help="Use clustered output."),
161
Option('max-distance', help="Show no nodes farther than this",
163
def run(self, branch, file, no_collapse=False, no_antialias=False,
164
merge_branch=None, cluster=False, max_distance=None):
125
Option('max-distance',
126
help="Show no nodes farther than this.", type=int),
128
help='Source branch to use (default is current'
133
def run(self, file, merge_branch=None, no_collapse=False,
134
no_antialias=False, cluster=False, max_distance=100,
136
if max_distance == -1:
167
140
ranking = "cluster"
169
142
ranking = "forced"
170
graph.write_ancestry_file(branch, file, not no_collapse,
171
not no_antialias, merge_branch, ranking,
143
graph.write_ancestry_file(directory, file, not no_collapse,
144
not no_antialias, merge_branch, ranking,
172
145
max_distance=max_distance)
175
class cmd_fetch_ghosts(bzrlib.commands.Command):
148
class cmd_fetch_ghosts(BzrToolsCommand):
176
149
"""Attempt to retrieve ghosts from another branch.
177
150
If the other branch is not supplied, the last-pulled branch is used.
179
152
aliases = ['fetch-missing']
180
153
takes_args = ['branch?']
181
takes_options = [Option('no-fix')]
154
takes_options = [Option('no-fix', help="Skip additional synchonization.")]
182
155
def run(self, branch=None, no_fix=False):
183
156
from fetch_ghosts import fetch_ghosts
184
157
fetch_ghosts(branch, no_fix)
366
345
See 'shelve' for more information.
368
347
takes_options = [
369
Option('all', help='Unshelve all changes without prompting'),
370
Option('force', help='Force unshelving even if errors occur'),
371
Option('no-color', help='Never display changes in color')
348
Option('all', help='Unshelve all changes without prompting.'),
349
Option('force', help='Force unshelving even if errors occur.'),
350
Option('no-color', help='Never display changes in color.')
373
352
takes_args = ['patch?']
374
353
def run(self, patch=None, all=False, force=False, no_color=False):
375
354
source = BzrPatchSource()
376
s = Shelf(source.base)
355
s = shelf.Shelf(source.base)
377
356
s.unshelve(source, patch, all, force, no_color)
381
class cmd_shell(bzrlib.commands.Command):
360
class cmd_shell(BzrToolsCommand):
382
361
"""Begin an interactive shell tailored for bzr.
383
362
Bzr commands can be used without typing bzr first, and will be run natively
384
363
when possible. Tab completion is tailored for bzr. The shell prompt shows
426
405
If --branch is specified, the branch will be deleted too, but only if the
427
406
the branch has no new commits (relative to its parent).
429
takes_options = [Option("branch", help="Remove associtated branch from"
408
takes_options = [Option("branch", help="Remove associated branch from"
410
Option('force', help='Delete tree even if contents are'
431
412
takes_args = ["checkout"]
432
def run(self, checkout, branch=False):
413
def run(self, checkout, branch=False, force=False):
433
414
from zap import zap
434
return zap(checkout, remove_branch=branch)
437
class cmd_cbranch(bzrlib.commands.Command):
415
return zap(checkout, remove_branch=branch, allow_modified=force)
418
class cmd_cbranch(BzrToolsCommand):
439
420
Create a new checkout, associated with a new repository branch.
441
422
When you cbranch, bzr looks up a target location in locations.conf, and
442
423
creates the branch there.
447
428
cbranch_target:policy = appendpath
449
430
This will mean that if you run "bzr cbranch foo/bar foo/baz" in the
450
working directory root, the branch will be created in
431
working directory root, the branch will be created in
451
432
"/branch_root/foo/baz"
453
434
NOTE: cbranch also supports "cbranch_root", but that behaviour is
456
takes_options = [Option("lightweight",
457
help="Create a lightweight checkout"), 'revision']
437
takes_options = [Option("lightweight",
438
help="Create a lightweight checkout."), 'revision',
439
Option('files-from', type=unicode,
440
help='Accelerate checkout using files from this'
443
help='Hard-link files from source/files-from tree'
458
445
takes_args = ["source", "target?"]
459
def run(self, source, target=None, lightweight=False, revision=None):
446
def run(self, source, target=None, lightweight=False, revision=None,
447
files_from=None, hardlink=False):
460
448
from cbranch import cbranch
461
return cbranch(source, target, lightweight=lightweight,
465
class cmd_branches(bzrlib.commands.Command):
449
return cbranch(source, target, lightweight=lightweight,
450
revision=revision, files_from=files_from,
454
class cmd_branches(BzrToolsCommand):
466
455
"""Scan a location for branches"""
467
456
takes_args = ["location?"]
468
457
def run(self, location=None):
469
458
from branches import branches
470
459
return branches(location)
461
class cmd_trees(BzrToolsCommand):
462
"""Scan a location for trees"""
463
takes_args = ['location?']
464
def run(self, location='.'):
465
from bzrlib.workingtree import WorkingTree
466
from bzrlib.transport import get_transport
467
t = get_transport(location)
468
for tree in WorkingTree.find_trees(location):
469
self.outf.write('%s\n' % t.relpath(
470
tree.bzrdir.root_transport.base))
473
class cmd_multi_pull(bzrlib.commands.Command):
472
class cmd_multi_pull(BzrToolsCommand):
474
473
"""Pull all the branches under a location, e.g. a repository.
476
475
Both branches present in the directory and the branches of checkouts are
479
478
takes_args = ["location?"]
480
479
def run(self, location=None):
481
from bzrlib.branch import Branch
482
480
from bzrlib.transport import get_transport
483
481
from bzrtools import iter_branch_tree
484
482
if location is None:
486
484
t = get_transport(location)
485
possible_transports = []
487
486
if not t.listable():
488
487
print "Can't list this type of location."
506
505
print "Pulling %s from %s" % (relpath, parent)
508
pullable.pull(Branch.open(parent))
507
branch_t = get_transport(parent, possible_transports)
508
pullable.pull(Branch.open_from_transport(branch_t))
509
509
except Exception, e:
513
class cmd_branch_mark(bzrlib.commands.Command):
515
Add, view or list branch markers <EXPERIMENTAL>
517
To add a mark, do 'bzr branch-mark MARK'.
518
To list marks, do 'bzr branch-mark' (this lists all marks for the branch's
520
To delete a mark, do 'bzr branch-mark --delete MARK'
522
These marks can be used to track a branch's status.
524
takes_args = ['mark?', 'branch?']
525
takes_options = [Option('delete', help='Delete this mark')]
526
def run(self, mark=None, branch=None, delete=False):
527
from branch_mark import branch_mark
528
branch_mark(mark, branch, delete)
531
class cmd_import(bzrlib.commands.Command):
514
class cmd_import(BzrToolsCommand):
532
515
"""Import sources from a directory, tarball or zip file
534
517
This command will import a directory, tarball or zip file into a bzr
535
518
tree, replacing any versioned files already present. If a directory is
536
519
specified, it is used as the target. If the directory does not exist, or
541
524
If the tarball or zip has a single root directory, that directory is
542
525
stripped when extracting the tarball. This is not done for directories.
545
528
takes_args = ['source', 'tree?']
546
529
def run(self, source, tree=None):
547
530
from upstream_import import do_import
548
531
do_import(source, tree)
551
class cmd_cdiff(bzrlib.commands.Command):
534
class cmd_cdiff(BzrToolsCommand):
552
535
"""A color version of bzr's diff"""
553
536
takes_args = property(lambda x: get_cmd_object('diff').takes_args)
555
def _takes_options(self):
556
options = list(get_cmd_object('diff').takes_options)
557
options.append(Option('check-style',
537
takes_options = list(get_cmd_object('diff').takes_options) + [
538
Option('check-style',
558
539
help='Warn if trailing whitespace or spurious changes have been'
562
takes_options = property(_takes_options)
564
542
def run(self, check_style=False, *args, **kwargs):
565
543
from colordiff import colordiff
566
544
colordiff(check_style, *args, **kwargs)
569
class cmd_baz_import(bzrlib.commands.Command):
570
"""Import an Arch or Baz archive into a bzr repository.
572
This command should be used on local archives (or mirrors) only. It is
573
quite slow on remote archives.
575
reuse_history allows you to specify any previous imports you
576
have done of different archives, which this archive has branches
577
tagged from. This will dramatically reduce the time to convert
578
the archive as it will not have to convert the history already
579
converted in that other branch.
581
If you specify prefixes, only branches whose names start with that prefix
582
will be imported. Skipped branches will be listed, so you can import any
583
branches you missed by accident. Here's an example of doing a partial
584
import from thelove@canonical.com:
585
bzr baz-import thelove thelove@canonical.com --prefixes dists:talloc-except
587
WARNING: Encoding should not be specified unless necessary, because if you
588
specify an encoding, your converted branch will not interoperate with
589
independently-converted branches, unless the other branches were converted
590
with exactly the same encoding. Any encoding recognized by Python may
591
be specified. Aliases are not detected, so 'utf_8', 'U8', 'UTF' and 'utf8'
594
takes_args = ['to_root_dir', 'from_archive', 'reuse_history*']
595
takes_options = ['verbose', Option('prefixes', type=str,
596
help="Prefixes of branches to import, colon-separated"),
597
Option('encoding', type=str,
598
help='Force encoding to specified value. See WARNING.')]
600
def run(self, to_root_dir, from_archive, encoding=None, verbose=False,
601
reuse_history_list=[], prefixes=None):
602
from errors import NoPyBaz
605
baz_import.baz_import(to_root_dir, from_archive, encoding,
606
verbose, reuse_history_list, prefixes)
608
print "This command is disabled. Please install PyBaz."
611
class cmd_baz_import_branch(bzrlib.commands.Command):
612
"""Import an Arch or Baz branch into a bzr branch.
614
WARNING: Encoding should not be specified unless necessary, because if you
615
specify an encoding, your converted branch will not interoperate with
616
independently-converted branches, unless the other branches were converted
617
with exactly the same encoding. Any encoding recognized by Python may
618
be specified. Aliases are not detected, so 'utf_8', 'U8', 'UTF' and 'utf8'
621
takes_args = ['to_location', 'from_branch?', 'reuse_history*']
622
takes_options = ['verbose', Option('max-count', type=int),
623
Option('encoding', type=str,
624
help='Force encoding to specified value. See WARNING.')]
626
def run(self, to_location, from_branch=None, fast=False, max_count=None,
627
encoding=None, verbose=False, dry_run=False,
628
reuse_history_list=[]):
629
from errors import NoPyBaz
632
baz_import.baz_import_branch(to_location, from_branch, fast,
633
max_count, verbose, encoding, dry_run,
636
print "This command is disabled. Please install PyBaz."
639
class cmd_rspush(bzrlib.commands.Command):
547
class cmd_rspush(BzrToolsCommand):
640
548
"""Upload this branch to another location using rsync.
642
If no location is specified, the last-used location will be used. To
643
prevent dirty trees from being uploaded, rspush will error out if there are
644
unknown files or local changes. It will also error out if the upstream
645
directory is non-empty and not an earlier version of the branch.
550
If no location is specified, the last-used location will be used. To
551
prevent dirty trees from being uploaded, rspush will error out if there are
552
unknown files or local changes. It will also error out if the upstream
553
directory is non-empty and not an earlier version of the branch.
647
555
takes_args = ['location?']
648
556
takes_options = [Option('overwrite', help='Ignore differences between'
649
' branches and overwrite unconditionally'),
557
' branches and overwrite unconditionally.'),
650
558
Option('no-tree', help='Do not push the working tree,'
651
559
' just the .bzr.')]
654
562
from bzrlib import workingtree
656
564
cur_branch = workingtree.WorkingTree.open_containing(".")[0]
657
bzrtools.rspush(cur_branch, location, overwrite=overwrite,
565
bzrtools.rspush(cur_branch, location, overwrite=overwrite,
658
566
working_tree=not no_tree)
661
class cmd_switch(bzrlib.commands.Command):
662
"""Set the branch of a lightweight checkout and update."""
664
takes_args = ['to_location']
666
def run(self, to_location):
667
from switch import cmd_switch
668
cmd_switch().run(to_location)
569
class cmd_link_tree(BzrToolsCommand):
570
"""Hardlink matching files to another tree.
572
Only files with identical content and execute bit will be linked.
574
takes_args = ['location']
576
def run(self, location):
577
from bzrlib import workingtree
578
from bzrlib.plugins.bzrtools.link_tree import link_tree
579
target_tree = workingtree.WorkingTree.open_containing(".")[0]
580
source_tree = workingtree.WorkingTree.open(location)
581
target_tree.lock_write()
583
source_tree.lock_read()
585
link_tree(target_tree, source_tree)
591
from heads import cmd_heads
673
cmd_baz_import_branch,
675
594
cmd_branch_history,
680
598
cmd_fetch_ghosts,
681
599
cmd_graph_ancestry,