71
74
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
77
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
74
78
def tree_files(file_list, default_branch=u'.', canonicalize=True,
77
return internal_tree_files(file_list, default_branch, canonicalize,
79
except errors.FileInWrongBranch, e:
80
raise errors.BzrCommandError("%s is not in the same branch as %s" %
81
(e.path, file_list[0]))
80
return internal_tree_files(file_list, default_branch, canonicalize,
84
84
def tree_files_for_add(file_list):
149
149
# XXX: Bad function name; should possibly also be a class method of
150
150
# WorkingTree rather than a function.
151
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
151
152
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
152
153
apply_view=True):
153
154
"""Convert command-line paths to a WorkingTree and relative paths.
156
Deprecated: use WorkingTree.open_containing_paths instead.
155
158
This is typically used for command-line processors that take one or
156
159
more filenames, and infer the workingtree that contains them.
168
171
:return: workingtree, [relative_paths]
170
if file_list is None or len(file_list) == 0:
171
tree = WorkingTree.open_containing(default_branch)[0]
172
if tree.supports_views() and apply_view:
173
view_files = tree.views.lookup_view()
175
file_list = view_files
176
view_str = views.view_display_str(view_files)
177
note("Ignoring files outside view. View is %s" % view_str)
178
return tree, file_list
179
tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
180
return tree, safe_relpath_files(tree, file_list, canonicalize,
181
apply_view=apply_view)
184
def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
185
"""Convert file_list into a list of relpaths in tree.
187
:param tree: A tree to operate on.
188
:param file_list: A list of user provided paths or None.
189
:param apply_view: if True and a view is set, apply it or check that
190
specified files are within it
191
:return: A list of relative paths.
192
:raises errors.PathNotChild: When a provided path is in a different tree
195
if file_list is None:
197
if tree.supports_views() and apply_view:
198
view_files = tree.views.lookup_view()
202
# tree.relpath exists as a "thunk" to osutils, but canonical_relpath
203
# doesn't - fix that up here before we enter the loop.
205
fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
208
for filename in file_list:
210
relpath = fixer(osutils.dereference_path(filename))
211
if view_files and not osutils.is_inside_any(view_files, relpath):
212
raise errors.FileOutsideView(filename, view_files)
213
new_list.append(relpath)
214
except errors.PathNotChild:
215
raise errors.FileInWrongBranch(tree.branch, filename)
173
return WorkingTree.open_containing_paths(
174
file_list, default_directory='.',
219
179
def _get_view_info_for_change_reporter(tree):
191
def _open_directory_or_containing_tree_or_branch(filename, directory):
192
"""Open the tree or branch containing the specified file, unless
193
the --directory option is used to specify a different branch."""
194
if directory is not None:
195
return (None, Branch.open(directory), filename)
196
return bzrdir.BzrDir.open_containing_tree_or_branch(filename)
231
199
# TODO: Make sure no commands unconditionally use the working directory as a
232
200
# branch. If a filename argument is used, the first of them should be used to
233
201
# specify the branch. (Perhaps this can be factored out into some kind of
338
306
takes_args = ['revision_id?']
339
takes_options = ['revision']
307
takes_options = ['directory', 'revision']
340
308
# cat-revision is more for frontends so should be exact
341
309
encoding = 'strict'
311
def print_revision(self, revisions, revid):
312
stream = revisions.get_record_stream([(revid,)], 'unordered', True)
313
record = stream.next()
314
if record.storage_kind == 'absent':
315
raise errors.NoSuchRevision(revisions, revid)
316
revtext = record.get_bytes_as('fulltext')
317
self.outf.write(revtext.decode('utf-8'))
344
def run(self, revision_id=None, revision=None):
320
def run(self, revision_id=None, revision=None, directory=u'.'):
345
321
if revision_id is not None and revision is not None:
346
322
raise errors.BzrCommandError('You can only supply one of'
347
323
' revision_id or --revision')
348
324
if revision_id is None and revision is None:
349
325
raise errors.BzrCommandError('You must supply either'
350
326
' --revision or a revision_id')
351
b = WorkingTree.open_containing(u'.')[0].branch
353
# TODO: jam 20060112 should cat-revision always output utf-8?
354
if revision_id is not None:
355
revision_id = osutils.safe_revision_id(revision_id, warn=False)
357
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
358
except errors.NoSuchRevision:
359
msg = "The repository %s contains no revision %s." % (b.repository.base,
361
raise errors.BzrCommandError(msg)
362
elif revision is not None:
365
raise errors.BzrCommandError('You cannot specify a NULL'
367
rev_id = rev.as_revision_id(b)
368
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
327
b = WorkingTree.open_containing(directory)[0].branch
329
revisions = b.repository.revisions
330
if revisions is None:
331
raise errors.BzrCommandError('Repository %r does not support '
332
'access to raw revision texts')
334
b.repository.lock_read()
336
# TODO: jam 20060112 should cat-revision always output utf-8?
337
if revision_id is not None:
338
revision_id = osutils.safe_revision_id(revision_id, warn=False)
340
self.print_revision(revisions, revision_id)
341
except errors.NoSuchRevision:
342
msg = "The repository %s contains no revision %s." % (
343
b.repository.base, revision_id)
344
raise errors.BzrCommandError(msg)
345
elif revision is not None:
348
raise errors.BzrCommandError(
349
'You cannot specify a NULL revision.')
350
rev_id = rev.as_revision_id(b)
351
self.print_revision(revisions, rev_id)
353
b.repository.unlock()
371
356
class cmd_dump_btree(Command):
372
"""Dump the contents of a btree index file to stdout.
357
__doc__ = """Dump the contents of a btree index file to stdout.
374
359
PATH is a btree index file, it can be any URL. This includes things like
375
360
.bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
439
424
for node in bt.iter_all_entries():
440
425
# Node is made up of:
441
426
# (index, key, value, [references])
442
refs_as_tuples = static_tuple.as_tuples(node[3])
430
refs_as_tuples = None
432
refs_as_tuples = static_tuple.as_tuples(refs)
443
433
as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
444
434
self.outf.write('%s\n' % (as_tuple,))
447
437
class cmd_remove_tree(Command):
448
"""Remove the working tree from a given branch/checkout.
438
__doc__ = """Remove the working tree from a given branch/checkout.
450
440
Since a lightweight checkout is little more than a working tree
451
441
this will refuse to run against one.
478
468
if (working.has_changes()):
479
469
raise errors.UncommittedChanges(working)
470
if working.get_shelf_manager().last_shelf() is not None:
471
raise errors.ShelvedChanges(working)
481
working_path = working.bzrdir.root_transport.base
482
branch_path = working.branch.bzrdir.root_transport.base
483
if working_path != branch_path:
473
if working.user_url != working.branch.user_url:
484
474
raise errors.BzrCommandError("You cannot remove the working tree"
485
475
" from a lightweight checkout")
516
505
revno = ".".join(str(n) for n in revno_t)
518
507
b = Branch.open_containing(location)[0]
520
self.add_cleanup(b.unlock)
508
self.add_cleanup(b.lock_read().unlock)
521
509
revno = b.revno()
522
510
self.cleanup_now()
523
511
self.outf.write(str(revno) + '\n')
526
514
class cmd_revision_info(Command):
527
"""Show revision number and revision id for a given revision identifier.
515
__doc__ = """Show revision number and revision id for a given revision identifier.
530
518
takes_args = ['revision_info*']
531
519
takes_options = [
521
custom_help('directory',
534
522
help='Branch to examine, '
535
'rather than the one containing the working directory.',
523
'rather than the one containing the working directory.'),
539
524
Option('tree', help='Show revno of working tree'),
683
665
def run(self, dir_list):
684
666
for d in dir_list:
686
667
wt, dd = WorkingTree.open_containing(d)
688
self.outf.write('added %s\n' % d)
668
base = os.path.dirname(dd)
669
id = wt.path2id(base)
673
self.outf.write('added %s\n' % d)
675
raise errors.NotVersionedError(path=base)
691
678
class cmd_relpath(Command):
692
"""Show path of a file relative to root"""
679
__doc__ = """Show path of a file relative to root"""
694
681
takes_args = ['filename']
730
717
raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
732
719
revision = _get_one_revision('inventory', revision)
733
work_tree, file_list = tree_files(file_list)
734
work_tree.lock_read()
735
self.add_cleanup(work_tree.unlock)
720
work_tree, file_list = WorkingTree.open_containing_paths(file_list)
721
self.add_cleanup(work_tree.lock_read().unlock)
736
722
if revision is not None:
737
723
tree = revision.as_tree(work_tree.branch)
739
725
extra_trees = [work_tree]
741
self.add_cleanup(tree.unlock)
726
self.add_cleanup(tree.lock_read().unlock)
804
789
if len(names_list) < 2:
805
790
raise errors.BzrCommandError("missing file argument")
806
tree, rel_names = tree_files(names_list, canonicalize=False)
807
tree.lock_tree_write()
808
self.add_cleanup(tree.unlock)
791
tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
792
self.add_cleanup(tree.lock_tree_write().unlock)
809
793
self._run(tree, names_list, rel_names, after)
811
795
def run_auto(self, names_list, after, dry_run):
816
800
raise errors.BzrCommandError('--after cannot be specified with'
818
work_tree, file_list = tree_files(names_list, default_branch='.')
819
work_tree.lock_tree_write()
820
self.add_cleanup(work_tree.unlock)
802
work_tree, file_list = WorkingTree.open_containing_paths(
803
names_list, default_directory='.')
804
self.add_cleanup(work_tree.lock_tree_write().unlock)
821
805
rename_map.RenameMap.guess_renames(work_tree, dry_run)
823
807
def _run(self, tree, names_list, rel_names, after):
931
915
takes_options = ['remember', 'overwrite', 'revision',
932
916
custom_help('verbose',
933
917
help='Show logs of pulled revisions.'),
918
custom_help('directory',
935
919
help='Branch to pull into, '
936
'rather than the one containing the working directory.',
920
'rather than the one containing the working directory.'),
941
922
help="Perform a local pull in a bound "
942
923
"branch. Local pulls are not applied to "
997
980
branch_from = Branch.open(location,
998
981
possible_transports=possible_transports)
982
self.add_cleanup(branch_from.lock_read().unlock)
1000
984
if branch_to.get_parent() is None or remember:
1001
985
branch_to.set_parent(branch_from.base)
1003
if branch_from is not branch_to:
1004
branch_from.lock_read()
1005
self.add_cleanup(branch_from.unlock)
1006
987
if revision is not None:
1007
988
revision_id = revision.as_revision_id(branch_from)
1009
branch_to.lock_write()
1010
self.add_cleanup(branch_to.unlock)
1011
990
if tree_to is not None:
1012
991
view_info = _get_view_info_for_change_reporter(tree_to)
1013
992
change_reporter = delta._ChangeReporter(
1058
1037
Option('create-prefix',
1059
1038
help='Create the path leading up to the branch '
1060
1039
'if it does not already exist.'),
1040
custom_help('directory',
1062
1041
help='Branch to push from, '
1063
'rather than the one containing the working directory.',
1042
'rather than the one containing the working directory.'),
1067
1043
Option('use-existing-dir',
1068
1044
help='By default push will fail if the target'
1069
1045
' directory exists, but does not already'
1095
1071
# Get the source branch
1096
1072
(tree, br_from,
1097
1073
_unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
1099
strict = br_from.get_config().get_user_option_as_bool('push_strict')
1100
if strict is None: strict = True # default value
1101
1074
# Get the tip's revision_id
1102
1075
revision = _get_one_revision('push', revision)
1103
1076
if revision is not None:
1104
1077
revision_id = revision.in_history(br_from).rev_id
1106
1079
revision_id = None
1107
if strict and tree is not None and revision_id is None:
1108
if (tree.has_changes()):
1109
raise errors.UncommittedChanges(
1110
tree, more='Use --no-strict to force the push.')
1111
if tree.last_revision() != tree.branch.last_revision():
1112
# The tree has lost sync with its branch, there is little
1113
# chance that the user is aware of it but he can still force
1114
# the push with --no-strict
1115
raise errors.OutOfDateTree(
1116
tree, more='Use --no-strict to force the push.')
1080
if tree is not None and revision_id is None:
1081
tree.check_changed_or_out_of_date(
1082
strict, 'push_strict',
1083
more_error='Use --no-strict to force the push.',
1084
more_warning='Uncommitted changes will not be pushed.')
1118
1085
# Get the stacked_on branch, if any
1119
1086
if stacked_on is not None:
1120
1087
stacked_on = urlutils.normalize_url(stacked_on)
1168
1135
_see_also = ['checkout']
1169
1136
takes_args = ['from_location', 'to_location?']
1170
takes_options = ['revision', Option('hardlink',
1171
help='Hard-link working tree files where possible.'),
1137
takes_options = ['revision',
1138
Option('hardlink', help='Hard-link working tree files where possible.'),
1139
Option('files-from', type=str,
1140
help="Get file contents from this tree."),
1172
1141
Option('no-tree',
1173
1142
help="Create a branch without a working-tree."),
1174
1143
Option('switch',
1193
1162
def run(self, from_location, to_location=None, revision=None,
1194
1163
hardlink=False, stacked=False, standalone=False, no_tree=False,
1195
use_existing_dir=False, switch=False, bind=False):
1164
use_existing_dir=False, switch=False, bind=False,
1196
1166
from bzrlib import switch as _mod_switch
1197
1167
from bzrlib.tag import _merge_tags_if_possible
1198
1168
accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1170
if not (hardlink or files_from):
1171
# accelerator_tree is usually slower because you have to read N
1172
# files (no readahead, lots of seeks, etc), but allow the user to
1173
# explicitly request it
1174
accelerator_tree = None
1175
if files_from is not None and files_from != from_location:
1176
accelerator_tree = WorkingTree.open(files_from)
1200
1177
revision = _get_one_revision('branch', revision)
1202
self.add_cleanup(br_from.unlock)
1178
self.add_cleanup(br_from.lock_read().unlock)
1203
1179
if revision is not None:
1204
1180
revision_id = revision.as_revision_id(br_from)
1310
1286
to_location = branch_location
1311
1287
accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1312
1288
branch_location)
1289
if not (hardlink or files_from):
1290
# accelerator_tree is usually slower because you have to read N
1291
# files (no readahead, lots of seeks, etc), but allow the user to
1292
# explicitly request it
1293
accelerator_tree = None
1313
1294
revision = _get_one_revision('checkout', revision)
1314
if files_from is not None:
1295
if files_from is not None and files_from != branch_location:
1315
1296
accelerator_tree = WorkingTree.open(files_from)
1316
1297
if revision is not None:
1317
1298
revision_id = revision.as_revision_id(source)
1394
1373
master = branch.get_master_branch(
1395
1374
possible_transports=possible_transports)
1396
1375
if master is not None:
1398
1376
branch_location = master.base
1379
branch_location = tree.branch.base
1400
1380
tree.lock_tree_write()
1401
branch_location = tree.branch.base
1402
1381
self.add_cleanup(tree.unlock)
1403
1382
# get rid of the final '/' and be ready for display
1404
branch_location = urlutils.unescape_for_display(branch_location[:-1],
1383
branch_location = urlutils.unescape_for_display(
1384
branch_location.rstrip('/'),
1406
1386
existing_pending_merges = tree.get_parent_ids()[1:]
1407
1387
if master is None:
1417
1397
revision_id = branch.last_revision()
1418
1398
if revision_id == _mod_revision.ensure_null(tree.last_revision()):
1419
revno = branch.revision_id_to_revno(revision_id)
1420
note("Tree is up to date at revision %d of branch %s" %
1421
(revno, branch_location))
1399
revno = branch.revision_id_to_dotted_revno(revision_id)
1400
note("Tree is up to date at revision %s of branch %s" %
1401
('.'.join(map(str, revno)), branch_location))
1423
1403
view_info = _get_view_info_for_change_reporter(tree)
1424
1404
change_reporter = delta._ChangeReporter(
1436
1416
"bzr update --revision only works"
1437
1417
" for a revision in the branch history"
1438
1418
% (e.revision))
1439
revno = tree.branch.revision_id_to_revno(
1419
revno = tree.branch.revision_id_to_dotted_revno(
1440
1420
_mod_revision.ensure_null(tree.last_revision()))
1441
note('Updated to revision %d of branch %s' %
1442
(revno, branch_location))
1443
if tree.get_parent_ids()[1:] != existing_pending_merges:
1421
note('Updated to revision %s of branch %s' %
1422
('.'.join(map(str, revno)), branch_location))
1423
parent_ids = tree.get_parent_ids()
1424
if parent_ids[1:] and parent_ids[1:] != existing_pending_merges:
1444
1425
note('Your local commits will now show as pending merges with '
1445
1426
"'bzr status', and can be committed with 'bzr commit'.")
1446
1427
if conflicts != 0:
1496
1477
class cmd_remove(Command):
1497
"""Remove files or directories.
1478
__doc__ = """Remove files or directories.
1499
This makes bzr stop tracking changes to the specified files. bzr will delete
1500
them if they can easily be recovered using revert. If no options or
1501
parameters are given bzr will scan for files that are being tracked by bzr
1502
but missing in your tree and stop tracking them for you.
1480
This makes Bazaar stop tracking changes to the specified files. Bazaar will
1481
delete them if they can easily be recovered using revert otherwise they
1482
will be backed up (adding an extention of the form .~#~). If no options or
1483
parameters are given Bazaar will scan for files that are being tracked by
1484
Bazaar but missing in your tree and stop tracking them for you.
1504
1486
takes_args = ['file*']
1505
1487
takes_options = ['verbose',
1507
1489
RegistryOption.from_kwargs('file-deletion-strategy',
1508
1490
'The file deletion mode to be used.',
1509
1491
title='Deletion Strategy', value_switches=True, enum_switch=False,
1510
safe='Only delete files if they can be'
1511
' safely recovered (default).',
1492
safe='Backup changed files (default).',
1512
1493
keep='Delete from bzr but leave the working copy.',
1513
1494
force='Delete all the specified files, even if they can not be '
1514
1495
'recovered and even if they are non-empty directories.')]
1518
1499
def run(self, file_list, verbose=False, new=False,
1519
1500
file_deletion_strategy='safe'):
1520
tree, file_list = tree_files(file_list)
1501
tree, file_list = WorkingTree.open_containing_paths(file_list)
1522
1503
if file_list is not None:
1523
1504
file_list = [f for f in file_list]
1526
self.add_cleanup(tree.unlock)
1506
self.add_cleanup(tree.lock_write().unlock)
1527
1507
# Heuristics should probably all move into tree.remove_smart or
1613
1593
_see_also = ['check']
1614
1594
takes_args = ['branch?']
1596
Option('canonicalize-chks',
1597
help='Make sure CHKs are in canonical form (repairs '
1616
def run(self, branch="."):
1602
def run(self, branch=".", canonicalize_chks=False):
1617
1603
from bzrlib.reconcile import reconcile
1618
1604
dir = bzrdir.BzrDir.open(branch)
1605
reconcile(dir, canonicalize_chks=canonicalize_chks)
1622
1608
class cmd_revision_history(Command):
1623
"""Display the list of revision ids on a branch."""
1609
__doc__ = """Display the list of revision ids on a branch."""
1625
1611
_see_also = ['log']
1626
1612
takes_args = ['location?']
1922
1912
help='Use this command to compare files.',
1915
RegistryOption('format',
1916
help='Diff format to use.',
1917
lazy_registry=('bzrlib.diff', 'format_registry'),
1918
value_switches=False, title='Diff format'),
1926
1920
aliases = ['di', 'dif']
1927
1921
encoding_type = 'exact'
1929
1923
@display_command
1930
1924
def run(self, revision=None, file_list=None, diff_options=None,
1931
prefix=None, old=None, new=None, using=None):
1932
from bzrlib.diff import get_trees_and_branches_to_diff, show_diff_trees
1925
prefix=None, old=None, new=None, using=None, format=None):
1926
from bzrlib.diff import (get_trees_and_branches_to_diff_locked,
1934
1929
if (prefix is None) or (prefix == '0'):
1935
1930
# diff -p0 format
1949
1944
raise errors.BzrCommandError('bzr diff --revision takes exactly'
1950
1945
' one or two revision specifiers')
1947
if using is not None and format is not None:
1948
raise errors.BzrCommandError('--using and --format are mutually '
1952
1951
(old_tree, new_tree,
1953
1952
old_branch, new_branch,
1954
specific_files, extra_trees) = get_trees_and_branches_to_diff(
1955
file_list, revision, old, new, apply_view=True)
1953
specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
1954
file_list, revision, old, new, self.add_cleanup, apply_view=True)
1955
# GNU diff on Windows uses ANSI encoding for filenames
1956
path_encoding = osutils.get_diff_header_encoding()
1956
1957
return show_diff_trees(old_tree, new_tree, sys.stdout,
1957
1958
specific_files=specific_files,
1958
1959
external_diff_options=diff_options,
1959
1960
old_label=old_label, new_label=new_label,
1960
extra_trees=extra_trees, using=using)
1961
extra_trees=extra_trees,
1962
path_encoding=path_encoding,
1963
1967
class cmd_deleted(Command):
1964
"""List files deleted in the working tree.
1968
__doc__ = """List files deleted in the working tree.
1966
1970
# TODO: Show files deleted since a previous revision, or
1967
1971
# between two revisions.
1970
1974
# level of effort but possibly much less IO. (Or possibly not,
1971
1975
# if the directories are very large...)
1972
1976
_see_also = ['status', 'ls']
1973
takes_options = ['show-ids']
1977
takes_options = ['directory', 'show-ids']
1975
1979
@display_command
1976
def run(self, show_ids=False):
1977
tree = WorkingTree.open_containing(u'.')[0]
1979
self.add_cleanup(tree.unlock)
1980
def run(self, show_ids=False, directory=u'.'):
1981
tree = WorkingTree.open_containing(directory)[0]
1982
self.add_cleanup(tree.lock_read().unlock)
1980
1983
old = tree.basis_tree()
1982
self.add_cleanup(old.unlock)
1984
self.add_cleanup(old.lock_read().unlock)
1983
1985
for path, ie in old.inventory.iter_entries():
1984
1986
if not tree.has_id(ie.file_id):
1985
1987
self.outf.write(path)
1992
1994
class cmd_modified(Command):
1993
"""List files modified in working tree.
1995
__doc__ = """List files modified in working tree.
1997
1999
_see_also = ['status', 'ls']
2000
help='Write an ascii NUL (\\0) separator '
2001
'between files rather than a newline.')
2000
takes_options = ['directory', 'null']
2004
2002
@display_command
2005
def run(self, null=False):
2006
tree = WorkingTree.open_containing(u'.')[0]
2003
def run(self, null=False, directory=u'.'):
2004
tree = WorkingTree.open_containing(directory)[0]
2007
2005
td = tree.changes_from(tree.basis_tree())
2008
2006
for path, id, kind, text_modified, meta_modified in td.modified:
2015
2013
class cmd_added(Command):
2016
"""List files added in working tree.
2014
__doc__ = """List files added in working tree.
2020
2018
_see_also = ['status', 'ls']
2023
help='Write an ascii NUL (\\0) separator '
2024
'between files rather than a newline.')
2019
takes_options = ['directory', 'null']
2027
2021
@display_command
2028
def run(self, null=False):
2029
wt = WorkingTree.open_containing(u'.')[0]
2031
self.add_cleanup(wt.unlock)
2022
def run(self, null=False, directory=u'.'):
2023
wt = WorkingTree.open_containing(directory)[0]
2024
self.add_cleanup(wt.lock_read().unlock)
2032
2025
basis = wt.basis_tree()
2034
self.add_cleanup(basis.unlock)
2026
self.add_cleanup(basis.lock_read().unlock)
2035
2027
basis_inv = basis.inventory
2036
2028
inv = wt.inventory
2037
2029
for file_id in inv:
2246
2238
help='Show just the specified revision.'
2247
2239
' See also "help revisionspec".'),
2241
RegistryOption('authors',
2242
'What names to list as authors - first, all or committer.',
2244
lazy_registry=('bzrlib.log', 'author_list_registry'),
2249
2246
Option('levels',
2250
2247
short_name='n',
2251
2248
help='Number of levels to display - 0 for all, 1 for flat.',
2310
2318
# find the file ids to log and check for directory filtering
2311
2319
b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2312
revision, file_list)
2313
self.add_cleanup(b.unlock)
2320
revision, file_list, self.add_cleanup)
2314
2321
for relpath, file_id, kind in file_info_list:
2315
2322
if file_id is None:
2316
2323
raise errors.BzrCommandError(
2386
2393
direction=direction, specific_fileids=file_ids,
2387
2394
start_revision=rev1, end_revision=rev2, limit=limit,
2388
2395
message_search=message, delta_type=delta_type,
2389
diff_type=diff_type, _match_using_deltas=match_using_deltas)
2396
diff_type=diff_type, _match_using_deltas=match_using_deltas,
2397
exclude_common_ancestry=exclude_common_ancestry,
2390
2399
Logger(b, rqst).show(lf)
2411
2420
raise errors.BzrCommandError(
2412
2421
"bzr %s doesn't accept two revisions in different"
2413
2422
" branches." % command_name)
2414
rev1 = start_spec.in_history(branch)
2423
if start_spec.spec is None:
2424
# Avoid loading all the history.
2425
rev1 = RevisionInfo(branch, None, None)
2427
rev1 = start_spec.in_history(branch)
2415
2428
# Avoid loading all of history when we know a missing
2416
2429
# end of range means the last revision ...
2417
2430
if end_spec.spec is None:
2459
2472
tree, relpath = WorkingTree.open_containing(filename)
2460
2473
file_id = tree.path2id(relpath)
2461
2474
b = tree.branch
2463
self.add_cleanup(b.unlock)
2475
self.add_cleanup(b.lock_read().unlock)
2464
2476
touching_revs = log.find_touching_revisions(b, file_id)
2465
2477
for revno, revision_id, what in touching_revs:
2466
2478
self.outf.write("%6d %s\n" % (revno, what))
2469
2481
class cmd_ls(Command):
2470
"""List files in a tree.
2482
__doc__ = """List files in a tree.
2473
2485
_see_also = ['status', 'cat']
2479
2491
help='Recurse into subdirectories.'),
2480
2492
Option('from-root',
2481
2493
help='Print paths relative to the root of the branch.'),
2482
Option('unknown', help='Print unknown files.'),
2494
Option('unknown', short_name='u',
2495
help='Print unknown files.'),
2483
2496
Option('versioned', help='Print versioned files.',
2484
2497
short_name='V'),
2485
Option('ignored', help='Print ignored files.'),
2487
help='Write an ascii NUL (\\0) separator '
2488
'between files rather than a newline.'),
2498
Option('ignored', short_name='i',
2499
help='Print ignored files.'),
2500
Option('kind', short_name='k',
2490
2501
help='List entries of a particular kind: file, directory, symlink.',
2494
2507
@display_command
2495
2508
def run(self, revision=None, verbose=False,
2496
2509
recursive=False, from_root=False,
2497
2510
unknown=False, versioned=False, ignored=False,
2498
null=False, kind=None, show_ids=False, path=None):
2511
null=False, kind=None, show_ids=False, path=None, directory=None):
2500
2513
if kind and kind not in ('file', 'directory', 'symlink'):
2501
2514
raise errors.BzrCommandError('invalid kind specified')
2535
2548
view_str = views.view_display_str(view_files)
2536
2549
note("Ignoring files outside view. View is %s" % view_str)
2539
self.add_cleanup(tree.unlock)
2551
self.add_cleanup(tree.lock_read().unlock)
2540
2552
for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2541
2553
from_dir=relpath, recursive=recursive):
2542
2554
# Apply additional masking
2586
2598
class cmd_unknowns(Command):
2587
"""List unknown files.
2599
__doc__ = """List unknown files.
2591
2603
_see_also = ['ls']
2604
takes_options = ['directory']
2593
2606
@display_command
2595
for f in WorkingTree.open_containing(u'.')[0].unknowns():
2607
def run(self, directory=u'.'):
2608
for f in WorkingTree.open_containing(directory)[0].unknowns():
2596
2609
self.outf.write(osutils.quotefn(f) + '\n')
2599
2612
class cmd_ignore(Command):
2600
"""Ignore specified files or patterns.
2613
__doc__ = """Ignore specified files or patterns.
2602
2615
See ``bzr help patterns`` for details on the syntax of patterns.
2612
2625
using this command or directly by using an editor, be sure to commit
2628
Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
2629
the global ignore file can be found in the application data directory as
2630
C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
2631
Global ignores are not touched by this command. The global ignore file
2632
can be edited directly using an editor.
2615
2634
Patterns prefixed with '!' are exceptions to ignore patterns and take
2616
2635
precedence over regular ignores. Such exceptions are used to specify
2617
2636
files that should be versioned which would otherwise be ignored.
2658
2677
_see_also = ['status', 'ignored', 'patterns']
2659
2678
takes_args = ['name_pattern*']
2661
Option('old-default-rules',
2662
help='Write out the ignore rules bzr < 0.9 always used.')
2679
takes_options = ['directory',
2680
Option('default-rules',
2681
help='Display the default ignore rules that bzr uses.')
2665
def run(self, name_pattern_list=None, old_default_rules=None):
2684
def run(self, name_pattern_list=None, default_rules=None,
2666
2686
from bzrlib import ignores
2667
if old_default_rules is not None:
2668
# dump the rules and exit
2669
for pattern in ignores.OLD_DEFAULTS:
2687
if default_rules is not None:
2688
# dump the default rules and exit
2689
for pattern in ignores.USER_DEFAULTS:
2690
self.outf.write("%s\n" % pattern)
2672
2692
if not name_pattern_list:
2673
2693
raise errors.BzrCommandError("ignore requires at least one "
2674
"NAME_PATTERN or --old-default-rules")
2694
"NAME_PATTERN or --default-rules.")
2675
2695
name_pattern_list = [globbing.normalize_pattern(p)
2676
2696
for p in name_pattern_list]
2698
for p in name_pattern_list:
2699
if not globbing.Globster.is_pattern_valid(p):
2700
bad_patterns += ('\n %s' % p)
2702
msg = ('Invalid ignore pattern(s) found. %s' % bad_patterns)
2703
ui.ui_factory.show_error(msg)
2704
raise errors.InvalidPattern('')
2677
2705
for name_pattern in name_pattern_list:
2678
2706
if (name_pattern[0] == '/' or
2679
2707
(len(name_pattern) > 1 and name_pattern[1] == ':')):
2680
2708
raise errors.BzrCommandError(
2681
2709
"NAME_PATTERN should not be an absolute path")
2682
tree, relpath = WorkingTree.open_containing(u'.')
2710
tree, relpath = WorkingTree.open_containing(directory)
2683
2711
ignores.tree_ignores_add_patterns(tree, name_pattern_list)
2684
2712
ignored = globbing.Globster(name_pattern_list)
2714
self.add_cleanup(tree.lock_read().unlock)
2687
2715
for entry in tree.list_files():
2689
2717
if id is not None:
2690
2718
filename = entry[0]
2691
2719
if ignored.match(filename):
2692
matches.append(filename.encode('utf-8'))
2720
matches.append(filename)
2694
2721
if len(matches) > 0:
2695
print "Warning: the following files are version controlled and" \
2696
" match your ignore pattern:\n%s" \
2697
"\nThese files will continue to be version controlled" \
2698
" unless you 'bzr remove' them." % ("\n".join(matches),)
2722
self.outf.write("Warning: the following files are version controlled and"
2723
" match your ignore pattern:\n%s"
2724
"\nThese files will continue to be version controlled"
2725
" unless you 'bzr remove' them.\n" % ("\n".join(matches),))
2701
2728
class cmd_ignored(Command):
2702
"""List ignored files and the patterns that matched them.
2729
__doc__ = """List ignored files and the patterns that matched them.
2704
2731
List all the ignored files and the ignore pattern that caused the file to
2712
2739
encoding_type = 'replace'
2713
2740
_see_also = ['ignore', 'ls']
2741
takes_options = ['directory']
2715
2743
@display_command
2717
tree = WorkingTree.open_containing(u'.')[0]
2719
self.add_cleanup(tree.unlock)
2744
def run(self, directory=u'.'):
2745
tree = WorkingTree.open_containing(directory)[0]
2746
self.add_cleanup(tree.lock_read().unlock)
2720
2747
for path, file_class, kind, file_id, entry in tree.list_files():
2721
2748
if file_class != 'I':
2728
2755
class cmd_lookup_revision(Command):
2729
"""Lookup the revision-id from a revision-number
2756
__doc__ = """Lookup the revision-id from a revision-number
2732
2759
bzr lookup-revision 33
2735
2762
takes_args = ['revno']
2763
takes_options = ['directory']
2737
2765
@display_command
2738
def run(self, revno):
2766
def run(self, revno, directory=u'.'):
2740
2768
revno = int(revno)
2741
2769
except ValueError:
2742
raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
2744
print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
2770
raise errors.BzrCommandError("not a valid revision-number: %r"
2772
revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
2773
self.outf.write("%s\n" % revid)
2747
2776
class cmd_export(Command):
2748
"""Export current or past revision to a destination directory or archive.
2777
__doc__ = """Export current or past revision to a destination directory or archive.
2750
2779
If no revision is specified this exports the last committed revision.
2785
2814
help="Name of the root directory inside the exported file."),
2815
Option('per-file-timestamps',
2816
help='Set modification time of files to that of the last '
2817
'revision in which it was changed.'),
2787
2819
def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2788
root=None, filters=False):
2820
root=None, filters=False, per_file_timestamps=False, directory=u'.'):
2789
2821
from bzrlib.export import export
2791
2823
if branch_or_subdir is None:
2792
tree = WorkingTree.open_containing(u'.')[0]
2824
tree = WorkingTree.open_containing(directory)[0]
2793
2825
b = tree.branch
2799
2831
rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2801
export(rev_tree, dest, format, root, subdir, filtered=filters)
2833
export(rev_tree, dest, format, root, subdir, filtered=filters,
2834
per_file_timestamps=per_file_timestamps)
2802
2835
except errors.NoSuchExportFormat, e:
2803
2836
raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2806
2839
class cmd_cat(Command):
2807
"""Write the contents of a file as of a given revision to standard output.
2840
__doc__ = """Write the contents of a file as of a given revision to standard output.
2809
2842
If no revision is nominated, the last revision is used.
2825
2858
@display_command
2826
2859
def run(self, filename, revision=None, name_from_revision=False,
2860
filters=False, directory=None):
2828
2861
if revision is not None and len(revision) != 1:
2829
2862
raise errors.BzrCommandError("bzr cat --revision takes exactly"
2830
2863
" one revision specifier")
2831
2864
tree, branch, relpath = \
2832
bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2834
self.add_cleanup(branch.unlock)
2865
_open_directory_or_containing_tree_or_branch(filename, directory)
2866
self.add_cleanup(branch.lock_read().unlock)
2835
2867
return self._run(tree, branch, relpath, filename, revision,
2836
2868
name_from_revision, filters)
2892
2923
class cmd_local_time_offset(Command):
2893
"""Show the offset in seconds from GMT to local time."""
2924
__doc__ = """Show the offset in seconds from GMT to local time."""
2895
2926
@display_command
2897
print osutils.local_time_offset()
2928
self.outf.write("%s\n" % osutils.local_time_offset())
2901
2932
class cmd_commit(Command):
2902
"""Commit changes into a new revision.
2933
__doc__ = """Commit changes into a new revision.
2904
2935
An explanatory message needs to be given for each commit. This is
2905
2936
often done by using the --message option (getting the message from the
3099
3130
'(use --file "%(f)s" to take commit message from that file)'
3100
3131
% { 'f': message })
3101
3132
ui.ui_factory.show_warning(warning_msg)
3134
message = message.replace('\r\n', '\n')
3135
message = message.replace('\r', '\n')
3137
raise errors.BzrCommandError(
3138
"please specify either --message or --file")
3103
3140
def get_message(commit_obj):
3104
3141
"""Callback to get commit message"""
3105
my_message = message
3106
if my_message is not None and '\r' in my_message:
3107
my_message = my_message.replace('\r\n', '\n')
3108
my_message = my_message.replace('\r', '\n')
3109
if my_message is None and not file:
3110
t = make_commit_message_template_encoded(tree,
3145
my_message = f.read().decode(osutils.get_user_encoding())
3148
elif message is not None:
3149
my_message = message
3151
# No message supplied: make one up.
3152
# text is the status of the tree
3153
text = make_commit_message_template_encoded(tree,
3111
3154
selected_list, diff=show_diff,
3112
3155
output_encoding=osutils.get_user_encoding())
3156
# start_message is the template generated from hooks
3157
# XXX: Warning - looks like hooks return unicode,
3158
# make_commit_message_template_encoded returns user encoding.
3159
# We probably want to be using edit_commit_message instead to
3113
3161
start_message = generate_commit_message_template(commit_obj)
3114
my_message = edit_commit_message_encoded(t,
3162
my_message = edit_commit_message_encoded(text,
3115
3163
start_message=start_message)
3116
3164
if my_message is None:
3117
3165
raise errors.BzrCommandError("please specify a commit"
3118
3166
" message with either --message or --file")
3119
elif my_message and file:
3120
raise errors.BzrCommandError(
3121
"please specify either --message or --file")
3123
my_message = codecs.open(file, 'rt',
3124
osutils.get_user_encoding()).read()
3125
3167
if my_message == "":
3126
3168
raise errors.BzrCommandError("empty commit message specified")
3127
3169
return my_message
3137
3179
reporter=None, verbose=verbose, revprops=properties,
3138
3180
authors=author, timestamp=commit_stamp,
3139
3181
timezone=offset,
3140
exclude=safe_relpath_files(tree, exclude))
3182
exclude=tree.safe_relpath_files(exclude))
3141
3183
except PointlessCommit:
3142
# FIXME: This should really happen before the file is read in;
3143
# perhaps prepare the commit; get the message; then actually commit
3144
3184
raise errors.BzrCommandError("No changes to commit."
3145
3185
" Use --unchanged to commit anyhow.")
3146
3186
except ConflictsInTree:
3151
3191
raise errors.BzrCommandError("Commit refused because there are"
3152
3192
" unknown files in the working tree.")
3153
3193
except errors.BoundBranchOutOfDate, e:
3154
raise errors.BzrCommandError(str(e) + "\n"
3155
'To commit to master branch, run update and then commit.\n'
3156
'You can also pass --local to commit to continue working '
3194
e.extra_help = ("\n"
3195
'To commit to master branch, run update and then commit.\n'
3196
'You can also pass --local to commit to continue working '
3160
3201
class cmd_check(Command):
3161
"""Validate working tree structure, branch consistency and repository history.
3202
__doc__ = """Validate working tree structure, branch consistency and repository history.
3163
3204
This command checks various invariants about branch and repository storage
3164
3205
to detect data corruption or bzr bugs.
3273
3315
encoding_type = 'replace'
3275
3317
@display_command
3276
def run(self, email=False, branch=False, name=None):
3318
def run(self, email=False, branch=False, name=None, directory=None):
3277
3319
if name is None:
3278
# use branch if we're inside one; otherwise global config
3280
c = Branch.open_containing('.')[0].get_config()
3281
except errors.NotBranchError:
3282
c = config.GlobalConfig()
3320
if directory is None:
3321
# use branch if we're inside one; otherwise global config
3323
c = Branch.open_containing(u'.')[0].get_config()
3324
except errors.NotBranchError:
3325
c = config.GlobalConfig()
3327
c = Branch.open(directory).get_config()
3284
3329
self.outf.write(c.user_email() + '\n')
3296
3341
# use global config unless --branch given
3298
c = Branch.open_containing('.')[0].get_config()
3343
if directory is None:
3344
c = Branch.open_containing(u'.')[0].get_config()
3346
c = Branch.open(directory).get_config()
3300
3348
c = config.GlobalConfig()
3301
3349
c.set_user_option('email', name)
3304
3352
class cmd_nick(Command):
3305
"""Print or set the branch nickname.
3353
__doc__ = """Print or set the branch nickname.
3307
3355
If unset, the tree root directory name is used as the nickname.
3308
3356
To print the current nickname, execute with no argument.
3470
3519
'throughout the test suite.',
3471
3520
type=get_transport_type),
3472
3521
Option('benchmark',
3473
help='Run the benchmarks rather than selftests.'),
3522
help='Run the benchmarks rather than selftests.',
3474
3524
Option('lsprof-timed',
3475
3525
help='Generate lsprof output for benchmarked'
3476
3526
' sections of code.'),
3477
3527
Option('lsprof-tests',
3478
3528
help='Generate lsprof output for each test.'),
3479
Option('cache-dir', type=str,
3480
help='Cache intermediate benchmark output in this '
3482
3529
Option('first',
3483
3530
help='Run all tests, but run specified tests first.',
3484
3531
short_name='f',
3519
3566
def run(self, testspecs_list=None, verbose=False, one=False,
3520
3567
transport=None, benchmark=None,
3521
lsprof_timed=None, cache_dir=None,
3522
3569
first=False, list_only=False,
3523
3570
randomize=None, exclude=None, strict=False,
3524
3571
load_list=None, debugflag=None, starting_with=None, subunit=False,
3525
3572
parallel=None, lsprof_tests=False):
3526
3573
from bzrlib.tests import selftest
3527
import bzrlib.benchmarks as benchmarks
3528
from bzrlib.benchmarks import tree_creator
3530
3575
# Make deprecation warnings visible, unless -Werror is set
3531
3576
symbol_versioning.activate_deprecation_warnings(override=False)
3533
if cache_dir is not None:
3534
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
3535
3578
if testspecs_list is not None:
3536
3579
pattern = '|'.join(testspecs_list)
3543
3586
raise errors.BzrCommandError("subunit not available. subunit "
3544
3587
"needs to be installed to use --subunit.")
3545
3588
self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
3589
# On Windows, disable automatic conversion of '\n' to '\r\n' in
3590
# stdout, which would corrupt the subunit stream.
3591
# FIXME: This has been fixed in subunit trunk (>0.0.5) so the
3592
# following code can be deleted when it's sufficiently deployed
3593
# -- vila/mgz 20100514
3594
if (sys.platform == "win32"
3595
and getattr(sys.stdout, 'fileno', None) is not None):
3597
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
3547
3599
self.additional_selftest_args.setdefault(
3548
3600
'suite_decorators', []).append(parallel)
3550
test_suite_factory = benchmarks.test_suite
3551
# Unless user explicitly asks for quiet, be verbose in benchmarks
3552
verbose = not is_quiet()
3553
# TODO: should possibly lock the history file...
3554
benchfile = open(".perf_history", "at", buffering=1)
3555
self.add_cleanup(benchfile.close)
3557
test_suite_factory = None
3602
raise errors.BzrCommandError(
3603
"--benchmark is no longer supported from bzr 2.2; "
3604
"use bzr-usertest instead")
3605
test_suite_factory = None
3559
3606
selftest_kwargs = {"verbose": verbose,
3560
3607
"pattern": pattern,
3561
3608
"stop_on_failure": one,
3598
3644
class cmd_rocks(Command):
3599
"""Statement of optimism."""
3645
__doc__ = """Statement of optimism."""
3603
3649
@display_command
3605
print "It sure does!"
3651
self.outf.write("It sure does!\n")
3608
3654
class cmd_find_merge_base(Command):
3609
"""Find and print a base revision for merging two branches."""
3655
__doc__ = """Find and print a base revision for merging two branches."""
3610
3656
# TODO: Options to specify revisions on either side, as if
3611
3657
# merging only part of the history.
3612
3658
takes_args = ['branch', 'other']
3619
3665
branch1 = Branch.open_containing(branch)[0]
3620
3666
branch2 = Branch.open_containing(other)[0]
3622
self.add_cleanup(branch1.unlock)
3624
self.add_cleanup(branch2.unlock)
3667
self.add_cleanup(branch1.lock_read().unlock)
3668
self.add_cleanup(branch2.lock_read().unlock)
3625
3669
last1 = ensure_null(branch1.last_revision())
3626
3670
last2 = ensure_null(branch2.last_revision())
3628
3672
graph = branch1.repository.get_graph(branch2.repository)
3629
3673
base_rev_id = graph.find_unique_lca(last1, last2)
3631
print 'merge base is revision %s' % base_rev_id
3675
self.outf.write('merge base is revision %s\n' % base_rev_id)
3634
3678
class cmd_merge(Command):
3635
"""Perform a three-way merge.
3679
__doc__ = """Perform a three-way merge.
3637
3681
The source of the merge can be specified either in the form of a branch,
3638
3682
or in the form of a path to a file containing a merge directive generated
3721
3765
' completely merged into the source, pull from the'
3722
3766
' source rather than merging. When this happens,'
3723
3767
' you do not need to commit the result.'),
3768
custom_help('directory',
3725
3769
help='Branch to merge into, '
3726
'rather than the one containing the working directory.',
3770
'rather than the one containing the working directory.'),
3730
3771
Option('preview', help='Instead of merging, show a diff of the'
3732
3773
Option('interactive', help='Select changes interactively.',
3833
3873
def _do_preview(self, merger):
3834
3874
from bzrlib.diff import show_diff_trees
3835
3875
result_tree = self._get_preview(merger)
3876
path_encoding = osutils.get_diff_header_encoding()
3836
3877
show_diff_trees(merger.this_tree, result_tree, self.outf,
3837
old_label='', new_label='')
3878
old_label='', new_label='',
3879
path_encoding=path_encoding)
3839
3881
def _do_merge(self, merger, change_reporter, allow_pending, verified):
3840
3882
merger.change_reporter = change_reporter
4025
4067
def run(self, file_list=None, merge_type=None, show_base=False,
4026
4068
reprocess=False):
4069
from bzrlib.conflicts import restore
4027
4070
if merge_type is None:
4028
4071
merge_type = _mod_merge.Merge3Merger
4029
tree, file_list = tree_files(file_list)
4031
self.add_cleanup(tree.unlock)
4072
tree, file_list = WorkingTree.open_containing_paths(file_list)
4073
self.add_cleanup(tree.lock_write().unlock)
4032
4074
parents = tree.get_parent_ids()
4033
4075
if len(parents) != 2:
4034
4076
raise errors.BzrCommandError("Sorry, remerge only works after normal"
4267
4309
theirs_only=False,
4268
4310
log_format=None, long=False, short=False, line=False,
4269
4311
show_ids=False, verbose=False, this=False, other=False,
4270
include_merges=False, revision=None, my_revision=None):
4312
include_merges=False, revision=None, my_revision=None,
4271
4314
from bzrlib.missing import find_unmerged, iter_log_revisions
4272
4315
def message(s):
4273
4316
if not is_quiet():
4301
4346
remote_branch = Branch.open(other_branch)
4302
4347
if remote_branch.base == local_branch.base:
4303
4348
remote_branch = local_branch
4350
self.add_cleanup(remote_branch.lock_read().unlock)
4305
local_branch.lock_read()
4306
self.add_cleanup(local_branch.unlock)
4307
4352
local_revid_range = _revision_range_to_revid_range(
4308
4353
_get_revision_range(my_revision, local_branch,
4311
remote_branch.lock_read()
4312
self.add_cleanup(remote_branch.unlock)
4313
4356
remote_revid_range = _revision_range_to_revid_range(
4314
4357
_get_revision_range(revision,
4315
4358
remote_branch, self.name()))
4376
4418
class cmd_pack(Command):
4377
"""Compress the data within a repository."""
4419
__doc__ = """Compress the data within a repository.
4421
This operation compresses the data within a bazaar repository. As
4422
bazaar supports automatic packing of repository, this operation is
4423
normally not required to be done manually.
4425
During the pack operation, bazaar takes a backup of existing repository
4426
data, i.e. pack files. This backup is eventually removed by bazaar
4427
automatically when it is safe to do so. To save disk space by removing
4428
the backed up pack files, the --clean-obsolete-packs option may be
4431
Warning: If you use --clean-obsolete-packs and your machine crashes
4432
during or immediately after repacking, you may be left with a state
4433
where the deletion has been written to disk but the new packs have not
4434
been. In this case the repository may be unusable.
4379
4437
_see_also = ['repositories']
4380
4438
takes_args = ['branch_or_repo?']
4440
Option('clean-obsolete-packs', 'Delete obsolete packs to save disk space.'),
4382
def run(self, branch_or_repo='.'):
4443
def run(self, branch_or_repo='.', clean_obsolete_packs=False):
4383
4444
dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
4385
4446
branch = dir.open_branch()
4386
4447
repository = branch.repository
4387
4448
except errors.NotBranchError:
4388
4449
repository = dir.open_repository()
4450
repository.pack(clean_obsolete_packs=clean_obsolete_packs)
4392
4453
class cmd_plugins(Command):
4393
"""List the installed plugins.
4454
__doc__ = """List the installed plugins.
4395
4456
This command displays the list of installed plugins including
4396
4457
version of plugin and a short description of each.
4427
4488
doc = '(no description)'
4428
4489
result.append((name_ver, doc, plugin.path()))
4429
4490
for name_ver, doc, path in sorted(result):
4491
self.outf.write("%s\n" % name_ver)
4492
self.outf.write(" %s\n" % doc)
4494
self.outf.write(" %s\n" % path)
4495
self.outf.write("\n")
4437
4498
class cmd_testament(Command):
4438
"""Show testament (signing-form) of a revision."""
4499
__doc__ = """Show testament (signing-form) of a revision."""
4439
4500
takes_options = [
4441
4502
Option('long', help='Produce long-format testament.'),
4484
4544
Option('long', help='Show commit date in annotations.'),
4488
4549
encoding_type = 'exact'
4490
4551
@display_command
4491
4552
def run(self, filename, all=False, long=False, revision=None,
4553
show_ids=False, directory=None):
4493
4554
from bzrlib.annotate import annotate_file, annotate_file_tree
4494
4555
wt, branch, relpath = \
4495
bzrdir.BzrDir.open_containing_tree_or_branch(filename)
4556
_open_directory_or_containing_tree_or_branch(filename, directory)
4496
4557
if wt is not None:
4498
self.add_cleanup(wt.unlock)
4558
self.add_cleanup(wt.lock_read().unlock)
4501
self.add_cleanup(branch.unlock)
4560
self.add_cleanup(branch.lock_read().unlock)
4502
4561
tree = _get_one_revision_tree('annotate', revision, branch=branch)
4504
self.add_cleanup(tree.unlock)
4562
self.add_cleanup(tree.lock_read().unlock)
4505
4563
if wt is not None:
4506
4564
file_id = wt.path2id(relpath)
4522
4580
class cmd_re_sign(Command):
4523
"""Create a digital signature for an existing revision."""
4581
__doc__ = """Create a digital signature for an existing revision."""
4524
4582
# TODO be able to replace existing ones.
4526
4584
hidden = True # is this right ?
4527
4585
takes_args = ['revision_id*']
4528
takes_options = ['revision']
4586
takes_options = ['directory', 'revision']
4530
def run(self, revision_id_list=None, revision=None):
4588
def run(self, revision_id_list=None, revision=None, directory=u'.'):
4531
4589
if revision_id_list is not None and revision is not None:
4532
4590
raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
4533
4591
if revision_id_list is None and revision is None:
4534
4592
raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4535
b = WorkingTree.open_containing(u'.')[0].branch
4537
self.add_cleanup(b.unlock)
4593
b = WorkingTree.open_containing(directory)[0].branch
4594
self.add_cleanup(b.lock_write().unlock)
4538
4595
return self._run(b, revision_id_list, revision)
4540
4597
def _run(self, b, revision_id_list, revision):
4599
4657
_see_also = ['checkouts', 'unbind']
4600
4658
takes_args = ['location?']
4659
takes_options = ['directory']
4603
def run(self, location=None):
4604
b, relpath = Branch.open_containing(u'.')
4661
def run(self, location=None, directory=u'.'):
4662
b, relpath = Branch.open_containing(directory)
4605
4663
if location is None:
4607
4665
location = b.get_old_bound_location()
4635
4693
_see_also = ['checkouts', 'bind']
4636
4694
takes_args = []
4695
takes_options = ['directory']
4640
b, relpath = Branch.open_containing(u'.')
4697
def run(self, directory=u'.'):
4698
b, relpath = Branch.open_containing(directory)
4641
4699
if not b.unbind():
4642
4700
raise errors.BzrCommandError('Local branch is not bound')
4645
4703
class cmd_uncommit(Command):
4646
"""Remove the last committed revision.
4704
__doc__ = """Remove the last committed revision.
4648
4706
--verbose will print out what is being removed.
4649
4707
--dry-run will go through all the motions, but not actually
4689
4747
b = control.open_branch()
4691
4749
if tree is not None:
4693
self.add_cleanup(tree.unlock)
4750
self.add_cleanup(tree.lock_write().unlock)
4696
self.add_cleanup(b.unlock)
4752
self.add_cleanup(b.lock_write().unlock)
4697
4753
return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4699
4755
def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4733
4788
end_revision=last_revno)
4736
ui.ui_factory.note('Dry-run, pretending to remove the above revisions.')
4791
self.outf.write('Dry-run, pretending to remove'
4792
' the above revisions.\n')
4738
ui.ui_factory.note('The above revision(s) will be removed.')
4794
self.outf.write('The above revision(s) will be removed.\n')
4741
if not ui.ui_factory.get_boolean('Are you sure [y/N]? '):
4742
ui.ui_factory.note('Canceled')
4797
if not ui.ui_factory.get_boolean('Are you sure'):
4798
self.outf.write('Canceled')
4745
4801
mutter('Uncommitting from {%s} to {%s}',
4746
4802
last_rev_id, rev_id)
4747
4803
uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
4748
4804
revno=revno, local=local)
4749
ui.ui_factory.note('You can restore the old tip by running:\n'
4750
' bzr pull . -r revid:%s' % last_rev_id)
4805
self.outf.write('You can restore the old tip by running:\n'
4806
' bzr pull . -r revid:%s\n' % last_rev_id)
4753
4809
class cmd_break_lock(Command):
4754
"""Break a dead lock on a repository, branch or working directory.
4810
__doc__ = """Break a dead lock on a repository, branch or working directory.
4756
4812
CAUTION: Locks should only be broken when you are sure that the process
4757
4813
holding the lock has been stopped.
4843
4898
def run(self, port=None, inet=False, directory=None, allow_writes=False,
4844
4899
protocol=None):
4845
from bzrlib.transport import get_transport, transport_server_registry
4900
from bzrlib import transport
4846
4901
if directory is None:
4847
4902
directory = os.getcwd()
4848
4903
if protocol is None:
4849
protocol = transport_server_registry.get()
4904
protocol = transport.transport_server_registry.get()
4850
4905
host, port = self.get_host_and_port(port)
4851
4906
url = urlutils.local_path_to_url(directory)
4852
4907
if not allow_writes:
4853
4908
url = 'readonly+' + url
4854
transport = get_transport(url)
4855
protocol(transport, host, port, inet)
4909
t = transport.get_transport(url)
4910
protocol(t, host, port, inet)
4858
4913
class cmd_join(Command):
4859
"""Combine a tree into its containing tree.
4914
__doc__ = """Combine a tree into its containing tree.
4861
4916
This command requires the target tree to be in a rich-root format.
4969
5025
encoding_type = 'exact'
4971
5027
def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
4972
sign=False, revision=None, mail_to=None, message=None):
5028
sign=False, revision=None, mail_to=None, message=None,
4973
5030
from bzrlib.revision import ensure_null, NULL_REVISION
4974
5031
include_patch, include_bundle = {
4975
5032
'plain': (False, False),
4976
5033
'diff': (True, False),
4977
5034
'bundle': (True, True),
4979
branch = Branch.open('.')
5036
branch = Branch.open(directory)
4980
5037
stored_submit_branch = branch.get_submit_branch()
4981
5038
if submit_branch is None:
4982
5039
submit_branch = stored_submit_branch
5232
5289
To rename a tag (change the name but keep it on the same revsion), run ``bzr
5233
5290
tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
5292
If no tag name is specified it will be determined through the
5293
'automatic_tag_name' hook. This can e.g. be used to automatically tag
5294
upstream releases by reading configure.ac. See ``bzr help hooks`` for
5236
5298
_see_also = ['commit', 'tags']
5237
takes_args = ['tag_name']
5299
takes_args = ['tag_name?']
5238
5300
takes_options = [
5239
5301
Option('delete',
5240
5302
help='Delete this tag rather than placing it.',
5243
help='Branch in which to place the tag.',
5304
custom_help('directory',
5305
help='Branch in which to place the tag.'),
5247
5306
Option('force',
5248
5307
help='Replace existing tags.',
5253
def run(self, tag_name,
5312
def run(self, tag_name=None,
5259
5318
branch, relpath = Branch.open_containing(directory)
5261
self.add_cleanup(branch.unlock)
5319
self.add_cleanup(branch.lock_write().unlock)
5321
if tag_name is None:
5322
raise errors.BzrCommandError("No tag specified to delete.")
5263
5323
branch.tags.delete_tag(tag_name)
5264
5324
self.outf.write('Deleted tag %s.\n' % tag_name)
5477
5539
def run(self, to_location=None, force=False, create_branch=False,
5540
revision=None, directory=u'.'):
5479
5541
from bzrlib import switch
5542
tree_location = directory
5481
5543
revision = _get_one_revision('switch', revision)
5482
5544
control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5483
5545
if to_location is None:
5484
5546
if revision is None:
5485
5547
raise errors.BzrCommandError('You must supply either a'
5486
5548
' revision or a location')
5549
to_location = tree_location
5489
5551
branch = control_dir.open_branch()
5490
5552
had_explicit_nick = branch.get_config().has_explicit_nickname()
5712
5775
self.outf.write(" <no hooks installed>\n")
5778
class cmd_remove_branch(Command):
5779
__doc__ = """Remove a branch.
5781
This will remove the branch from the specified location but
5782
will keep any working tree or repository in place.
5786
Remove the branch at repo/trunk::
5788
bzr remove-branch repo/trunk
5792
takes_args = ["location?"]
5794
aliases = ["rmbranch"]
5796
def run(self, location=None):
5797
if location is None:
5799
branch = Branch.open_containing(location)[0]
5800
branch.bzrdir.destroy_branch()
5715
5803
class cmd_shelve(Command):
5716
"""Temporarily set aside some changes from the current tree.
5804
__doc__ = """Temporarily set aside some changes from the current tree.
5718
5806
Shelve allows you to temporarily put changes you've made "on the shelf",
5719
5807
ie. out of the way, until a later time when you can bring them back from
5754
5843
_see_also = ['unshelve']
5756
5845
def run(self, revision=None, all=False, file_list=None, message=None,
5757
writer=None, list=False, destroy=False):
5846
writer=None, list=False, destroy=False, directory=u'.'):
5759
5848
return self.run_for_list()
5760
5849
from bzrlib.shelf_ui import Shelver
5835
5924
To check what clean-tree will do, use --dry-run.
5837
takes_options = [Option('ignored', help='Delete all ignored files.'),
5926
takes_options = ['directory',
5927
Option('ignored', help='Delete all ignored files.'),
5838
5928
Option('detritus', help='Delete conflict files, merge'
5839
5929
' backups, and failed selftest dirs.'),
5840
5930
Option('unknown',
5843
5933
' deleting them.'),
5844
5934
Option('force', help='Do not prompt before deleting.')]
5845
5935
def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
5936
force=False, directory=u'.'):
5847
5937
from bzrlib.clean_tree import clean_tree
5848
5938
if not (unknown or ignored or detritus):
5852
clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
5853
dry_run=dry_run, no_prompt=force)
5942
clean_tree(directory, unknown=unknown, ignored=ignored,
5943
detritus=detritus, dry_run=dry_run, no_prompt=force)
5856
5946
class cmd_reference(Command):
5857
"""list, view and set branch locations for nested trees.
5947
__doc__ = """list, view and set branch locations for nested trees.
5859
5949
If no arguments are provided, lists the branch locations for nested trees.
5860
5950
If one argument is provided, display the branch location for that tree.
5900
5990
self.outf.write('%s %s\n' % (path, location))
5903
# these get imported and then picked up by the scan for cmd_*
5904
# TODO: Some more consistent way to split command definitions across files;
5905
# we do need to load at least some information about them to know of
5906
# aliases. ideally we would avoid loading the implementation until the
5907
# details were needed.
5908
from bzrlib.cmd_version_info import cmd_version_info
5909
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
5910
from bzrlib.bundle.commands import (
5913
from bzrlib.foreign import cmd_dpush
5914
from bzrlib.sign_my_commits import cmd_sign_my_commits
5993
def _register_lazy_builtins():
5994
# register lazy builtins from other modules; called at startup and should
5995
# be only called once.
5996
for (name, aliases, module_name) in [
5997
('cmd_bundle_info', [], 'bzrlib.bundle.commands'),
5998
('cmd_dpush', [], 'bzrlib.foreign'),
5999
('cmd_version_info', [], 'bzrlib.cmd_version_info'),
6000
('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
6001
('cmd_conflicts', [], 'bzrlib.conflicts'),
6002
('cmd_sign_my_commits', [], 'bzrlib.sign_my_commits'),
6004
builtin_command_registry.register_lazy(name, aliases, module_name)