16
16
# along with this program; if not, write to the Free Software
17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
Various useful plugins for working with bzr.
26
__version__ = '0.18.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 or (bzrlib_version == desired_plus and
43
bzrlib.version_info[3] == 'dev'):
46
from bzrlib.trace import warning
48
# get the message out any way we can
49
from warnings import warn as warning
50
if bzrlib_version < desired:
51
warning('Installed Bazaar version %s is too old to be used with'
53
'"Bzrtools" %s.' % (bzrlib.__version__, __version__))
54
# Not using BzrNewError, because it may not exist.
55
raise Exception, ('Version mismatch', version_info)
57
warning('Plugin "Bzrtools" is not up to date with installed Bazaar'
59
' There should be a newer version of Bzrtools available, e.g.'
61
% (bzrlib.__version__, bzrlib_version[0], bzrlib_version[1]))
62
if bzrlib_version != desired_plus:
63
raise Exception, 'Version mismatch'
66
check_bzrlib_version(version_info[:2])
68
23
from bzrlib.lazy_import import lazy_import
69
24
lazy_import(globals(), """
70
from bzrlib import help
25
from bzrlib import help, urlutils
74
from errors import CommandError, NoPyBaz
29
from command import BzrToolsCommand
30
from errors import CommandError
75
31
from patchsource import BzrPatchSource
79
35
import bzrlib.builtins
80
36
import bzrlib.commands
37
from bzrlib.branch import Branch
38
from bzrlib.bzrdir import BzrDir
81
39
from bzrlib.commands import get_cmd_object
82
40
from bzrlib.errors import BzrCommandError
83
41
import bzrlib.ignores
84
from bzrlib.option import Option
85
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__),
90
bzrlib.ignores.add_runtime_ignores(['./.shelf'])
93
class cmd_clean_tree(bzrlib.commands.Command):
94
"""Remove unwanted files from working tree.
96
By default, only unknown files, not ignored files, are deleted. Versioned
97
files are never deleted.
99
Another class is 'detritus', which includes files emitted by bzr during
100
normal operations and selftests. (The value of these files decreases with
103
If no options are specified, unknown files are deleted. Otherwise, option
104
flags are respected, and may be combined.
106
To check what clean-tree will do, use --dry-run.
108
takes_options = [Option('ignored', help='delete all ignored files.'),
109
Option('detritus', help='delete conflict files, merge'
110
' backups, and failed selftest dirs.'),
112
help='delete files unknown to bzr. (default)'),
113
Option('dry-run', help='show files to delete instead of'
115
def run(self, unknown=False, ignored=False, detritus=False, dry_run=False):
116
from clean_tree import clean_tree
117
if not (unknown or ignored or detritus):
119
clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
123
class cmd_graph_ancestry(bzrlib.commands.Command):
42
from bzrlib.trace import note
43
from bzrlib.option import Option, RegistryOption
44
from bzrlib.workingtree import WorkingTree
46
from command import BzrToolsCommand
49
class cmd_graph_ancestry(BzrToolsCommand):
124
50
"""Produce ancestry graphs using dot.
126
52
Output format is detected according to file extension. Some of the more
215
141
return patch(wt, filename, strip, silent)
218
class cmd_shelve(bzrlib.commands.Command):
144
class cmd_shelve1(BzrToolsCommand):
219
145
"""Temporarily set aside some changes from the current tree.
221
147
Shelve allows you to temporarily put changes you've made "on the shelf",
222
148
ie. out of the way, until a later time when you can bring them back from
223
the shelf with the 'unshelve' command.
149
the shelf with the 'unshelve1' command.
225
151
Shelve is intended to help separate several sets of text changes that have
226
152
been inappropriately mingled. If you just want to get rid of all changes
227
153
(text and otherwise) and you don't need to restore them later, use revert.
228
If you want to shelve all text changes at once, use shelve --all.
154
If you want to shelve all text changes at once, use shelve1 --all.
230
By default shelve asks you what you want to shelve, press '?' at the
231
prompt to get help. To shelve everything run shelve --all.
156
By default shelve1 asks you what you want to shelve, press '?' at the
157
prompt to get help. To shelve everything run shelve1 --all.
233
159
If filenames are specified, only the changes to those files will be
234
160
shelved, other files will be left untouched.
236
162
If a revision is specified, changes since that revision will be shelved.
238
164
You can put multiple items on the shelf. Normally each time you run
239
unshelve the most recently shelved changes will be reinstated. However,
165
unshelve1 the most recently shelved changes will be reinstated. However,
240
166
you can also unshelve changes in a different order by explicitly
241
specifiying which changes to unshelve. This works best when the changes
167
specifiying which changes to unshelve1. This works best when the changes
242
168
don't depend on each other.
244
170
While you have patches on the shelf you can view and manipulate them with
245
the 'shelf' command. Run 'bzr shelf -h' for more info.
171
the 'shelf1' command. Run 'bzr shelf1 -h' for more info.
248
174
takes_args = ['file*']
249
takes_options = ['message', 'revision',
250
Option('all', help='Shelve all changes without prompting'),
251
Option('no-color', help='Never display changes in color')]
175
takes_options = [Option('message',
176
help='A message to associate with the shelved changes.',
177
short_name='m', type=unicode),
179
Option('all', help='Shelve all changes without prompting.'),
180
Option('no-color', help='Never display changes in color.')]
253
182
def run(self, all=False, file_list=None, message=None, revision=None,
472
403
takes_options = [Option("lightweight",
473
help="Create a lightweight checkout"), 'revision']
404
help="Create a lightweight checkout."), 'revision',
405
Option('files-from', type=unicode,
406
help='Accelerate checkout using files from this'
409
help='Hard-link files from source/files-from tree'
474
411
takes_args = ["source", "target?"]
475
def run(self, source, target=None, lightweight=False, revision=None):
412
def run(self, source, target=None, lightweight=False, revision=None,
413
files_from=None, hardlink=False):
476
414
from cbranch import cbranch
477
415
return cbranch(source, target, lightweight=lightweight,
481
class cmd_branches(bzrlib.commands.Command):
416
revision=revision, files_from=files_from,
420
class cmd_branches(BzrToolsCommand):
482
421
"""Scan a location for branches"""
483
422
takes_args = ["location?"]
484
423
def run(self, location=None):
485
424
from branches import branches
486
425
return branches(location)
427
class cmd_trees(BzrToolsCommand):
428
"""Scan a location for trees"""
429
takes_args = ['location?']
430
def run(self, location='.'):
431
from bzrlib.workingtree import WorkingTree
432
from bzrlib.transport import get_transport
433
t = get_transport(location)
434
for tree in WorkingTree.find_trees(location):
435
self.outf.write('%s\n' % t.relpath(
436
tree.bzrdir.root_transport.base))
489
class cmd_multi_pull(bzrlib.commands.Command):
438
class cmd_multi_pull(BzrToolsCommand):
490
439
"""Pull all the branches under a location, e.g. a repository.
492
441
Both branches present in the directory and the branches of checkouts are
522
471
print "Pulling %s from %s" % (relpath, parent)
524
pullable.pull(Branch.open(parent))
473
branch_t = get_transport(parent, possible_transports)
474
pullable.pull(Branch.open_from_transport(branch_t))
525
475
except Exception, e:
529
class cmd_branch_mark(bzrlib.commands.Command):
531
Add, view or list branch markers <EXPERIMENTAL>
533
To add a mark, do 'bzr branch-mark MARK'.
534
To list marks, do 'bzr branch-mark' (this lists all marks for the branch's
536
To delete a mark, do 'bzr branch-mark --delete MARK'
538
These marks can be used to track a branch's status.
540
takes_args = ['mark?', 'branch?']
541
takes_options = [Option('delete', help='Delete this mark')]
542
def run(self, mark=None, branch=None, delete=False):
543
from branch_mark import branch_mark
544
branch_mark(mark, branch, delete)
547
class cmd_import(bzrlib.commands.Command):
480
class cmd_import(BzrToolsCommand):
548
481
"""Import sources from a directory, tarball or zip file
550
483
This command will import a directory, tarball or zip file into a bzr
564
497
do_import(source, tree)
567
class cmd_cdiff(bzrlib.commands.Command):
500
class cmd_cdiff(BzrToolsCommand):
568
501
"""A color version of bzr's diff"""
569
502
takes_args = property(lambda x: get_cmd_object('diff').takes_args)
571
def _takes_options(self):
572
options = list(get_cmd_object('diff').takes_options)
573
options.append(Option('check-style',
503
takes_options = list(get_cmd_object('diff').takes_options) + [
504
RegistryOption.from_kwargs('color',
505
'Color mode to use.',
506
title='Color Mode', value_switches=False, enum_switch=True,
507
never='Never colorize output.',
508
auto='Only colorize output if terminal supports it and STDOUT is a'
510
always='Always colorize output (default).'),
511
Option('check-style',
574
512
help='Warn if trailing whitespace or spurious changes have been'
578
takes_options = property(_takes_options)
580
def run(self, check_style=False, *args, **kwargs):
515
def run(self, color='always', check_style=False, *args, **kwargs):
581
516
from colordiff import colordiff
582
colordiff(check_style, *args, **kwargs)
585
class cmd_baz_import(bzrlib.commands.Command):
586
"""Import an Arch or Baz archive into a bzr repository.
588
This command should be used on local archives (or mirrors) only. It is
589
quite slow on remote archives.
591
reuse_history allows you to specify any previous imports you
592
have done of different archives, which this archive has branches
593
tagged from. This will dramatically reduce the time to convert
594
the archive as it will not have to convert the history already
595
converted in that other branch.
597
If you specify prefixes, only branches whose names start with that prefix
598
will be imported. Skipped branches will be listed, so you can import any
599
branches you missed by accident. Here's an example of doing a partial
600
import from thelove@canonical.com:
601
bzr baz-import thelove thelove@canonical.com --prefixes dists:talloc-except
603
WARNING: Encoding should not be specified unless necessary, because if you
604
specify an encoding, your converted branch will not interoperate with
605
independently-converted branches, unless the other branches were converted
606
with exactly the same encoding. Any encoding recognized by Python may
607
be specified. Aliases are not detected, so 'utf_8', 'U8', 'UTF' and 'utf8'
610
takes_args = ['to_root_dir', 'from_archive', 'reuse_history*']
611
takes_options = ['verbose', Option('prefixes', type=str,
612
help="Prefixes of branches to import, colon-separated"),
613
Option('encoding', type=str,
614
help='Force encoding to specified value. See WARNING.')]
616
def run(self, to_root_dir, from_archive, encoding=None, verbose=False,
617
reuse_history_list=[], prefixes=None):
618
from errors import NoPyBaz
621
baz_import.baz_import(to_root_dir, from_archive, encoding,
622
verbose, reuse_history_list, prefixes)
624
print "This command is disabled. Please install PyBaz."
627
class cmd_baz_import_branch(bzrlib.commands.Command):
628
"""Import an Arch or Baz branch into a bzr branch.
630
WARNING: Encoding should not be specified unless necessary, because if you
631
specify an encoding, your converted branch will not interoperate with
632
independently-converted branches, unless the other branches were converted
633
with exactly the same encoding. Any encoding recognized by Python may
634
be specified. Aliases are not detected, so 'utf_8', 'U8', 'UTF' and 'utf8'
637
takes_args = ['to_location', 'from_branch?', 'reuse_history*']
638
takes_options = ['verbose', Option('max-count', type=int),
639
Option('encoding', type=str,
640
help='Force encoding to specified value. See WARNING.')]
642
def run(self, to_location, from_branch=None, fast=False, max_count=None,
643
encoding=None, verbose=False, dry_run=False,
644
reuse_history_list=[]):
645
from errors import NoPyBaz
648
baz_import.baz_import_branch(to_location, from_branch, fast,
649
max_count, verbose, encoding, dry_run,
652
print "This command is disabled. Please install PyBaz."
655
class cmd_rspush(bzrlib.commands.Command):
517
colordiff(color, check_style, *args, **kwargs)
520
class cmd_conflict_diff(BzrToolsCommand):
522
"""Compare a conflicted file against BASE."""
524
encoding_type = 'exact'
525
takes_args = ['file']
527
RegistryOption.from_kwargs('direction', 'Direction of comparison.',
528
value_switches=True, enum_switch=False,
529
other='Compare OTHER against common base.',
530
this='Compare THIS against common base.')]
532
def run(self, file, direction='other'):
533
from bzrlib.plugins.bzrtools.colordiff import DiffWriter
534
from conflict_diff import conflict_diff
535
dw = DiffWriter(self.outf, check_style=False, color='auto')
536
conflict_diff(dw, file, direction)
539
class cmd_rspush(BzrToolsCommand):
656
540
"""Upload this branch to another location using rsync.
658
542
If no location is specified, the last-used location will be used. To
674
558
working_tree=not no_tree)
677
class cmd_switch(bzrlib.commands.Command):
678
"""Set the branch of a lightweight checkout and update."""
680
takes_args = ['to_location']
682
def run(self, to_location):
683
from switch import cmd_switch
684
cmd_switch().run(to_location)
689
cmd_baz_import_branch,
711
if hasattr(bzrlib.commands, 'register_command'):
712
for command in commands:
713
bzrlib.commands.register_command(command)
717
from bzrlib.tests.TestUtil import TestLoader
719
from doctest import DocTestSuite, ELLIPSIS
720
from unittest import TestSuite
722
import tests.clean_tree
723
import tests.is_clean
724
import tests.upstream_import
726
import tests.blackbox
727
import tests.shelf_tests
729
result.addTest(DocTestSuite(bzrtools, optionflags=ELLIPSIS))
730
result.addTest(tests.clean_tree.test_suite())
733
result.addTest(DocTestSuite(baz_import))
736
result.addTest(tests.test_suite())
737
result.addTest(TestLoader().loadTestsFromModule(tests.shelf_tests))
738
result.addTest(tests.blackbox.test_suite())
739
result.addTest(tests.upstream_import.test_suite())
740
result.addTest(zap.test_suite())
741
result.addTest(TestLoader().loadTestsFromModule(tests.is_clean))
561
class cmd_link_tree(BzrToolsCommand):
562
"""Hardlink matching files to another tree.
564
Only files with identical content and execute bit will be linked.
566
takes_args = ['location']
568
def run(self, location):
569
from bzrlib import workingtree
570
from bzrlib.plugins.bzrtools.link_tree import link_tree
571
target_tree = workingtree.WorkingTree.open_containing(".")[0]
572
source_tree = workingtree.WorkingTree.open(location)
573
target_tree.lock_write()
575
source_tree.lock_read()
577
link_tree(target_tree, source_tree)