57
57
from bzrlib.commands import Command, display_command
58
58
from bzrlib.option import ListOption, Option, RegistryOption, custom_help
59
from bzrlib.trace import mutter, note, warning, is_quiet, info
59
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
62
62
def tree_files(file_list, default_branch=u'.'):
67
67
(e.path, file_list[0]))
70
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
75
rev_tree = tree.basis_tree()
77
rev_tree = branch.basis_tree()
79
if len(revisions) != 1:
80
raise errors.BzrCommandError(
81
'bzr %s --revision takes exactly one revision identifier' % (
83
rev_tree = revisions[0].as_tree(branch)
70
87
# XXX: Bad function name; should possibly also be a class method of
71
88
# WorkingTree rather than a function.
72
89
def internal_tree_files(file_list, default_branch=u'.'):
184
201
raise errors.BzrCommandError('bzr status --revision takes exactly'
185
202
' one or two revision specifiers')
187
tree, file_list = tree_files(file_list)
204
tree, relfile_list = tree_files(file_list)
205
# Avoid asking for specific files when that is not needed.
206
if relfile_list == ['']:
208
# Don't disable pending merges for full trees other than '.'.
209
if file_list == ['.']:
211
# A specific path within a tree was given.
212
elif relfile_list is not None:
189
214
show_tree_status(tree, show_ids=show_ids,
190
specific_files=file_list, revision=revision,
215
specific_files=relfile_list, revision=revision,
191
216
to_file=self.outf, short=short, versioned=versioned,
192
show_pending=not no_pending)
217
show_pending=(not no_pending))
195
220
class cmd_cat_revision(Command):
227
257
rev_id = rev.as_revision_id(b)
228
258
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
261
class cmd_dump_btree(Command):
262
"""Dump the contents of a btree index file to stdout.
264
PATH is a btree index file, it can be any URL. This includes things like
265
.bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
267
By default, the tuples stored in the index file will be displayed. With
268
--raw, we will uncompress the pages, but otherwise display the raw bytes
272
# TODO: Do we want to dump the internal nodes as well?
273
# TODO: It would be nice to be able to dump the un-parsed information,
274
# rather than only going through iter_all_entries. However, this is
275
# good enough for a start
277
encoding_type = 'exact'
278
takes_args = ['path']
279
takes_options = [Option('raw', help='Write the uncompressed bytes out,'
280
' rather than the parsed tuples.'),
283
def run(self, path, raw=False):
284
dirname, basename = osutils.split(path)
285
t = transport.get_transport(dirname)
287
self._dump_raw_bytes(t, basename)
289
self._dump_entries(t, basename)
291
def _get_index_and_bytes(self, trans, basename):
292
"""Create a BTreeGraphIndex and raw bytes."""
293
bt = btree_index.BTreeGraphIndex(trans, basename, None)
294
bytes = trans.get_bytes(basename)
295
bt._file = cStringIO.StringIO(bytes)
296
bt._size = len(bytes)
299
def _dump_raw_bytes(self, trans, basename):
302
# We need to parse at least the root node.
303
# This is because the first page of every row starts with an
304
# uncompressed header.
305
bt, bytes = self._get_index_and_bytes(trans, basename)
306
for page_idx, page_start in enumerate(xrange(0, len(bytes),
307
btree_index._PAGE_SIZE)):
308
page_end = min(page_start + btree_index._PAGE_SIZE, len(bytes))
309
page_bytes = bytes[page_start:page_end]
311
self.outf.write('Root node:\n')
312
header_end, data = bt._parse_header_from_bytes(page_bytes)
313
self.outf.write(page_bytes[:header_end])
315
self.outf.write('\nPage %d\n' % (page_idx,))
316
decomp_bytes = zlib.decompress(page_bytes)
317
self.outf.write(decomp_bytes)
318
self.outf.write('\n')
320
def _dump_entries(self, trans, basename):
322
st = trans.stat(basename)
323
except errors.TransportNotPossible:
324
# We can't stat, so we'll fake it because we have to do the 'get()'
326
bt, _ = self._get_index_and_bytes(trans, basename)
328
bt = btree_index.BTreeGraphIndex(trans, basename, st.st_size)
329
for node in bt.iter_all_entries():
330
# Node is made up of:
331
# (index, key, value, [references])
332
self.outf.write('%s\n' % (node[1:],))
231
335
class cmd_remove_tree(Command):
232
336
"""Remove the working tree from a given branch/checkout.
824
945
help='Create a stacked branch referring to the source branch. '
825
946
'The new branch will depend on the availability of the source '
826
947
'branch for all operations.'),
949
help='Do not use a shared repository, even if available.'),
828
951
aliases = ['get', 'clone']
830
953
def run(self, from_location, to_location=None, revision=None,
831
hardlink=False, stacked=False):
954
hardlink=False, stacked=False, standalone=False):
832
955
from bzrlib.tag import _merge_tags_if_possible
833
956
if revision is None:
834
957
revision = [None]
863
986
dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
864
987
possible_transports=[to_transport],
865
988
accelerator_tree=accelerator_tree,
866
hardlink=hardlink, stacked=stacked)
989
hardlink=hardlink, stacked=stacked,
990
force_new_repo=standalone,
991
source_branch=br_from)
867
992
branch = dir.open_branch()
868
993
except errors.NoSuchRevision:
869
994
to_transport.delete_tree('.')
976
1101
old_tree.lock_read()
978
1103
old_inv = old_tree.inventory
979
renames = list(_mod_tree.find_renames(old_inv, new_inv))
1105
iterator = tree.iter_changes(old_tree, include_unchanged=True)
1106
for f, paths, c, v, p, n, k, e in iterator:
1107
if paths[0] == paths[1]:
1111
renames.append(paths)
981
1113
for old_name, new_name in renames:
982
1114
self.outf.write("%s => %s\n" % (old_name, new_name))
1066
1198
class cmd_remove(Command):
1067
1199
"""Remove files or directories.
1069
This makes bzr stop tracking changes to the specified files and
1070
delete them if they can easily be recovered using revert.
1072
You can specify one or more files, and/or --new. If you specify --new,
1073
only 'added' files will be removed. If you specify both, then new files
1074
in the specified directories will be removed. If the directories are
1075
also new, they will also be removed.
1201
This makes bzr stop tracking changes to the specified files. bzr will delete
1202
them if they can easily be recovered using revert. If no options or
1203
parameters are given bzr will scan for files that are being tracked by bzr
1204
but missing in your tree and stop tracking them for you.
1077
1206
takes_args = ['file*']
1078
1207
takes_options = ['verbose',
1079
Option('new', help='Remove newly-added files.'),
1208
Option('new', help='Only remove files that have never been committed.'),
1080
1209
RegistryOption.from_kwargs('file-deletion-strategy',
1081
1210
'The file deletion mode to be used.',
1082
1211
title='Deletion Strategy', value_switches=True, enum_switch=False,
1095
1224
if file_list is not None:
1096
1225
file_list = [f for f in file_list]
1098
raise errors.BzrCommandError('Specify one or more files to'
1099
' remove, or use --new.')
1102
added = tree.changes_from(tree.basis_tree(),
1103
specific_files=file_list).added
1104
file_list = sorted([f[0] for f in added], reverse=True)
1105
if len(file_list) == 0:
1106
raise errors.BzrCommandError('No matching files.')
1107
tree.remove(file_list, verbose=verbose, to_file=self.outf,
1108
keep_files=file_deletion_strategy=='keep',
1109
force=file_deletion_strategy=='force')
1229
# Heuristics should probably all move into tree.remove_smart or
1232
added = tree.changes_from(tree.basis_tree(),
1233
specific_files=file_list).added
1234
file_list = sorted([f[0] for f in added], reverse=True)
1235
if len(file_list) == 0:
1236
raise errors.BzrCommandError('No matching files.')
1237
elif file_list is None:
1238
# missing files show up in iter_changes(basis) as
1239
# versioned-with-no-kind.
1241
for change in tree.iter_changes(tree.basis_tree()):
1242
# Find paths in the working tree that have no kind:
1243
if change[1][1] is not None and change[6][1] is None:
1244
missing.append(change[1][1])
1245
file_list = sorted(missing, reverse=True)
1246
file_deletion_strategy = 'keep'
1247
tree.remove(file_list, verbose=verbose, to_file=self.outf,
1248
keep_files=file_deletion_strategy=='keep',
1249
force=file_deletion_strategy=='force')
1112
1254
class cmd_file_id(Command):
1289
1431
_create_prefix(to_transport)
1292
existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1434
a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1293
1435
except errors.NotBranchError:
1294
1436
# really a NotBzrDir error...
1295
1437
create_branch = bzrdir.BzrDir.create_branch_convenience
1296
1438
branch = create_branch(to_transport.base, format=format,
1297
1439
possible_transports=[to_transport])
1440
a_bzrdir = branch.bzrdir
1299
1442
from bzrlib.transport.local import LocalTransport
1300
if existing_bzrdir.has_branch():
1443
if a_bzrdir.has_branch():
1301
1444
if (isinstance(to_transport, LocalTransport)
1302
and not existing_bzrdir.has_workingtree()):
1445
and not a_bzrdir.has_workingtree()):
1303
1446
raise errors.BranchExistsWithoutWorkingTree(location)
1304
1447
raise errors.AlreadyBranchError(location)
1306
branch = existing_bzrdir.create_branch()
1307
existing_bzrdir.create_workingtree()
1448
branch = a_bzrdir.create_branch()
1449
a_bzrdir.create_workingtree()
1308
1450
if append_revisions_only:
1310
1452
branch.set_append_revisions_only(True)
1311
1453
except errors.UpgradeRequired:
1312
1454
raise errors.BzrCommandError('This branch format cannot be set'
1313
1455
' to append-revisions-only. Try --experimental-branch6')
1457
from bzrlib.info import show_bzrdir_info
1458
show_bzrdir_info(a_bzrdir, verbose=0, outfile=self.outf)
1316
1461
class cmd_init_repository(Command):
1340
1485
takes_options = [RegistryOption('format',
1341
1486
help='Specify a format for this repository. See'
1342
1487
' "bzr help formats" for details.',
1343
registry=bzrdir.format_registry,
1344
converter=bzrdir.format_registry.make_bzrdir,
1488
lazy_registry=('bzrlib.bzrdir', 'format_registry'),
1489
converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1345
1490
value_switches=True, title='Repository format'),
1346
1491
Option('no-trees',
1347
1492
help='Branches in the repository will default to'
2022
2190
help="Name of the root directory inside the exported file."),
2024
def run(self, dest, branch=None, revision=None, format=None, root=None,
2192
def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2193
root=None, filters=False):
2026
2194
from bzrlib.export import export
2196
if branch_or_subdir is None:
2029
2197
tree = WorkingTree.open_containing(u'.')[0]
2030
2198
b = tree.branch
2032
b = Branch.open(branch)
2034
if revision is None:
2035
# should be tree.last_revision FIXME
2036
rev_id = b.last_revision()
2038
if len(revision) != 1:
2039
raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2040
rev_id = revision[0].as_revision_id(b)
2041
t = b.repository.revision_tree(rev_id)
2201
b, subdir = Branch.open_containing(branch_or_subdir)
2204
rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2043
export(t, dest, format, root, filtered=filters)
2206
export(rev_tree, dest, format, root, subdir, filtered=filters)
2044
2207
except errors.NoSuchExportFormat, e:
2045
2208
raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2083
2246
if tree is None:
2084
2247
tree = b.basis_tree()
2085
if revision is None:
2086
revision_id = b.last_revision()
2088
revision_id = revision[0].as_revision_id(b)
2248
rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2090
2250
cur_file_id = tree.path2id(relpath)
2091
rev_tree = b.repository.revision_tree(revision_id)
2092
2251
old_file_id = rev_tree.path2id(relpath)
2094
2253
if name_from_revision:
2095
2254
if old_file_id is None:
2096
raise errors.BzrCommandError("%r is not present in revision %s"
2097
% (filename, revision_id))
2255
raise errors.BzrCommandError(
2256
"%r is not present in revision %s" % (
2257
filename, rev_tree.get_revision_id()))
2099
2259
content = rev_tree.get_file_text(old_file_id)
2100
2260
elif cur_file_id is not None:
2273
2435
if my_message is None and not file:
2274
2436
t = make_commit_message_template_encoded(tree,
2275
2437
selected_list, diff=show_diff,
2276
output_encoding=bzrlib.user_encoding)
2277
my_message = edit_commit_message_encoded(t)
2438
output_encoding=osutils.get_user_encoding())
2439
start_message = generate_commit_message_template(commit_obj)
2440
my_message = edit_commit_message_encoded(t,
2441
start_message=start_message)
2278
2442
if my_message is None:
2279
2443
raise errors.BzrCommandError("please specify a commit"
2280
2444
" message with either --message or --file")
2640
2807
help='Load a test id list from a text file.'),
2641
2808
ListOption('debugflag', type=str, short_name='E',
2642
2809
help='Turn on a selftest debug flag.'),
2643
Option('starting-with', type=str, argname='TESTID',
2645
help='Load only the tests starting with TESTID.'),
2810
ListOption('starting-with', type=str, argname='TESTID',
2811
param_name='starting_with', short_name='s',
2813
'Load only the tests starting with TESTID.'),
2647
2815
encoding_type = 'replace'
3049
3222
Report if the remembered location was used.
3051
3224
stored_location = tree.branch.get_submit_branch()
3225
stored_location_type = "submit"
3052
3226
if stored_location is None:
3053
3227
stored_location = tree.branch.get_parent()
3228
stored_location_type = "parent"
3054
3229
mutter("%s", stored_location)
3055
3230
if stored_location is None:
3056
3231
raise errors.BzrCommandError("No location specified or remembered")
3057
3232
display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
3058
note(u"%s remembered location %s", verb_string, display_url)
3233
note(u"%s remembered %s location %s", verb_string,
3234
stored_location_type, display_url)
3059
3235
return stored_location
3204
3380
def run(self, revision=None, no_backup=False, file_list=None,
3205
3381
forget_merges=None):
3206
3382
tree, file_list = tree_files(file_list)
3208
tree.set_parent_ids(tree.get_parent_ids()[:1])
3210
self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3386
tree.set_parent_ids(tree.get_parent_ids()[:1])
3388
self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3213
3393
def _revert_tree_to_revision(tree, revision, file_list, no_backup):
3214
if revision is None:
3215
rev_id = tree.last_revision()
3216
elif len(revision) != 1:
3217
raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3219
rev_id = revision[0].as_revision_id(tree.branch)
3394
rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
3220
3395
pb = ui.ui_factory.nested_progress_bar()
3222
tree.revert(file_list,
3223
tree.branch.repository.revision_tree(rev_id),
3224
not no_backup, pb, report_changes=True)
3397
tree.revert(file_list, rev_tree, not no_backup, pb,
3398
report_changes=True)
3288
3462
Option('other', 'Same as --theirs-only.'),
3466
Option('include-merges', 'Show merged revisions.'),
3293
3468
encoding_type = 'replace'
3295
3470
@display_command
3296
3471
def run(self, other_branch=None, reverse=False, mine_only=False,
3297
theirs_only=False, log_format=None, long=False, short=False, line=False,
3298
show_ids=False, verbose=False, this=False, other=False):
3473
log_format=None, long=False, short=False, line=False,
3474
show_ids=False, verbose=False, this=False, other=False,
3475
include_merges=False):
3299
3476
from bzrlib.missing import find_unmerged, iter_log_revisions
3302
3482
mine_only = this
3371
3549
if mine_only and not local_extra:
3372
3550
# We checked local, and found nothing extra
3373
self.outf.write('This branch is up to date.\n')
3551
message('This branch is up to date.\n')
3374
3552
elif theirs_only and not remote_extra:
3375
3553
# We checked remote, and found nothing extra
3376
self.outf.write('Other branch is up to date.\n')
3554
message('Other branch is up to date.\n')
3377
3555
elif not (mine_only or theirs_only or local_extra or
3379
3557
# We checked both branches, and neither one had extra
3381
self.outf.write("Branches are up to date.\n")
3559
message("Branches are up to date.\n")
3383
3561
remote_branch.unlock()
3535
3707
if file_id is None:
3536
3708
raise errors.NotVersionedError(filename)
3537
3709
file_version = tree.inventory[file_id].revision
3538
annotate_file(branch, file_version, file_id, long, all, self.outf,
3710
if wt is not None and revision is None:
3711
# If there is a tree and we're not annotating historical
3712
# versions, annotate the working tree's content.
3713
annotate_file_tree(wt, file_id, self.outf, long, all,
3716
annotate_file(branch, file_version, file_id, long, all, self.outf,
3541
3719
if wt is not None:
4087
4275
(For Thunderbird 1.5, this works around some bugs.) Supported values for
4088
4276
specific clients are "evolution", "kmail", "mutt", and "thunderbird";
4089
4277
generic options are "default", "editor", "emacsclient", "mapi", and
4278
"xdg-email". Plugins may also add supported clients.
4092
4280
If mail is being sent, a to address is required. This can be supplied
4093
4281
either on the commandline, by setting the submit_to configuration
4165
4353
raise errors.BzrCommandError(
4166
4354
'--remember requires a branch to be specified.')
4167
4355
stored_submit_branch = branch.get_submit_branch()
4168
remembered_submit_branch = False
4356
remembered_submit_branch = None
4169
4357
if submit_branch is None:
4170
4358
submit_branch = stored_submit_branch
4171
remembered_submit_branch = True
4359
remembered_submit_branch = "submit"
4173
4361
if stored_submit_branch is None or remember:
4174
4362
branch.set_submit_branch(submit_branch)
4175
4363
if submit_branch is None:
4176
4364
submit_branch = branch.get_parent()
4177
remembered_submit_branch = True
4365
remembered_submit_branch = "parent"
4178
4366
if submit_branch is None:
4179
4367
raise errors.BzrCommandError('No submit branch known or'
4181
if remembered_submit_branch:
4182
note('Using saved location "%s" to determine what changes to submit.', submit_branch)
4369
if remembered_submit_branch is not None:
4370
note('Using saved %s location "%s" to determine what '
4371
'changes to submit.', remembered_submit_branch,
4184
4374
if mail_to is None:
4185
4375
submit_config = Branch.open(submit_branch).get_config()
4518
4715
from bzrlib import switch
4519
4716
tree_location = '.'
4520
4717
control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4718
branch = control_dir.open_branch()
4522
4720
to_branch = Branch.open(to_location)
4523
4721
except errors.NotBranchError:
4722
this_branch = control_dir.open_branch()
4723
# This may be a heavy checkout, where we want the master branch
4724
this_url = this_branch.get_bound_location()
4725
# If not, use a local sibling
4726
if this_url is None:
4727
this_url = this_branch.base
4524
4728
to_branch = Branch.open(
4525
control_dir.open_branch().base + '../' + to_location)
4729
urlutils.join(this_url, '..', to_location))
4526
4730
switch.switch(control_dir, to_branch, force)
4731
if branch.get_config().has_explicit_nickname():
4732
branch = control_dir.open_branch() #get the new branch!
4733
branch.nick = to_branch.nick
4527
4734
note('Switched to branch: %s',
4528
4735
urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4550
4757
self.outf.write(" <no hooks installed>\n")
4760
class cmd_shelve(Command):
4761
"""Temporarily set aside some changes from the current tree.
4763
Shelve allows you to temporarily put changes you've made "on the shelf",
4764
ie. out of the way, until a later time when you can bring them back from
4765
the shelf with the 'unshelve' command.
4767
If shelve --list is specified, previously-shelved changes are listed.
4769
Shelve is intended to help separate several sets of changes that have
4770
been inappropriately mingled. If you just want to get rid of all changes
4771
and you don't need to restore them later, use revert. If you want to
4772
shelve all text changes at once, use shelve --all.
4774
If filenames are specified, only the changes to those files will be
4775
shelved. Other files will be left untouched.
4777
If a revision is specified, changes since that revision will be shelved.
4779
You can put multiple items on the shelf, and by default, 'unshelve' will
4780
restore the most recently shelved changes.
4783
takes_args = ['file*']
4787
Option('all', help='Shelve all changes.'),
4789
RegistryOption('writer', 'Method to use for writing diffs.',
4790
bzrlib.option.diff_writer_registry,
4791
value_switches=True, enum_switch=False),
4793
Option('list', help='List shelved changes.'),
4795
_see_also = ['unshelve']
4797
def run(self, revision=None, all=False, file_list=None, message=None,
4798
writer=None, list=False):
4800
return self.run_for_list()
4801
from bzrlib.shelf_ui import Shelver
4803
writer = bzrlib.option.diff_writer_registry.get()
4805
Shelver.from_args(writer(sys.stdout), revision, all, file_list,
4807
except errors.UserAbort:
4810
def run_for_list(self):
4811
tree = WorkingTree.open_containing('.')[0]
4814
manager = tree.get_shelf_manager()
4815
shelves = manager.active_shelves()
4816
if len(shelves) == 0:
4817
note('No shelved changes.')
4819
for shelf_id in reversed(shelves):
4820
message = manager.get_metadata(shelf_id).get('message')
4822
message = '<no message>'
4823
self.outf.write('%3d: %s\n' % (shelf_id, message))
4829
class cmd_unshelve(Command):
4830
"""Restore shelved changes.
4832
By default, the most recently shelved changes are restored. However if you
4833
specify a patch by name those changes will be restored instead. This
4834
works best when the changes don't depend on each other.
4837
takes_args = ['shelf_id?']
4839
RegistryOption.from_kwargs(
4840
'action', help="The action to perform.",
4841
enum_switch=False, value_switches=True,
4842
apply="Apply changes and remove from the shelf.",
4843
dry_run="Show changes, but do not apply or remove them.",
4844
delete_only="Delete changes without applying them."
4847
_see_also = ['shelve']
4849
def run(self, shelf_id=None, action='apply'):
4850
from bzrlib.shelf_ui import Unshelver
4851
Unshelver.from_args(shelf_id, action).run()
4553
4854
def _create_prefix(cur_transport):
4554
4855
needed = [cur_transport]
4555
4856
# Recurse upwards until we can create a directory successfully