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
26
__version__ = '0.14.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 bzr version %s is too old to be used with bzrtools'
51
' %s.' % (bzrlib.__version__, __version__))
52
# Not using BzrNewError, because it may not exist.
53
raise Exception, ('Version mismatch', version_info)
55
warning('Bzrtools is not up to date with installed bzr version %s.'
56
' \nThere should be a newer version available, e.g. %i.%i.'
57
% (bzrlib.__version__, bzrlib_version[0], bzrlib_version[1]))
58
if bzrlib_version != desired_plus:
59
raise Exception, 'Version mismatch'
62
check_bzrlib_version(version_info[:2])
33
65
from errors import CommandError, NoPyBaz
34
66
from patchsource import BzrPatchSource
67
from shelf import Shelf
38
71
import bzrlib.builtins
39
72
import bzrlib.commands
40
from bzrlib.branch import Branch
41
from bzrlib.bzrdir import BzrDir
42
73
from bzrlib.commands import get_cmd_object
43
74
from bzrlib.errors import BzrCommandError
75
from bzrlib.help import command_usage
44
76
import bzrlib.ignores
45
from bzrlib.trace import note
46
77
from bzrlib.option import Option
47
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__),
78
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__),
51
from command import BzrToolsCommand
53
83
bzrlib.ignores.add_runtime_ignores(['./.shelf'])
56
class cmd_clean_tree(BzrToolsCommand):
86
class cmd_clean_tree(bzrlib.commands.Command):
57
87
"""Remove unwanted files from working tree.
59
89
By default, only unknown files, not ignored files, are deleted. Versioned
69
99
To check what clean-tree will do, use --dry-run.
71
takes_options = [Option('ignored', help='Delete all ignored files.'),
72
Option('detritus', help='Delete conflict files, merge'
73
' backups, and failed selftest dirs.'),
75
help='Delete files unknown to bzr (default).'),
76
Option('dry-run', help='Show files to delete instead of'
101
takes_options = [Option('ignored', help='delete all ignored files.'),
102
Option('detritus', help='delete conflict files, merge'
103
' backups, and failed selftest dirs.'),
105
help='delete files unknown to bzr. (default)'),
106
Option('dry-run', help='show files to delete instead of'
77
107
' deleting them.')]
78
108
def run(self, unknown=False, ignored=False, detritus=False, dry_run=False):
79
109
from clean_tree import clean_tree
118
148
If available, rsvg is used to antialias PNG and JPEG output, but this can
119
149
be disabled with --no-antialias.
121
takes_args = ['file', 'merge_branch?']
122
takes_options = [Option('no-collapse', help="Do not skip simple nodes."),
151
takes_args = ['branch', 'file']
152
takes_options = [Option('no-collapse', help="Do not skip simple nodes"),
123
153
Option('no-antialias',
124
help="Do not use rsvg to produce antialiased output."),
125
Option('merge-branch', type=str,
126
help="Use this branch to calcuate a merge base."),
127
Option('cluster', help="Use clustered output."),
128
Option('max-distance',
129
help="Show no nodes farther than this.", type=int),
131
help='Source branch to use (default is current'
136
def run(self, file, merge_branch=None, no_collapse=False,
137
no_antialias=False, cluster=False, max_distance=100,
139
if max_distance == -1:
154
help="Do not use rsvg to produce antialiased output"),
155
Option('merge-branch', type=str,
156
help="Use this branch to calcuate a merge base"),
157
Option('cluster', help="Use clustered output.")]
158
def run(self, branch, file, no_collapse=False, no_antialias=False,
159
merge_branch=None, cluster=False):
143
162
ranking = "cluster"
145
164
ranking = "forced"
146
graph.write_ancestry_file(directory, file, not no_collapse,
147
not no_antialias, merge_branch, ranking,
148
max_distance=max_distance)
151
class cmd_fetch_ghosts(BzrToolsCommand):
165
graph.write_ancestry_file(branch, file, not no_collapse,
166
not no_antialias, merge_branch, ranking)
169
class cmd_fetch_ghosts(bzrlib.commands.Command):
152
170
"""Attempt to retrieve ghosts from another branch.
153
171
If the other branch is not supplied, the last-pulled branch is used.
155
173
aliases = ['fetch-missing']
156
174
takes_args = ['branch?']
157
takes_options = [Option('no-fix', help="Skip additional synchonization.")]
175
takes_options = [Option('no-fix')]
158
176
def run(self, branch=None, no_fix=False):
159
177
from fetch_ghosts import fetch_ghosts
160
178
fetch_ghosts(branch, no_fix)
163
181
each file name found in the patch file."""
166
class cmd_patch(BzrToolsCommand):
184
class cmd_patch(bzrlib.commands.Command):
167
185
"""Apply a named patch to the current tree.
169
187
takes_args = ['filename?']
170
takes_options = [Option('strip', type=int, help=strip_help),
171
Option('silent', help='Suppress chatter.')]
172
def run(self, filename=None, strip=None, silent=False):
188
takes_options = [Option('strip', type=int, help=strip_help)]
189
def run(self, filename=None, strip=None):
173
190
from patch import patch
174
191
from bzrlib.workingtree import WorkingTree
175
192
wt = WorkingTree.open_containing('.')[0]
176
193
if strip is None:
178
return patch(wt, filename, strip, silent)
181
class cmd_shelve(BzrToolsCommand):
195
return patch(wt, filename, strip)
198
class cmd_shelve(bzrlib.commands.Command):
182
199
"""Temporarily set aside some changes from the current tree.
184
201
Shelve allows you to temporarily put changes you've made "on the shelf",
348
359
See 'shelve' for more information.
350
361
takes_options = [
351
Option('all', help='Unshelve all changes without prompting.'),
352
Option('force', help='Force unshelving even if errors occur.'),
353
Option('no-color', help='Never display changes in color.')
362
Option('all', help='Unshelve all changes without prompting'),
363
Option('force', help='Force unshelving even if errors occur'),
364
Option('no-color', help='Never display changes in color')
355
366
takes_args = ['patch?']
356
367
def run(self, patch=None, all=False, force=False, no_color=False):
357
368
source = BzrPatchSource()
358
s = shelf.Shelf(source.base)
369
s = Shelf(source.base)
359
370
s.unshelve(source, patch, all, force, no_color)
363
class cmd_shell(BzrToolsCommand):
374
class cmd_shell(bzrlib.commands.Command):
364
375
"""Begin an interactive shell tailored for bzr.
365
376
Bzr commands can be used without typing bzr first, and will be run natively
366
377
when possible. Tab completion is tailored for bzr. The shell prompt shows
408
419
If --branch is specified, the branch will be deleted too, but only if the
409
420
the branch has no new commits (relative to its parent).
411
takes_options = [Option("branch", help="Remove associated branch from"
413
Option('force', help='Delete tree even if contents are'
422
takes_options = [Option("branch", help="Remove associtated branch from"
415
424
takes_args = ["checkout"]
416
def run(self, checkout, branch=False, force=False):
425
def run(self, checkout, branch=False):
417
426
from zap import zap
418
return zap(checkout, remove_branch=branch, allow_modified=force)
421
class cmd_cbranch(BzrToolsCommand):
427
return zap(checkout, remove_branch=branch)
430
class cmd_cbranch(bzrlib.commands.Command):
423
432
Create a new checkout, associated with a new repository branch.
425
When you cbranch, bzr looks up a target location in locations.conf, and
426
creates the branch there.
428
In your locations.conf, add the following lines:
429
[/working_directory_root]
430
cbranch_target = /branch_root
431
cbranch_target:policy = appendpath
433
This will mean that if you run "bzr cbranch foo/bar foo/baz" in the
434
working directory root, the branch will be created in
435
"/branch_root/foo/baz"
437
NOTE: cbranch also supports "cbranch_root", but that behaviour is
434
When you cbranch, bzr looks up the repository associated with your current
435
directory in locations.conf. It creates a new branch in that repository
436
with the same name and relative path as the checkout you request.
438
The locations.conf parameter is "cbranch_root". So if you want
439
cbranch operations in /home/jrandom/bigproject to produce branches in
440
/home/jrandom/bigproject/repository, you'd add this:
442
[/home/jrandom/bigproject]
443
cbranch_root = /home/jrandom/bigproject/repository
445
Note that if "/home/jrandom/bigproject/repository" isn't a repository,
446
standalone branches will be produced. Standalone branches will also
447
be produced if the source branch is in 0.7 format (or earlier).
440
takes_options = [Option("lightweight",
441
help="Create a lightweight checkout."), 'revision',
442
Option('files-from', type=unicode,
443
help='Accelerate checkout using files from this'
446
help='Hard-link files from source/files-from tree'
449
takes_options = [Option("lightweight",
450
help="Create a lightweight checkout"), 'revision']
448
451
takes_args = ["source", "target?"]
449
def run(self, source, target=None, lightweight=False, revision=None,
450
files_from=None, hardlink=False):
452
def run(self, source, target=None, lightweight=False, revision=None):
451
453
from cbranch import cbranch
452
return cbranch(source, target, lightweight=lightweight,
453
revision=revision, files_from=files_from,
457
class cmd_branches(BzrToolsCommand):
454
return cbranch(source, target, lightweight=lightweight,
458
class cmd_branches(bzrlib.commands.Command):
458
459
"""Scan a location for branches"""
459
460
takes_args = ["location?"]
460
461
def run(self, location=None):
461
462
from branches import branches
462
463
return branches(location)
464
class cmd_trees(BzrToolsCommand):
465
"""Scan a location for trees"""
466
takes_args = ['location?']
467
def run(self, location='.'):
468
from bzrlib.workingtree import WorkingTree
469
from bzrlib.transport import get_transport
470
t = get_transport(location)
471
for tree in WorkingTree.find_trees(location):
472
self.outf.write('%s\n' % t.relpath(
473
tree.bzrdir.root_transport.base))
475
class cmd_multi_pull(BzrToolsCommand):
466
class cmd_multi_pull(bzrlib.commands.Command):
476
467
"""Pull all the branches under a location, e.g. a repository.
478
469
Both branches present in the directory and the branches of checkouts are
481
472
takes_args = ["location?"]
482
473
def run(self, location=None):
474
from bzrlib.branch import Branch
483
475
from bzrlib.transport import get_transport
484
476
from bzrtools import iter_branch_tree
485
477
if location is None:
487
479
t = get_transport(location)
488
possible_transports = []
489
480
if not t.listable():
490
481
print "Can't list this type of location."
508
499
print "Pulling %s from %s" % (relpath, parent)
510
branch_t = get_transport(parent, possible_transports)
511
pullable.pull(Branch.open_from_transport(branch_t))
501
pullable.pull(Branch.open(parent))
512
502
except Exception, e:
517
class cmd_import(BzrToolsCommand):
518
"""Import sources from a directory, tarball or zip file
520
This command will import a directory, tarball or zip file into a bzr
521
tree, replacing any versioned files already present. If a directory is
522
specified, it is used as the target. If the directory does not exist, or
523
is not versioned, it is created.
506
class cmd_branch_mark(bzrlib.commands.Command):
508
Add, view or list branch markers <EXPERIMENTAL>
510
To add a mark, do 'bzr branch-mark MARK'.
511
To list marks, do 'bzr branch-mark' (this lists all marks for the branch's
513
To delete a mark, do 'bzr branch-mark --delete MARK'
515
These marks can be used to track a branch's status.
517
takes_args = ['mark?', 'branch?']
518
takes_options = [Option('delete', help='Delete this mark')]
519
def run(self, mark=None, branch=None, delete=False):
520
from branch_mark import branch_mark
521
branch_mark(mark, branch, delete)
524
class cmd_import(bzrlib.commands.Command):
525
"""Import sources from a tarball or zip file
527
This command will import a tarball or zip file into a bzr tree, replacing
528
any versioned files already present. If a directory is specified, it is
529
used as the target. If the directory does not exist, or is not versioned,
525
532
Tarballs may be gzip or bzip2 compressed. This is autodetected.
527
If the tarball or zip has a single root directory, that directory is
528
stripped when extracting the tarball. This is not done for directories.
534
If the tarball has a single root directory, that directory is stripped
535
when extracting the tarball.
531
538
takes_args = ['source', 'tree?']
532
539
def run(self, source, tree=None):
533
540
from upstream_import import do_import
534
541
do_import(source, tree)
537
class cmd_cdiff(BzrToolsCommand):
544
class cmd_cdiff(bzrlib.commands.Command):
538
545
"""A color version of bzr's diff"""
539
546
takes_args = property(lambda x: get_cmd_object('diff').takes_args)
540
takes_options = list(get_cmd_object('diff').takes_options) + [
541
Option('check-style',
542
help='Warn if trailing whitespace or spurious changes have been'
545
def run(self, check_style=False, *args, **kwargs):
547
takes_options = property(lambda x: get_cmd_object('diff').takes_options)
548
def run(*args, **kwargs):
546
549
from colordiff import colordiff
547
colordiff(check_style, *args, **kwargs)
550
class cmd_baz_import(BzrToolsCommand):
550
colordiff(*args, **kwargs)
553
class cmd_baz_import(bzrlib.commands.Command):
551
554
"""Import an Arch or Baz archive into a bzr repository.
553
556
This command should be used on local archives (or mirrors) only. It is
554
557
quite slow on remote archives.
556
reuse_history allows you to specify any previous imports you
559
reuse_history allows you to specify any previous imports you
557
560
have done of different archives, which this archive has branches
558
tagged from. This will dramatically reduce the time to convert
561
tagged from. This will dramatically reduce the time to convert
559
562
the archive as it will not have to convert the history already
560
563
converted in that other branch.
600
603
are incompatible.
602
605
takes_args = ['to_location', 'from_branch?', 'reuse_history*']
603
takes_options = ['verbose',
604
Option('max-count', type=int,
605
help='Maximim revisions to import at once.'),
606
Option('encoding', type=str,
606
takes_options = ['verbose', Option('max-count', type=int),
607
Option('encoding', type=str,
607
608
help='Force encoding to specified value. See WARNING.')]
609
610
def run(self, to_location, from_branch=None, fast=False, max_count=None,
612
613
from errors import NoPyBaz
614
615
import baz_import
615
baz_import.baz_import_branch(to_location, from_branch, fast,
616
baz_import.baz_import_branch(to_location, from_branch, fast,
616
617
max_count, verbose, encoding, dry_run,
617
618
reuse_history_list)
619
620
print "This command is disabled. Please install PyBaz."
622
class cmd_rspush(BzrToolsCommand):
623
class cmd_rspush(bzrlib.commands.Command):
623
624
"""Upload this branch to another location using rsync.
625
If no location is specified, the last-used location will be used. To
626
prevent dirty trees from being uploaded, rspush will error out if there are
627
unknown files or local changes. It will also error out if the upstream
628
directory is non-empty and not an earlier version of the branch.
626
If no location is specified, the last-used location will be used. To
627
prevent dirty trees from being uploaded, rspush will error out if there are
628
unknown files or local changes. It will also error out if the upstream
629
directory is non-empty and not an earlier version of the branch.
630
631
takes_args = ['location?']
631
632
takes_options = [Option('overwrite', help='Ignore differences between'
632
' branches and overwrite unconditionally.'),
633
' branches and overwrite unconditionally'),
633
634
Option('no-tree', help='Do not push the working tree,'
634
635
' just the .bzr.')]
637
638
from bzrlib import workingtree
639
640
cur_branch = workingtree.WorkingTree.open_containing(".")[0]
640
bzrtools.rspush(cur_branch, location, overwrite=overwrite,
641
bzrtools.rspush(cur_branch, location, overwrite=overwrite,
641
642
working_tree=not no_tree)
644
class cmd_link_tree(BzrToolsCommand):
645
"""Hardlink matching files to another tree.
647
Only files with identical content and execute bit will be linked.
649
takes_args = ['location']
651
def run(self, location):
652
from bzrlib import workingtree
653
from bzrlib.plugins.bzrtools.link_tree import link_tree
654
target_tree = workingtree.WorkingTree.open_containing(".")[0]
655
source_tree = workingtree.WorkingTree.open(location)
656
target_tree.lock_write()
658
source_tree.lock_read()
660
link_tree(target_tree, source_tree)
666
from heads import cmd_heads
645
class cmd_switch(bzrlib.commands.Command):
646
"""Set the branch of a lightweight checkout and update."""
648
takes_args = ['to_location']
650
def run(self, to_location):
651
from switch import cmd_switch
652
cmd_switch().run(to_location)
669
657
cmd_baz_import_branch,
671
659
cmd_branch_history,
675
664
cmd_fetch_ghosts,
676
665
cmd_graph_ancestry,