463
470
self.print_revision(revisions, revision_id)
464
471
except errors.NoSuchRevision:
466
"The repository {0} contains no revision {1}.").format(
467
b.repository.base, revision_id.decode('utf-8'))
468
raise errors.CommandError(msg)
472
msg = gettext("The repository {0} contains no revision {1}.").format(
473
b.repository.base, revision_id)
474
raise errors.BzrCommandError(msg)
469
475
elif revision is not None:
470
476
for rev in revision:
472
raise errors.CommandError(
478
raise errors.BzrCommandError(
473
479
gettext('You cannot specify a NULL revision.'))
474
480
rev_id = rev.as_revision_id(b)
475
481
self.print_revision(revisions, rev_id)
484
class cmd_dump_btree(Command):
485
__doc__ = """Dump the contents of a btree index file to stdout.
487
PATH is a btree index file, it can be any URL. This includes things like
488
.bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
490
By default, the tuples stored in the index file will be displayed. With
491
--raw, we will uncompress the pages, but otherwise display the raw bytes
495
# TODO: Do we want to dump the internal nodes as well?
496
# TODO: It would be nice to be able to dump the un-parsed information,
497
# rather than only going through iter_all_entries. However, this is
498
# good enough for a start
500
encoding_type = 'exact'
501
takes_args = ['path']
502
takes_options = [Option('raw', help='Write the uncompressed bytes out,'
503
' rather than the parsed tuples.'),
506
def run(self, path, raw=False):
507
dirname, basename = osutils.split(path)
508
t = transport.get_transport(dirname)
510
self._dump_raw_bytes(t, basename)
512
self._dump_entries(t, basename)
514
def _get_index_and_bytes(self, trans, basename):
515
"""Create a BTreeGraphIndex and raw bytes."""
516
bt = btree_index.BTreeGraphIndex(trans, basename, None)
517
bytes = trans.get_bytes(basename)
518
bt._file = BytesIO(bytes)
519
bt._size = len(bytes)
522
def _dump_raw_bytes(self, trans, basename):
525
# We need to parse at least the root node.
526
# This is because the first page of every row starts with an
527
# uncompressed header.
528
bt, bytes = self._get_index_and_bytes(trans, basename)
529
for page_idx, page_start in enumerate(range(0, len(bytes),
530
btree_index._PAGE_SIZE)):
531
page_end = min(page_start + btree_index._PAGE_SIZE, len(bytes))
532
page_bytes = bytes[page_start:page_end]
534
self.outf.write('Root node:\n')
535
header_end, data = bt._parse_header_from_bytes(page_bytes)
536
self.outf.write(page_bytes[:header_end])
538
self.outf.write('\nPage %d\n' % (page_idx,))
539
if len(page_bytes) == 0:
540
self.outf.write('(empty)\n');
542
decomp_bytes = zlib.decompress(page_bytes)
543
self.outf.write(decomp_bytes)
544
self.outf.write('\n')
546
def _dump_entries(self, trans, basename):
548
st = trans.stat(basename)
549
except errors.TransportNotPossible:
550
# We can't stat, so we'll fake it because we have to do the 'get()'
552
bt, _ = self._get_index_and_bytes(trans, basename)
554
bt = btree_index.BTreeGraphIndex(trans, basename, st.st_size)
555
for node in bt.iter_all_entries():
556
# Node is made up of:
557
# (index, key, value, [references])
561
refs_as_tuples = None
563
refs_as_tuples = static_tuple.as_tuples(refs)
564
as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
565
self.outf.write('%s\n' % (as_tuple,))
478
568
class cmd_remove_tree(Command):
479
569
__doc__ = """Remove the working tree from a given branch/checkout.
742
826
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
743
827
file_ids_from=None):
744
828
import breezy.add
745
tree, file_list = tree_files_for_add(file_list)
747
if file_ids_from is not None and not tree.supports_setting_file_ids():
749
gettext('Ignoring --file-ids-from, since the tree does not '
750
'support setting file ids.'))
754
831
if file_ids_from is not None:
756
833
base_tree, base_path = WorkingTree.open_containing(
758
835
except errors.NoWorkingTree:
759
836
base_branch, base_path = Branch.open_containing(
761
838
base_tree = base_branch.basis_tree()
763
action = breezy.add.AddFromBaseAction(
764
base_tree, base_path, to_file=self.outf,
840
action = breezy.add.AddFromBaseAction(base_tree, base_path,
841
to_file=self.outf, should_print=(not is_quiet()))
843
action = breezy.add.AddWithSkipLargeAction(to_file=self.outf,
765
844
should_print=(not is_quiet()))
767
action = breezy.add.AddWithSkipLargeAction(
768
to_file=self.outf, should_print=(not is_quiet()))
771
self.enter_context(base_tree.lock_read())
772
added, ignored = tree.smart_add(
773
file_list, not no_recurse, action=action, save=not dry_run)
847
self.add_cleanup(base_tree.lock_read().unlock)
848
tree, file_list = tree_files_for_add(file_list)
849
added, ignored = tree.smart_add(file_list, not
850
no_recurse, action=action, save=not dry_run)
774
851
self.cleanup_now()
775
852
if len(ignored) > 0:
777
854
for glob in sorted(ignored):
778
855
for path in ignored[glob]:
780
gettext("ignored {0} matching \"{1}\"\n").format(
857
gettext("ignored {0} matching \"{1}\"\n").format(
784
861
class cmd_mkdir(Command):
858
935
takes_options = [
861
Option('include-root',
862
help='Include the entry for the root of the tree, if any.'),
864
help='List entries of a particular kind: file, directory, '
939
help='List entries of a particular kind: file, directory, symlink.',
868
942
takes_args = ['file*']
871
def run(self, revision=None, show_ids=False, kind=None, include_root=False,
945
def run(self, revision=None, show_ids=False, kind=None, file_list=None):
873
946
if kind and kind not in ['file', 'directory', 'symlink']:
874
raise errors.CommandError(
875
gettext('invalid kind %r specified') % (kind,))
947
raise errors.BzrCommandError(gettext('invalid kind %r specified') % (kind,))
877
949
revision = _get_one_revision('inventory', revision)
878
950
work_tree, file_list = WorkingTree.open_containing_paths(file_list)
879
self.enter_context(work_tree.lock_read())
951
self.add_cleanup(work_tree.lock_read().unlock)
880
952
if revision is not None:
881
953
tree = revision.as_tree(work_tree.branch)
883
955
extra_trees = [work_tree]
884
self.enter_context(tree.lock_read())
956
self.add_cleanup(tree.lock_read().unlock)
889
self.enter_context(tree.lock_read())
961
self.add_cleanup(tree.lock_read().unlock)
890
962
if file_list is not None:
891
paths = tree.find_related_paths_across_trees(
892
file_list, extra_trees, require_versioned=True)
963
file_ids = tree.paths2ids(file_list, trees=extra_trees,
964
require_versioned=True)
893
965
# find_ids_across_trees may include some paths that don't
894
966
# exist in 'tree'.
895
entries = tree.iter_entries_by_dir(specific_files=paths)
967
entries = tree.iter_entries_by_dir(specific_file_ids=file_ids)
897
969
entries = tree.iter_entries_by_dir()
899
971
for path, entry in sorted(entries):
900
972
if kind and kind != entry.kind:
902
if path == "" and not include_root:
905
self.outf.write('%-50s %s\n' % (
906
path, entry.file_id.decode('utf-8')))
977
self.outf.write('%-50s %s\n' % (path, entry.file_id))
908
979
self.outf.write(path)
909
980
self.outf.write('\n')
931
1002
encoding_type = 'replace'
933
1004
def run(self, names_list):
934
1006
if names_list is None:
936
1008
if len(names_list) < 2:
937
raise errors.CommandError(gettext("missing file argument"))
938
tree, rel_names = WorkingTree.open_containing_paths(
939
names_list, canonicalize=False)
1009
raise errors.BzrCommandError(gettext("missing file argument"))
1010
tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
940
1011
for file_name in rel_names[0:-1]:
941
1012
if file_name == '':
942
raise errors.CommandError(
943
gettext("can not copy root of branch"))
944
self.enter_context(tree.lock_tree_write())
1013
raise errors.BzrCommandError(gettext("can not copy root of branch"))
1014
self.add_cleanup(tree.lock_tree_write().unlock)
945
1015
into_existing = osutils.isdir(names_list[-1])
946
1016
if not into_existing:
948
1018
(src, dst) = rel_names
949
1019
except IndexError:
950
raise errors.CommandError(
951
gettext('to copy multiple files the'
952
' destination must be a versioned'
1020
raise errors.BzrCommandError(gettext('to copy multiple files the'
1021
' destination must be a versioned'
954
1023
pairs = [(src, dst)]
957
(n, osutils.joinpath([rel_names[-1], osutils.basename(n)]))
958
for n in rel_names[:-1]]
1025
pairs = [(n, osutils.joinpath([rel_names[-1], osutils.basename(n)]))
1026
for n in rel_names[:-1]]
960
1028
for src, dst in pairs:
962
1030
src_kind = tree.stored_kind(src)
963
1031
except errors.NoSuchFile:
964
raise errors.CommandError(
965
gettext('Could not copy %s => %s: %s is not versioned.')
1032
raise errors.BzrCommandError(
1033
gettext('Could not copy %s => %s: %s is not versioned.')
967
1035
if src_kind is None:
968
raise errors.CommandError(
969
gettext('Could not copy %s => %s . %s is not versioned\\.'
1036
raise errors.BzrCommandError(
1037
gettext('Could not copy %s => %s . %s is not versioned\.'
971
1039
if src_kind == 'directory':
972
raise errors.CommandError(
1040
raise errors.BzrCommandError(
973
1041
gettext('Could not copy %s => %s . %s is a directory.'
975
1043
dst_parent = osutils.split(dst)[0]
976
1044
if dst_parent != '':
978
1046
dst_parent_kind = tree.stored_kind(dst_parent)
979
1047
except errors.NoSuchFile:
980
raise errors.CommandError(
981
gettext('Could not copy %s => %s: %s is not versioned.')
982
% (src, dst, dst_parent))
1048
raise errors.BzrCommandError(
1049
gettext('Could not copy %s => %s: %s is not versioned.')
1050
% (src, dst, dst_parent))
983
1051
if dst_parent_kind != 'directory':
984
raise errors.CommandError(
985
gettext('Could not copy to %s: %s is not a directory.')
986
% (dst_parent, dst_parent))
1052
raise errors.BzrCommandError(
1053
gettext('Could not copy to %s: %s is not a directory.')
1054
% (dst_parent, dst_parent))
988
1056
tree.copy_one(src, dst)
1024
1091
return self.run_auto(names_list, after, dry_run)
1026
raise errors.CommandError(gettext('--dry-run requires --auto.'))
1093
raise errors.BzrCommandError(gettext('--dry-run requires --auto.'))
1027
1094
if names_list is None:
1028
1095
names_list = []
1029
1096
if len(names_list) < 2:
1030
raise errors.CommandError(gettext("missing file argument"))
1031
tree, rel_names = WorkingTree.open_containing_paths(
1032
names_list, canonicalize=False)
1097
raise errors.BzrCommandError(gettext("missing file argument"))
1098
tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
1033
1099
for file_name in rel_names[0:-1]:
1034
1100
if file_name == '':
1035
raise errors.CommandError(
1036
gettext("can not move root of branch"))
1037
self.enter_context(tree.lock_tree_write())
1101
raise errors.BzrCommandError(gettext("can not move root of branch"))
1102
self.add_cleanup(tree.lock_tree_write().unlock)
1038
1103
self._run(tree, names_list, rel_names, after)
1040
1105
def run_auto(self, names_list, after, dry_run):
1041
1106
if names_list is not None and len(names_list) > 1:
1042
raise errors.CommandError(
1043
gettext('Only one path may be specified to --auto.'))
1107
raise errors.BzrCommandError(gettext('Only one path may be specified to'
1045
raise errors.CommandError(
1046
gettext('--after cannot be specified with --auto.'))
1110
raise errors.BzrCommandError(gettext('--after cannot be specified with'
1047
1112
work_tree, file_list = WorkingTree.open_containing_paths(
1048
1113
names_list, default_directory='.')
1049
self.enter_context(work_tree.lock_tree_write())
1050
rename_map.RenameMap.guess_renames(
1051
work_tree.basis_tree(), work_tree, dry_run)
1114
self.add_cleanup(work_tree.lock_tree_write().unlock)
1115
rename_map.RenameMap.guess_renames(work_tree, dry_run)
1053
1117
def _run(self, tree, names_list, rel_names, after):
1054
1118
into_existing = osutils.isdir(names_list[-1])
1311
1374
_see_also = ['pull', 'update', 'working-trees']
1312
1375
takes_options = ['remember', 'overwrite', 'verbose', 'revision',
1313
Option('create-prefix',
1314
help='Create the path leading up to the branch '
1315
'if it does not already exist.'),
1316
custom_help('directory',
1317
help='Branch to push from, '
1318
'rather than the one containing the working directory.'),
1319
Option('use-existing-dir',
1320
help='By default push will fail if the target'
1321
' directory exists, but does not already'
1322
' have a control directory. This flag will'
1323
' allow push to proceed.'),
1325
help='Create a stacked branch that references the public location '
1326
'of the parent branch.'),
1327
Option('stacked-on',
1328
help='Create a stacked branch that refers to another branch '
1329
'for the commit history. Only the work not present in the '
1330
'referenced branch is included in the branch created.',
1333
help='Refuse to push if there are uncommitted changes in'
1334
' the working tree, --no-strict disables the check.'),
1336
help="Don't populate the working tree, even for protocols"
1337
" that support it."),
1338
Option('overwrite-tags',
1339
help="Overwrite tags only."),
1340
Option('lossy', help="Allow lossy push, i.e. dropping metadata "
1341
"that can't be represented in the target.")
1376
Option('create-prefix',
1377
help='Create the path leading up to the branch '
1378
'if it does not already exist.'),
1379
custom_help('directory',
1380
help='Branch to push from, '
1381
'rather than the one containing the working directory.'),
1382
Option('use-existing-dir',
1383
help='By default push will fail if the target'
1384
' directory exists, but does not already'
1385
' have a control directory. This flag will'
1386
' allow push to proceed.'),
1388
help='Create a stacked branch that references the public location '
1389
'of the parent branch.'),
1390
Option('stacked-on',
1391
help='Create a stacked branch that refers to another branch '
1392
'for the commit history. Only the work not present in the '
1393
'referenced branch is included in the branch created.',
1396
help='Refuse to push if there are uncommitted changes in'
1397
' the working tree, --no-strict disables the check.'),
1399
help="Don't populate the working tree, even for protocols"
1400
" that support it."),
1401
Option('overwrite-tags',
1402
help="Overwrite tags only."),
1343
1404
takes_args = ['location?']
1344
1405
encoding_type = 'replace'
1346
1407
def run(self, location=None, remember=None, overwrite=False,
1347
create_prefix=False, verbose=False, revision=None,
1348
use_existing_dir=False, directory=None, stacked_on=None,
1349
stacked=False, strict=None, no_tree=False,
1350
overwrite_tags=False, lossy=False):
1351
from .location import location_to_url
1408
create_prefix=False, verbose=False, revision=None,
1409
use_existing_dir=False, directory=None, stacked_on=None,
1410
stacked=False, strict=None, no_tree=False,
1411
overwrite_tags=False):
1352
1412
from .push import _show_push_branch
1434
1492
parameter, as in "branch foo/bar -r 5".
1438
1495
_see_also = ['checkout']
1439
1496
takes_args = ['from_location', 'to_location?']
1440
1497
takes_options = ['revision',
1442
'hardlink', help='Hard-link working tree files where possible.'),
1443
Option('files-from', type=str,
1444
help="Get file contents from this tree."),
1446
help="Create a branch without a working-tree."),
1448
help="Switch the checkout in the current directory "
1449
"to the new branch."),
1451
help='Create a stacked branch referring to the source branch. '
1452
'The new branch will depend on the availability of the source '
1453
'branch for all operations.'),
1454
Option('standalone',
1455
help='Do not use a shared repository, even if available.'),
1456
Option('use-existing-dir',
1457
help='By default branch will fail if the target'
1458
' directory exists, but does not already'
1459
' have a control directory. This flag will'
1460
' allow branch to proceed.'),
1462
help="Bind new branch to from location."),
1463
Option('no-recurse-nested',
1464
help='Do not recursively check out nested trees.'),
1465
Option('colocated-branch', short_name='b',
1466
type=str, help='Name of colocated branch to sprout.'),
1498
Option('hardlink', help='Hard-link working tree files where possible.'),
1499
Option('files-from', type=text_type,
1500
help="Get file contents from this tree."),
1502
help="Create a branch without a working-tree."),
1504
help="Switch the checkout in the current directory "
1505
"to the new branch."),
1507
help='Create a stacked branch referring to the source branch. '
1508
'The new branch will depend on the availability of the source '
1509
'branch for all operations.'),
1510
Option('standalone',
1511
help='Do not use a shared repository, even if available.'),
1512
Option('use-existing-dir',
1513
help='By default branch will fail if the target'
1514
' directory exists, but does not already'
1515
' have a control directory. This flag will'
1516
' allow branch to proceed.'),
1518
help="Bind new branch to from location."),
1469
1521
def run(self, from_location, to_location=None, revision=None,
1470
1522
hardlink=False, stacked=False, standalone=False, no_tree=False,
1471
1523
use_existing_dir=False, switch=False, bind=False,
1472
files_from=None, no_recurse_nested=False, colocated_branch=None):
1473
1525
from breezy import switch as _mod_switch
1474
1526
accelerator_tree, br_from = controldir.ControlDir.open_tree_or_branch(
1475
from_location, name=colocated_branch)
1476
if no_recurse_nested:
1480
1528
if not (hardlink or files_from):
1481
1529
# accelerator_tree is usually slower because you have to read N
1482
1530
# files (no readahead, lots of seeks, etc), but allow the user to
1918
1931
class cmd_remove(Command):
1919
1932
__doc__ = """Remove files or directories.
1921
This makes Breezy stop tracking changes to the specified files. Breezy will
1934
This makes Bazaar stop tracking changes to the specified files. Bazaar will
1922
1935
delete them if they can easily be recovered using revert otherwise they
1923
1936
will be backed up (adding an extension of the form .~#~). If no options or
1924
parameters are given Breezy will scan for files that are being tracked by
1925
Breezy but missing in your tree and stop tracking them for you.
1937
parameters are given Bazaar will scan for files that are being tracked by
1938
Bazaar but missing in your tree and stop tracking them for you.
1927
1940
takes_args = ['file*']
1928
1941
takes_options = ['verbose',
1930
'new', help='Only remove files that have never been committed.'),
1931
RegistryOption.from_kwargs('file-deletion-strategy',
1932
'The file deletion mode to be used.',
1933
title='Deletion Strategy', value_switches=True, enum_switch=False,
1934
safe='Backup changed files (default).',
1935
keep='Delete from brz but leave the working copy.',
1936
no_backup='Don\'t backup changed files.'),
1942
Option('new', help='Only remove files that have never been committed.'),
1943
RegistryOption.from_kwargs('file-deletion-strategy',
1944
'The file deletion mode to be used.',
1945
title='Deletion Strategy', value_switches=True, enum_switch=False,
1946
safe='Backup changed files (default).',
1947
keep='Delete from brz but leave the working copy.',
1948
no_backup='Don\'t backup changed files.'),
1938
1950
aliases = ['rm', 'del']
1939
1951
encoding_type = 'replace'
1941
1953
def run(self, file_list, verbose=False, new=False,
1942
file_deletion_strategy='safe'):
1954
file_deletion_strategy='safe'):
1944
1956
tree, file_list = WorkingTree.open_containing_paths(file_list)
1946
1958
if file_list is not None:
1947
1959
file_list = [f for f in file_list]
1949
self.enter_context(tree.lock_write())
1961
self.add_cleanup(tree.lock_write().unlock)
1950
1962
# Heuristics should probably all move into tree.remove_smart or
1953
1965
added = tree.changes_from(tree.basis_tree(),
1954
specific_files=file_list).added
1955
file_list = sorted([f.path[1] for f in added], reverse=True)
1966
specific_files=file_list).added
1967
file_list = sorted([f[0] for f in added], reverse=True)
1956
1968
if len(file_list) == 0:
1957
raise errors.CommandError(gettext('No matching files.'))
1969
raise errors.BzrCommandError(gettext('No matching files.'))
1958
1970
elif file_list is None:
1959
1971
# missing files show up in iter_changes(basis) as
1960
1972
# versioned-with-no-kind.
1962
1974
for change in tree.iter_changes(tree.basis_tree()):
1963
1975
# Find paths in the working tree that have no kind:
1964
if change.path[1] is not None and change.kind[1] is None:
1965
missing.append(change.path[1])
1976
if change[1][1] is not None and change[6][1] is None:
1977
missing.append(change[1][1])
1966
1978
file_list = sorted(missing, reverse=True)
1967
1979
file_deletion_strategy = 'keep'
1968
1980
tree.remove(file_list, verbose=verbose, to_file=self.outf,
1969
keep_files=file_deletion_strategy == 'keep',
1970
force=(file_deletion_strategy == 'no-backup'))
1981
keep_files=file_deletion_strategy=='keep',
1982
force=(file_deletion_strategy=='no-backup'))
1985
class cmd_file_id(Command):
1986
__doc__ = """Print file_id of a particular file or directory.
1988
The file_id is assigned when the file is first added and remains the
1989
same through all revisions where the file exists, even when it is
1994
_see_also = ['inventory', 'ls']
1995
takes_args = ['filename']
1998
def run(self, filename):
1999
tree, relpath = WorkingTree.open_containing(filename)
2000
i = tree.path2id(relpath)
2002
raise errors.NotVersionedError(filename)
2004
self.outf.write(i + '\n')
2007
class cmd_file_path(Command):
2008
__doc__ = """Print path of file_ids to a file or directory.
2010
This prints one line for each directory down to the target,
2011
starting at the branch root.
2015
takes_args = ['filename']
2018
def run(self, filename):
2019
tree, relpath = WorkingTree.open_containing(filename)
2020
fid = tree.path2id(relpath)
2022
raise errors.NotVersionedError(filename)
2023
segments = osutils.splitpath(relpath)
2024
for pos in range(1, len(segments) + 1):
2025
path = osutils.joinpath(segments[:pos])
2026
self.outf.write("%s\n" % tree.path2id(path))
1973
2029
class cmd_reconcile(Command):
2332
2378
_see_also = ['status']
2333
2379
takes_args = ['file*']
2334
2380
takes_options = [
2335
Option('diff-options', type=str,
2381
Option('diff-options', type=text_type,
2336
2382
help='Pass these options to the external diff program.'),
2337
Option('prefix', type=str,
2383
Option('prefix', type=text_type,
2338
2384
short_name='p',
2339
2385
help='Set prefixes added to old and new filenames, as '
2340
2386
'two values separated by a colon. (eg "old/:new/").'),
2342
help='Branch/tree to compare from.',
2388
help='Branch/tree to compare from.',
2346
help='Branch/tree to compare to.',
2392
help='Branch/tree to compare to.',
2351
2397
Option('using',
2352
help='Use this command to compare files.',
2398
help='Use this command to compare files.',
2355
2401
RegistryOption('format',
2357
help='Diff format to use.',
2358
lazy_registry=('breezy.diff', 'format_registry'),
2359
title='Diff format'),
2403
help='Diff format to use.',
2404
lazy_registry=('breezy.diff', 'format_registry'),
2405
title='Diff format'),
2360
2406
Option('context',
2361
help='How many lines of context to show.',
2364
RegistryOption.from_kwargs(
2366
help='Color mode to use.',
2367
title='Color Mode', value_switches=False, enum_switch=True,
2368
never='Never colorize output.',
2369
auto='Only colorize output if terminal supports it and STDOUT is a'
2371
always='Always colorize output (default).'),
2374
help=('Warn if trailing whitespace or spurious changes have been'
2407
help='How many lines of context to show.',
2378
2411
aliases = ['di', 'dif']
2379
2412
encoding_type = 'exact'
2381
2414
@display_command
2382
2415
def run(self, revision=None, file_list=None, diff_options=None,
2383
2416
prefix=None, old=None, new=None, using=None, format=None,
2384
context=None, color='never'):
2385
2418
from .diff import (get_trees_and_branches_to_diff_locked,
2388
2421
if prefix == u'0':
2389
2422
# diff -p0 format
2698
2721
takes_args = ['file*']
2699
2722
_see_also = ['log-formats', 'revisionspec']
2700
2723
takes_options = [
2702
help='Show from oldest to newest.'),
2704
custom_help('verbose',
2705
help='Show files changed in each revision.'),
2709
type=breezy.option._parse_revision_str,
2711
help='Show just the specified revision.'
2712
' See also "help revisionspec".'),
2714
RegistryOption('authors',
2715
'What names to list as authors - first, all or committer.',
2718
'breezy.log', 'author_list_registry'),
2722
help='Number of levels to display - 0 for all, 1 for flat.',
2724
type=_parse_levels),
2726
help='Show revisions whose message matches this '
2727
'regular expression.',
2732
help='Limit the output to the first N revisions.',
2737
help='Show changes made in each revision as a patch.'),
2738
Option('include-merged',
2739
help='Show merged revisions like --levels 0 does.'),
2740
Option('include-merges', hidden=True,
2741
help='Historical alias for --include-merged.'),
2742
Option('omit-merges',
2743
help='Do not report commits with more than one parent.'),
2744
Option('exclude-common-ancestry',
2745
help='Display only the revisions that are not part'
2746
' of both ancestries (require -rX..Y).'
2748
Option('signatures',
2749
help='Show digital signature validity.'),
2752
help='Show revisions whose properties match this '
2755
ListOption('match-message',
2756
help='Show revisions whose message matches this '
2759
ListOption('match-committer',
2725
help='Show from oldest to newest.'),
2727
custom_help('verbose',
2728
help='Show files changed in each revision.'),
2732
type=breezy.option._parse_revision_str,
2734
help='Show just the specified revision.'
2735
' See also "help revisionspec".'),
2737
RegistryOption('authors',
2738
'What names to list as authors - first, all or committer.',
2740
lazy_registry=('breezy.log', 'author_list_registry'),
2744
help='Number of levels to display - 0 for all, 1 for flat.',
2746
type=_parse_levels),
2748
help='Show revisions whose message matches this '
2749
'regular expression.',
2754
help='Limit the output to the first N revisions.',
2759
help='Show changes made in each revision as a patch.'),
2760
Option('include-merged',
2761
help='Show merged revisions like --levels 0 does.'),
2762
Option('include-merges', hidden=True,
2763
help='Historical alias for --include-merged.'),
2764
Option('omit-merges',
2765
help='Do not report commits with more than one parent.'),
2766
Option('exclude-common-ancestry',
2767
help='Display only the revisions that are not part'
2768
' of both ancestries (require -rX..Y).'
2770
Option('signatures',
2771
help='Show digital signature validity.'),
2774
help='Show revisions whose properties match this '
2777
ListOption('match-message',
2778
help='Show revisions whose message matches this '
2781
ListOption('match-committer',
2760
2782
help='Show revisions whose committer matches this '
2763
ListOption('match-author',
2785
ListOption('match-author',
2764
2786
help='Show revisions whose authors match this '
2767
ListOption('match-bugs',
2789
ListOption('match-bugs',
2768
2790
help='Show revisions whose bugs match this '
2772
2794
encoding_type = 'replace'
2774
2796
@display_command
3018
3039
_see_also = ['status', 'cat']
3019
3040
takes_args = ['path?']
3020
3041
takes_options = [
3023
Option('recursive', short_name='R',
3024
help='Recurse into subdirectories.'),
3026
help='Print paths relative to the root of the branch.'),
3027
Option('unknown', short_name='u',
3028
help='Print unknown files.'),
3029
Option('versioned', help='Print versioned files.',
3031
Option('ignored', short_name='i',
3032
help='Print ignored files.'),
3033
Option('kind', short_name='k',
3034
help=('List entries of a particular kind: file, '
3035
'directory, symlink, tree-reference.'),
3044
Option('recursive', short_name='R',
3045
help='Recurse into subdirectories.'),
3047
help='Print paths relative to the root of the branch.'),
3048
Option('unknown', short_name='u',
3049
help='Print unknown files.'),
3050
Option('versioned', help='Print versioned files.',
3052
Option('ignored', short_name='i',
3053
help='Print ignored files.'),
3054
Option('kind', short_name='k',
3055
help='List entries of a particular kind: file, directory, symlink.',
3042
3061
@display_command
3043
3062
def run(self, revision=None, verbose=False,
3044
3063
recursive=False, from_root=False,
3045
3064
unknown=False, versioned=False, ignored=False,
3046
3065
null=False, kind=None, show_ids=False, path=None, directory=None):
3048
if kind and kind not in ('file', 'directory', 'symlink', 'tree-reference'):
3049
raise errors.CommandError(gettext('invalid kind specified'))
3067
if kind and kind not in ('file', 'directory', 'symlink'):
3068
raise errors.BzrCommandError(gettext('invalid kind specified'))
3051
3070
if verbose and null:
3052
raise errors.CommandError(
3053
gettext('Cannot set both --verbose and --null'))
3071
raise errors.BzrCommandError(gettext('Cannot set both --verbose and --null'))
3054
3072
all = not (unknown or versioned or ignored)
3056
selection = {'I': ignored, '?': unknown, 'V': versioned}
3074
selection = {'I':ignored, '?':unknown, 'V':versioned}
3058
3076
if path is None:
3062
raise errors.CommandError(gettext('cannot specify both --from-root'
3080
raise errors.BzrCommandError(gettext('cannot specify both --from-root'
3065
3083
tree, branch, relpath = \
3066
3084
_open_directory_or_containing_tree_or_branch(fs_path, directory)
3443
3438
def run(self, filename, revision=None, name_from_revision=False,
3444
3439
filters=False, directory=None):
3445
3440
if revision is not None and len(revision) != 1:
3446
raise errors.CommandError(gettext("brz cat --revision takes exactly"
3447
" one revision specifier"))
3441
raise errors.BzrCommandError(gettext("brz cat --revision takes exactly"
3442
" one revision specifier"))
3448
3443
tree, branch, relpath = \
3449
3444
_open_directory_or_containing_tree_or_branch(filename, directory)
3450
self.enter_context(branch.lock_read())
3445
self.add_cleanup(branch.lock_read().unlock)
3451
3446
return self._run(tree, branch, relpath, filename, revision,
3452
3447
name_from_revision, filters)
3454
3449
def _run(self, tree, b, relpath, filename, revision, name_from_revision,
3457
3451
if tree is None:
3458
3452
tree = b.basis_tree()
3459
3453
rev_tree = _get_one_revision_tree('cat', revision, branch=b)
3460
self.enter_context(rev_tree.lock_read())
3454
self.add_cleanup(rev_tree.lock_read().unlock)
3456
old_file_id = rev_tree.path2id(relpath)
3458
# TODO: Split out this code to something that generically finds the
3459
# best id for a path across one or more trees; it's like
3460
# find_ids_across_trees but restricted to find just one. -- mbp
3462
3462
if name_from_revision:
3463
3463
# Try in revision if requested
3464
if not rev_tree.is_versioned(relpath):
3465
raise errors.CommandError(gettext(
3464
if old_file_id is None:
3465
raise errors.BzrCommandError(gettext(
3466
3466
"{0!r} is not present in revision {1}").format(
3467
3467
filename, rev_tree.get_revision_id()))
3468
rev_tree_path = relpath
3469
actual_file_id = old_file_id
3471
rev_tree_path = _mod_tree.find_previous_path(
3472
tree, rev_tree, relpath)
3473
except errors.NoSuchFile:
3474
rev_tree_path = None
3476
if rev_tree_path is None:
3477
# Path didn't exist in working tree
3478
if not rev_tree.is_versioned(relpath):
3479
raise errors.CommandError(gettext(
3480
"{0!r} is not present in revision {1}").format(
3481
filename, rev_tree.get_revision_id()))
3483
# Fall back to the same path in the basis tree, if present.
3484
rev_tree_path = relpath
3471
cur_file_id = tree.path2id(relpath)
3472
if cur_file_id is not None and rev_tree.has_id(cur_file_id):
3473
actual_file_id = cur_file_id
3474
elif old_file_id is not None:
3475
actual_file_id = old_file_id
3477
raise errors.BzrCommandError(gettext(
3478
"{0!r} is not present in revision {1}").format(
3479
filename, rev_tree.get_revision_id()))
3487
3481
from .filter_tree import ContentFilterTree
3488
filter_tree = ContentFilterTree(
3489
rev_tree, rev_tree._content_filter_stack)
3490
fileobj = filter_tree.get_file(rev_tree_path)
3482
filter_tree = ContentFilterTree(rev_tree,
3483
rev_tree._content_filter_stack)
3484
content = filter_tree.get_file_text(relpath, actual_file_id)
3492
fileobj = rev_tree.get_file(rev_tree_path)
3493
shutil.copyfileobj(fileobj, self.outf)
3486
content = rev_tree.get_file_text(relpath, actual_file_id)
3494
3487
self.cleanup_now()
3488
self.outf.write(content)
3497
3491
class cmd_local_time_offset(Command):
3498
3492
__doc__ = """Show the offset in seconds from GMT to local time."""
3501
3494
@display_command
3503
3496
self.outf.write("%s\n" % osutils.local_time_offset())
3506
3500
class cmd_commit(Command):
3507
3501
__doc__ = """Commit changes into a new revision.
3563
3557
_see_also = ['add', 'bugs', 'hooks', 'uncommit']
3564
3558
takes_args = ['selected*']
3565
3559
takes_options = [
3567
'exclude', type=str, short_name='x',
3568
help="Do not consider changes made to a given path."),
3569
Option('message', type=str,
3571
help="Description of the new revision."),
3574
help='Commit even if nothing has changed.'),
3575
Option('file', type=str,
3578
help='Take commit message from this file.'),
3580
help="Refuse to commit if there are unknown "
3581
"files in the working tree."),
3582
Option('commit-time', type=str,
3583
help="Manually set a commit time using commit date "
3584
"format, e.g. '2009-10-10 08:00:00 +0100'."),
3587
help="Link to a related bug. (see \"brz help bugs\")."),
3590
help="Mark a bug as being fixed by this revision "
3591
"(see \"brz help bugs\")."),
3594
help="Set the author's name, if it's different "
3595
"from the committer."),
3597
help="Perform a local commit in a bound "
3598
"branch. Local commits are not pushed to "
3599
"the master branch until a normal commit "
3602
Option('show-diff', short_name='p',
3603
help='When no message is supplied, show the diff along'
3604
' with the status summary in the message editor.'),
3606
help='When committing to a foreign version control '
3607
'system do not push data that can not be natively '
3560
ListOption('exclude', type=text_type, short_name='x',
3561
help="Do not consider changes made to a given path."),
3562
Option('message', type=text_type,
3564
help="Description of the new revision."),
3567
help='Commit even if nothing has changed.'),
3568
Option('file', type=text_type,
3571
help='Take commit message from this file.'),
3573
help="Refuse to commit if there are unknown "
3574
"files in the working tree."),
3575
Option('commit-time', type=text_type,
3576
help="Manually set a commit time using commit date "
3577
"format, e.g. '2009-10-10 08:00:00 +0100'."),
3578
ListOption('fixes', type=text_type,
3579
help="Mark a bug as being fixed by this revision "
3580
"(see \"brz help bugs\")."),
3581
ListOption('author', type=text_type,
3582
help="Set the author's name, if it's different "
3583
"from the committer."),
3585
help="Perform a local commit in a bound "
3586
"branch. Local commits are not pushed to "
3587
"the master branch until a normal commit "
3590
Option('show-diff', short_name='p',
3591
help='When no message is supplied, show the diff along'
3592
' with the status summary in the message editor.'),
3594
help='When committing to a foreign version control '
3595
'system do not push data that can not be natively '
3609
3598
aliases = ['ci', 'checkin']
3611
def _iter_bug_urls(self, bugs, branch, status):
3612
default_bugtracker = None
3600
def _iter_bug_fix_urls(self, fixes, branch):
3601
default_bugtracker = None
3613
3602
# Configure the properties for bug fixing attributes.
3615
tokens = bug.split(':')
3603
for fixed_bug in fixes:
3604
tokens = fixed_bug.split(':')
3616
3605
if len(tokens) == 1:
3617
3606
if default_bugtracker is None:
3618
3607
branch_config = branch.get_config_stack()
3619
3608
default_bugtracker = branch_config.get(
3621
3610
if default_bugtracker is None:
3622
raise errors.CommandError(gettext(
3611
raise errors.BzrCommandError(gettext(
3623
3612
"No tracker specified for bug %s. Use the form "
3624
3613
"'tracker:id' or specify a default bug tracker "
3625
3614
"using the `bugtracker` option.\nSee "
3626
3615
"\"brz help bugs\" for more information on this "
3627
"feature. Commit refused.") % bug)
3616
"feature. Commit refused.") % fixed_bug)
3628
3617
tag = default_bugtracker
3629
3618
bug_id = tokens[0]
3630
3619
elif len(tokens) != 2:
3631
raise errors.CommandError(gettext(
3620
raise errors.BzrCommandError(gettext(
3632
3621
"Invalid bug %s. Must be in the form of 'tracker:id'. "
3633
3622
"See \"brz help bugs\" for more information on this "
3634
"feature.\nCommit refused.") % bug)
3623
"feature.\nCommit refused.") % fixed_bug)
3636
3625
tag, bug_id = tokens
3638
yield bugtracker.get_bug_url(tag, branch, bug_id), status
3627
yield bugtracker.get_bug_url(tag, branch, bug_id)
3639
3628
except bugtracker.UnknownBugTrackerAbbreviation:
3640
raise errors.CommandError(gettext(
3641
'Unrecognized bug %s. Commit refused.') % bug)
3629
raise errors.BzrCommandError(gettext(
3630
'Unrecognized bug %s. Commit refused.') % fixed_bug)
3642
3631
except bugtracker.MalformedBugIdentifier as e:
3643
raise errors.CommandError(gettext(
3632
raise errors.BzrCommandError(gettext(
3644
3633
u"%s\nCommit refused.") % (e,))
3646
3635
def run(self, message=None, file=None, verbose=False, selected_list=None,
3647
unchanged=False, strict=False, local=False, fixes=None, bugs=None,
3636
unchanged=False, strict=False, local=False, fixes=None,
3648
3637
author=None, show_diff=False, exclude=None, commit_time=None,
3651
3639
from .commit import (
3652
3640
PointlessCommit,
4502
4478
change_reporter = delta._ChangeReporter(
4503
4479
unversioned_filter=tree.is_ignored, view_info=view_info)
4504
4480
pb = ui.ui_factory.nested_progress_bar()
4505
self.enter_context(pb)
4506
self.enter_context(tree.lock_write())
4481
self.add_cleanup(pb.finished)
4482
self.add_cleanup(tree.lock_write().unlock)
4507
4483
if location is not None:
4509
mergeable = _mod_mergeable.read_mergeable_from_url(
4510
location, possible_transports=possible_transports)
4485
mergeable = bundle.read_mergeable_from_url(location,
4486
possible_transports=possible_transports)
4511
4487
except errors.NotABundle:
4512
4488
mergeable = None
4514
4490
if uncommitted:
4515
raise errors.CommandError(gettext('Cannot use --uncommitted'
4516
' with bundles or merge directives.'))
4491
raise errors.BzrCommandError(gettext('Cannot use --uncommitted'
4492
' with bundles or merge directives.'))
4518
4494
if revision is not None:
4519
raise errors.CommandError(gettext(
4495
raise errors.BzrCommandError(gettext(
4520
4496
'Cannot use -r with merge directives or bundles'))
4521
4497
merger, verified = _mod_merge.Merger.from_mergeable(tree,
4524
4500
if merger is None and uncommitted:
4525
4501
if revision is not None and len(revision) > 0:
4526
raise errors.CommandError(gettext('Cannot use --uncommitted and'
4527
' --revision at the same time.'))
4502
raise errors.BzrCommandError(gettext('Cannot use --uncommitted and'
4503
' --revision at the same time.'))
4528
4504
merger = self.get_merger_from_uncommitted(tree, location, None)
4529
4505
allow_pending = False
4531
4507
if merger is None:
4532
4508
merger, allow_pending = self._get_merger_from_branch(tree,
4533
location, revision, remember, possible_transports, None)
4509
location, revision, remember, possible_transports, None)
4535
4511
merger.merge_type = merge_type
4536
4512
merger.reprocess = reprocess
4537
4513
merger.show_base = show_base
4538
4514
self.sanity_check_merger(merger)
4539
4515
if (merger.base_rev_id == merger.other_rev_id and
4540
merger.other_rev_id is not None):
4516
merger.other_rev_id is not None):
4541
4517
# check if location is a nonexistent file (and not a branch) to
4542
4518
# disambiguate the 'Nothing to do'
4543
4519
if merger.interesting_files:
4544
4520
if not merger.other_tree.has_filename(
4545
merger.interesting_files[0]):
4521
merger.interesting_files[0]):
4546
4522
note(gettext("merger: ") + str(merger))
4547
4523
raise errors.PathsDoNotExist([location])
4548
4524
note(gettext('Nothing to do.'))
4550
4526
if pull and not preview:
4551
4527
if merger.interesting_files is not None:
4552
raise errors.CommandError(
4553
gettext('Cannot pull individual files'))
4528
raise errors.BzrCommandError(gettext('Cannot pull individual files'))
4554
4529
if (merger.base_rev_id == tree.last_revision()):
4555
4530
result = tree.pull(merger.other_branch, False,
4556
4531
merger.other_rev_id)
4557
4532
result.report(self.outf)
4559
4534
if merger.this_basis is None:
4560
raise errors.CommandError(gettext(
4535
raise errors.BzrCommandError(gettext(
4561
4536
"This branch has no commits."
4562
4537
" (perhaps you would prefer 'brz pull')"))
4792
4757
if merge_type is None:
4793
4758
merge_type = _mod_merge.Merge3Merger
4794
4759
tree, file_list = WorkingTree.open_containing_paths(file_list)
4795
self.enter_context(tree.lock_write())
4760
self.add_cleanup(tree.lock_write().unlock)
4796
4761
parents = tree.get_parent_ids()
4797
4762
if len(parents) != 2:
4798
raise errors.CommandError(
4799
gettext("Sorry, remerge only works after normal"
4800
" merges. Not cherrypicking or multi-merges."))
4801
interesting_files = None
4763
raise errors.BzrCommandError(gettext("Sorry, remerge only works after normal"
4764
" merges. Not cherrypicking or"
4766
repository = tree.branch.repository
4767
interesting_ids = None
4802
4768
new_conflicts = []
4803
4769
conflicts = tree.conflicts()
4804
4770
if file_list is not None:
4805
interesting_files = set()
4771
interesting_ids = set()
4806
4772
for filename in file_list:
4807
if not tree.is_versioned(filename):
4773
file_id = tree.path2id(filename)
4808
4775
raise errors.NotVersionedError(filename)
4809
interesting_files.add(filename)
4810
if tree.kind(filename) != "directory":
4776
interesting_ids.add(file_id)
4777
if tree.kind(filename, file_id) != "directory":
4813
for path, ie in tree.iter_entries_by_dir(
4814
specific_files=[filename]):
4815
interesting_files.add(path)
4780
# FIXME: Support nested trees
4781
for name, ie in tree.root_inventory.iter_entries(file_id):
4782
interesting_ids.add(ie.file_id)
4816
4783
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4818
4785
# Remerge only supports resolving contents conflicts
4819
4786
allowed_conflicts = ('text conflict', 'contents conflict')
4820
4787
restore_files = [c.path for c in conflicts
4821
4788
if c.typestring in allowed_conflicts]
4822
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_files)
4789
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
4823
4790
tree.set_conflicts(ConflictList(new_conflicts))
4824
4791
if file_list is not None:
4825
4792
restore_files = file_list
5289
5253
wt, branch, relpath = \
5290
5254
_open_directory_or_containing_tree_or_branch(filename, directory)
5291
5255
if wt is not None:
5292
self.enter_context(wt.lock_read())
5256
self.add_cleanup(wt.lock_read().unlock)
5294
self.enter_context(branch.lock_read())
5258
self.add_cleanup(branch.lock_read().unlock)
5295
5259
tree = _get_one_revision_tree('annotate', revision, branch=branch)
5296
self.enter_context(tree.lock_read())
5297
if wt is not None and revision is None:
5298
if not wt.is_versioned(relpath):
5299
raise errors.NotVersionedError(relpath)
5260
self.add_cleanup(tree.lock_read().unlock)
5261
if wt is not None and revision is None:
5262
file_id = wt.path2id(relpath)
5264
file_id = tree.path2id(relpath)
5266
raise errors.NotVersionedError(filename)
5267
if wt is not None and revision is None:
5300
5268
# If there is a tree and we're not annotating historical
5301
5269
# versions, annotate the working tree's content.
5302
5270
annotate_file_tree(wt, relpath, self.outf, long, all,
5271
show_ids=show_ids, file_id=file_id)
5305
if not tree.is_versioned(relpath):
5306
raise errors.NotVersionedError(relpath)
5307
5273
annotate_file_tree(tree, relpath, self.outf, long, all,
5308
show_ids=show_ids, branch=branch)
5274
show_ids=show_ids, branch=branch, file_id=file_id)
5311
5277
class cmd_re_sign(Command):
5312
5278
__doc__ = """Create a digital signature for an existing revision."""
5313
5279
# TODO be able to replace existing ones.
5315
hidden = True # is this right ?
5281
hidden = True # is this right ?
5316
5282
takes_args = ['revision_id*']
5317
5283
takes_options = ['directory', 'revision']
5319
5285
def run(self, revision_id_list=None, revision=None, directory=u'.'):
5320
5286
if revision_id_list is not None and revision is not None:
5321
raise errors.CommandError(
5322
gettext('You can only supply one of revision_id or --revision'))
5287
raise errors.BzrCommandError(gettext('You can only supply one of revision_id or --revision'))
5323
5288
if revision_id_list is None and revision is None:
5324
raise errors.CommandError(
5325
gettext('You must supply either --revision or a revision_id'))
5289
raise errors.BzrCommandError(gettext('You must supply either --revision or a revision_id'))
5326
5290
b = WorkingTree.open_containing(directory)[0].branch
5327
self.enter_context(b.lock_write())
5291
self.add_cleanup(b.lock_write().unlock)
5328
5292
return self._run(b, revision_id_list, revision)
5330
5294
def _run(self, b, revision_id_list, revision):
5331
from .repository import WriteGroup
5332
5296
gpg_strategy = gpg.GPGStrategy(b.get_config_stack())
5333
5297
if revision_id_list is not None:
5334
with WriteGroup(b.repository):
5298
b.repository.start_write_group()
5335
5300
for revision_id in revision_id_list:
5336
5301
revision_id = cache_utf8.encode(revision_id)
5337
5302
b.repository.sign_revision(revision_id, gpg_strategy)
5304
b.repository.abort_write_group()
5307
b.repository.commit_write_group()
5338
5308
elif revision is not None:
5339
5309
if len(revision) == 1:
5340
5310
revno, rev_id = revision[0].in_history(b)
5341
with WriteGroup(b.repository):
5311
b.repository.start_write_group()
5342
5313
b.repository.sign_revision(rev_id, gpg_strategy)
5315
b.repository.abort_write_group()
5318
b.repository.commit_write_group()
5343
5319
elif len(revision) == 2:
5344
5320
# are they both on rh- if so we can walk between them
5345
5321
# might be nice to have a range helper for arbitrary
6342
6317
except errors.NotBranchError:
6344
6319
had_explicit_nick = False
6346
possible_transports.append(branch.user_transport)
6347
6320
if create_branch:
6348
6321
if branch is None:
6349
raise errors.CommandError(
6322
raise errors.BzrCommandError(
6350
6323
gettext('cannot create branch without source branch'))
6351
to_location = lookup_new_sibling_branch(
6352
control_dir, to_location,
6353
possible_transports=possible_transports)
6354
if revision is not None:
6355
revision = revision.as_revision_id(branch)
6356
to_branch = branch.controldir.sprout(
6358
possible_transports=possible_transports,
6359
revision_id=revision,
6360
source_branch=branch).open_branch()
6324
to_location = lookup_new_sibling_branch(control_dir, to_location,
6325
possible_transports=possible_transports)
6326
to_branch = branch.controldir.sprout(to_location,
6327
possible_transports=possible_transports,
6328
source_branch=branch).open_branch()
6363
to_branch = Branch.open(
6364
to_location, possible_transports=possible_transports)
6331
to_branch = Branch.open(to_location,
6332
possible_transports=possible_transports)
6365
6333
except errors.NotBranchError:
6366
to_branch = open_sibling_branch(
6367
control_dir, to_location,
6334
to_branch = open_sibling_branch(control_dir, to_location,
6368
6335
possible_transports=possible_transports)
6369
if revision is not None:
6370
revision = revision.as_revision_id(to_branch)
6371
possible_transports.append(to_branch.user_transport)
6373
switch.switch(control_dir, to_branch, force, revision_id=revision,
6374
store_uncommitted=store,
6375
possible_transports=possible_transports)
6376
except controldir.BranchReferenceLoop:
6377
raise errors.CommandError(
6378
gettext('switching would create a branch reference loop. '
6379
'Use the "bzr up" command to switch to a '
6380
'different revision.'))
6336
if revision is not None:
6337
revision = revision.as_revision_id(to_branch)
6338
switch.switch(control_dir, to_branch, force, revision_id=revision,
6339
store_uncommitted=store)
6381
6340
if had_explicit_nick:
6382
branch = control_dir.open_branch() # get the new branch!
6341
branch = control_dir.open_branch() #get the new branch!
6383
6342
branch.nick = to_branch.nick
6385
if to_branch.controldir.control_url != control_dir.control_url:
6386
note(gettext('Switched to branch %s at %s'),
6387
to_branch.name, urlutils.unescape_for_display(to_branch.base, 'utf-8'))
6389
note(gettext('Switched to branch %s'), to_branch.name)
6391
note(gettext('Switched to branch at %s'),
6392
urlutils.unescape_for_display(to_branch.base, 'utf-8'))
6343
note(gettext('Switched to branch: %s'),
6344
urlutils.unescape_for_display(to_branch.base, 'utf-8'))
6395
6348
class cmd_view(Command):
6779
6725
takes_args = ['path?', 'location?']
6782
Option('force-unversioned',
6783
help='Set reference even if path is not versioned.'),
6786
def run(self, path=None, directory='.', location=None, force_unversioned=False):
6787
tree, branch, relpath = (
6788
controldir.ControlDir.open_containing_tree_or_branch(directory))
6727
def run(self, path=None, location=None):
6729
if path is not None:
6731
tree, branch, relpath =(
6732
controldir.ControlDir.open_containing_tree_or_branch(branchdir))
6733
if path is not None:
6789
6735
if tree is None:
6790
6736
tree = branch.basis_tree()
6791
6737
if path is None:
6792
with tree.lock_read():
6794
(path, tree.get_reference_info(path, branch))
6795
for path in tree.iter_references()]
6796
self._display_reference_info(tree, branch, info)
6738
info = viewitems(branch._get_all_reference_info())
6739
self._display_reference_info(tree, branch, info)
6798
if not tree.is_versioned(path) and not force_unversioned:
6741
file_id = tree.path2id(path)
6799
6743
raise errors.NotVersionedError(path)
6800
6744
if location is None:
6801
info = [(path, tree.get_reference_info(path, branch))]
6745
info = [(file_id, branch.get_reference_info(file_id))]
6802
6746
self._display_reference_info(tree, branch, info)
6804
tree.set_reference_info(path, location)
6748
branch.set_reference_info(file_id, path, location)
6806
6750
def _display_reference_info(self, tree, branch, info):
6808
for path, location in info:
6752
for file_id, (path, location) in info:
6754
path = tree.id2path(file_id)
6755
except errors.NoSuchId:
6809
6757
ref_list.append((path, location))
6810
6758
for path, location in sorted(ref_list):
6811
6759
self.outf.write('%s %s\n' % (path, location))
6883
6838
if len(installed) > 0:
6884
6839
self.outf.write("Installed:\n")
6885
6840
for rev in installed:
6886
self.outf.write(rev.decode('utf-8') + "\n")
6841
self.outf.write(rev + "\n")
6887
6842
if len(failed) > 0:
6888
6843
self.outf.write("Still missing:\n")
6889
6844
for rev in failed:
6890
self.outf.write(rev.decode('utf-8') + "\n")
6845
self.outf.write(rev + "\n")
6891
6846
if not no_fix and len(installed) > 0:
6892
6847
cmd_reconcile().run(".")
6895
class cmd_grep(Command):
6896
"""Print lines matching PATTERN for specified files and revisions.
6898
This command searches the specified files and revisions for a given
6899
pattern. The pattern is specified as a Python regular expressions[1].
6901
If the file name is not specified, the revisions starting with the
6902
current directory are searched recursively. If the revision number is
6903
not specified, the working copy is searched. To search the last committed
6904
revision, use the '-r -1' or '-r last:1' option.
6906
Unversioned files are not searched unless explicitly specified on the
6907
command line. Unversioned directores are not searched.
6909
When searching a pattern, the output is shown in the 'filepath:string'
6910
format. If a revision is explicitly searched, the output is shown as
6911
'filepath~N:string', where N is the revision number.
6913
--include and --exclude options can be used to search only (or exclude
6914
from search) files with base name matches the specified Unix style GLOB
6915
pattern. The GLOB pattern an use *, ?, and [...] as wildcards, and \\
6916
to quote wildcard or backslash character literally. Note that the glob
6917
pattern is not a regular expression.
6919
[1] http://docs.python.org/library/re.html#regular-expression-syntax
6922
encoding_type = 'replace'
6923
takes_args = ['pattern', 'path*']
6927
Option('color', type=str, argname='when',
6928
help='Show match in color. WHEN is never, always or auto.'),
6929
Option('diff', short_name='p',
6930
help='Grep for pattern in changeset for each revision.'),
6931
ListOption('exclude', type=str, argname='glob', short_name='X',
6932
help="Skip files whose base name matches GLOB."),
6933
ListOption('include', type=str, argname='glob', short_name='I',
6934
help="Search only files whose base name matches GLOB."),
6935
Option('files-with-matches', short_name='l',
6936
help='Print only the name of each input file in '
6937
'which PATTERN is found.'),
6938
Option('files-without-match', short_name='L',
6939
help='Print only the name of each input file in '
6940
'which PATTERN is not found.'),
6941
Option('fixed-string', short_name='F',
6942
help='Interpret PATTERN is a single fixed string (not regex).'),
6944
help='Search for pattern starting from the root of the branch. '
6945
'(implies --recursive)'),
6946
Option('ignore-case', short_name='i',
6947
help='Ignore case distinctions while matching.'),
6949
help='Number of levels to display - 0 for all, 1 for collapsed '
6952
type=_parse_levels),
6953
Option('line-number', short_name='n',
6954
help='Show 1-based line number.'),
6955
Option('no-recursive',
6956
help="Don't recurse into subdirectories. (default is --recursive)"),
6957
Option('null', short_name='Z',
6958
help='Write an ASCII NUL (\\0) separator '
6959
'between output lines rather than a newline.'),
6963
def run(self, verbose=False, ignore_case=False, no_recursive=False,
6964
from_root=False, null=False, levels=None, line_number=False,
6965
path_list=None, revision=None, pattern=None, include=None,
6966
exclude=None, fixed_string=False, files_with_matches=False,
6967
files_without_match=False, color=None, diff=False):
6968
from breezy import _termcolor
6971
if path_list is None:
6975
raise errors.CommandError(
6976
'cannot specify both --from-root and PATH.')
6978
if files_with_matches and files_without_match:
6979
raise errors.CommandError(
6980
'cannot specify both '
6981
'-l/--files-with-matches and -L/--files-without-matches.')
6983
global_config = _mod_config.GlobalConfig()
6986
color = global_config.get_user_option('grep_color')
6991
if color not in ['always', 'never', 'auto']:
6992
raise errors.CommandError('Valid values for --color are '
6993
'"always", "never" or "auto".')
6999
if revision is not None or levels == 0:
7000
# print revision numbers as we may be showing multiple revisions
7007
if not ignore_case and grep.is_fixed_string(pattern):
7008
# if the pattern isalnum, implicitly use to -F for faster grep
7010
elif ignore_case and fixed_string:
7011
# GZ 2010-06-02: Fall back to regexp rather than lowercasing
7012
# pattern and text which will cause pain later
7013
fixed_string = False
7014
pattern = re.escape(pattern)
7017
re_flags = re.MULTILINE
7019
re_flags |= re.IGNORECASE
7021
if not fixed_string:
7022
patternc = grep.compile_pattern(
7023
pattern.encode(grep._user_encoding), re_flags)
7025
if color == 'always':
7027
elif color == 'never':
7029
elif color == 'auto':
7030
show_color = _termcolor.allow_color()
7032
opts = grep.GrepOptions()
7034
opts.verbose = verbose
7035
opts.ignore_case = ignore_case
7036
opts.no_recursive = no_recursive
7037
opts.from_root = from_root
7039
opts.levels = levels
7040
opts.line_number = line_number
7041
opts.path_list = path_list
7042
opts.revision = revision
7043
opts.pattern = pattern
7044
opts.include = include
7045
opts.exclude = exclude
7046
opts.fixed_string = fixed_string
7047
opts.files_with_matches = files_with_matches
7048
opts.files_without_match = files_without_match
7052
opts.eol_marker = eol_marker
7053
opts.print_revno = print_revno
7054
opts.patternc = patternc
7055
opts.recursive = not no_recursive
7056
opts.fixed_string = fixed_string
7057
opts.outf = self.outf
7058
opts.show_color = show_color
7062
# files_with_matches, files_without_match
7063
# levels(?), line_number, from_root
7065
# These are silently ignored.
7066
grep.grep_diff(opts)
7067
elif revision is None:
7068
grep.workingtree_grep(opts)
7070
grep.versioned_grep(opts)
7073
class cmd_patch(Command):
7074
"""Apply a named patch to the current tree.
7078
takes_args = ['filename?']
7079
takes_options = [Option('strip', type=int, short_name='p',
7080
help=("Strip the smallest prefix containing num "
7081
"leading slashes from filenames.")),
7082
Option('silent', help='Suppress chatter.')]
7084
def run(self, filename=None, strip=None, silent=False):
7085
from .patch import patch_tree
7086
wt = WorkingTree.open_containing('.')[0]
7090
if filename is None:
7091
my_file = getattr(sys.stdin, 'buffer', sys.stdin)
7093
my_file = open(filename, 'rb')
7094
patches = [my_file.read()]
7095
return patch_tree(wt, patches, strip, quiet=is_quiet(), out=self.outf)
7098
class cmd_resolve_location(Command):
7099
__doc__ = """Expand a location to a full URL.
7102
Look up a Launchpad URL.
7104
brz resolve-location lp:brz
7106
takes_args = ['location']
7109
def run(self, location):
7110
from .location import location_to_url
7111
url = location_to_url(location)
7112
display_url = urlutils.unescape_for_display(url, self.outf.encoding)
7113
self.outf.write('%s\n' % display_url)
7116
6850
def _register_lazy_builtins():
7117
6851
# register lazy builtins from other modules; called at startup and should
7118
6852
# be only called once.
7119
6853
for (name, aliases, module_name) in [
7120
('cmd_bisect', [], 'breezy.bisect'),
7121
('cmd_bundle_info', [], 'breezy.bzr.bundle.commands'),
7122
('cmd_config', [], 'breezy.config'),
7123
('cmd_dump_btree', [], 'breezy.bzr.debug_commands'),
7124
('cmd_file_id', [], 'breezy.bzr.debug_commands'),
7125
('cmd_file_path', [], 'breezy.bzr.debug_commands'),
7126
('cmd_version_info', [], 'breezy.cmd_version_info'),
7127
('cmd_resolve', ['resolved'], 'breezy.conflicts'),
7128
('cmd_conflicts', [], 'breezy.conflicts'),
7129
('cmd_ping', [], 'breezy.bzr.smart.ping'),
7130
('cmd_sign_my_commits', [], 'breezy.commit_signature_commands'),
7131
('cmd_verify_signatures', [], 'breezy.commit_signature_commands'),
7132
('cmd_test_script', [], 'breezy.cmd_test_script'),
6854
('cmd_bisect', [], 'breezy.bisect'),
6855
('cmd_bundle_info', [], 'breezy.bundle.commands'),
6856
('cmd_config', [], 'breezy.config'),
6857
('cmd_dpush', [], 'breezy.foreign'),
6858
('cmd_version_info', [], 'breezy.cmd_version_info'),
6859
('cmd_resolve', ['resolved'], 'breezy.conflicts'),
6860
('cmd_conflicts', [], 'breezy.conflicts'),
6861
('cmd_ping', [], 'breezy.bzr.smart.ping'),
6862
('cmd_sign_my_commits', [], 'breezy.commit_signature_commands'),
6863
('cmd_verify_signatures', [], 'breezy.commit_signature_commands'),
6864
('cmd_test_script', [], 'breezy.cmd_test_script'),
7134
6866
builtin_command_registry.register_lazy(name, aliases, module_name)