442
443
def run(self, revision_id=None, revision=None, directory=u'.'):
443
444
if revision_id is not None and revision is not None:
444
raise errors.CommandError(gettext('You can only supply one of'
445
' revision_id or --revision'))
445
raise errors.BzrCommandError(gettext('You can only supply one of'
446
' revision_id or --revision'))
446
447
if revision_id is None and revision is None:
447
raise errors.CommandError(
448
gettext('You must supply either --revision or a revision_id'))
448
raise errors.BzrCommandError(gettext('You must supply either'
449
' --revision or a revision_id'))
450
451
b = controldir.ControlDir.open_containing_tree_or_branch(directory)[1]
452
revisions = getattr(b.repository, "revisions", None)
453
revisions = b.repository.revisions
453
454
if revisions is None:
454
raise errors.CommandError(
455
gettext('Repository %r does not support '
456
'access to raw revision texts') % b.repository)
455
raise errors.BzrCommandError(gettext('Repository %r does not support '
456
'access to raw revision texts'))
458
with b.repository.lock_read():
458
b.repository.lock_read()
459
460
# TODO: jam 20060112 should cat-revision always output utf-8?
460
461
if revision_id is not None:
461
462
revision_id = cache_utf8.encode(revision_id)
463
464
self.print_revision(revisions, revision_id)
464
465
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)
466
msg = gettext("The repository {0} contains no revision {1}.").format(
467
b.repository.base, revision_id)
468
raise errors.BzrCommandError(msg)
469
469
elif revision is not None:
470
470
for rev in revision:
472
raise errors.CommandError(
472
raise errors.BzrCommandError(
473
473
gettext('You cannot specify a NULL revision.'))
474
474
rev_id = rev.as_revision_id(b)
475
475
self.print_revision(revisions, rev_id)
477
b.repository.unlock()
480
class cmd_dump_btree(Command):
481
__doc__ = """Dump the contents of a btree index file to stdout.
483
PATH is a btree index file, it can be any URL. This includes things like
484
.bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
486
By default, the tuples stored in the index file will be displayed. With
487
--raw, we will uncompress the pages, but otherwise display the raw bytes
491
# TODO: Do we want to dump the internal nodes as well?
492
# TODO: It would be nice to be able to dump the un-parsed information,
493
# rather than only going through iter_all_entries. However, this is
494
# good enough for a start
496
encoding_type = 'exact'
497
takes_args = ['path']
498
takes_options = [Option('raw', help='Write the uncompressed bytes out,'
499
' rather than the parsed tuples.'),
502
def run(self, path, raw=False):
503
dirname, basename = osutils.split(path)
504
t = transport.get_transport(dirname)
506
self._dump_raw_bytes(t, basename)
508
self._dump_entries(t, basename)
510
def _get_index_and_bytes(self, trans, basename):
511
"""Create a BTreeGraphIndex and raw bytes."""
512
bt = btree_index.BTreeGraphIndex(trans, basename, None)
513
bytes = trans.get_bytes(basename)
514
bt._file = BytesIO(bytes)
515
bt._size = len(bytes)
518
def _dump_raw_bytes(self, trans, basename):
521
# We need to parse at least the root node.
522
# This is because the first page of every row starts with an
523
# uncompressed header.
524
bt, bytes = self._get_index_and_bytes(trans, basename)
525
for page_idx, page_start in enumerate(range(0, len(bytes),
526
btree_index._PAGE_SIZE)):
527
page_end = min(page_start + btree_index._PAGE_SIZE, len(bytes))
528
page_bytes = bytes[page_start:page_end]
530
self.outf.write('Root node:\n')
531
header_end, data = bt._parse_header_from_bytes(page_bytes)
532
self.outf.write(page_bytes[:header_end])
534
self.outf.write('\nPage %d\n' % (page_idx,))
535
if len(page_bytes) == 0:
536
self.outf.write('(empty)\n');
538
decomp_bytes = zlib.decompress(page_bytes)
539
self.outf.write(decomp_bytes)
540
self.outf.write('\n')
542
def _dump_entries(self, trans, basename):
544
st = trans.stat(basename)
545
except errors.TransportNotPossible:
546
# We can't stat, so we'll fake it because we have to do the 'get()'
548
bt, _ = self._get_index_and_bytes(trans, basename)
550
bt = btree_index.BTreeGraphIndex(trans, basename, st.st_size)
551
for node in bt.iter_all_entries():
552
# Node is made up of:
553
# (index, key, value, [references])
557
refs_as_tuples = None
559
refs_as_tuples = static_tuple.as_tuples(refs)
560
as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
561
self.outf.write('%s\n' % (as_tuple,))
478
564
class cmd_remove_tree(Command):
742
822
def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
743
823
file_ids_from=None):
744
824
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
827
if file_ids_from is not None:
756
829
base_tree, base_path = WorkingTree.open_containing(
758
831
except errors.NoWorkingTree:
759
832
base_branch, base_path = Branch.open_containing(
761
834
base_tree = base_branch.basis_tree()
763
action = breezy.add.AddFromBaseAction(
764
base_tree, base_path, to_file=self.outf,
836
action = breezy.add.AddFromBaseAction(base_tree, base_path,
837
to_file=self.outf, should_print=(not is_quiet()))
839
action = breezy.add.AddWithSkipLargeAction(to_file=self.outf,
765
840
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)
843
self.add_cleanup(base_tree.lock_read().unlock)
844
tree, file_list = tree_files_for_add(file_list)
845
added, ignored = tree.smart_add(file_list, not
846
no_recurse, action=action, save=not dry_run)
774
847
self.cleanup_now()
775
848
if len(ignored) > 0:
777
850
for glob in sorted(ignored):
778
851
for path in ignored[glob]:
780
gettext("ignored {0} matching \"{1}\"\n").format(
853
gettext("ignored {0} matching \"{1}\"\n").format(
784
857
class cmd_mkdir(Command):
858
931
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, '
935
help='List entries of a particular kind: file, directory, symlink.',
868
938
takes_args = ['file*']
871
def run(self, revision=None, show_ids=False, kind=None, include_root=False,
941
def run(self, revision=None, show_ids=False, kind=None, file_list=None):
873
942
if kind and kind not in ['file', 'directory', 'symlink']:
874
raise errors.CommandError(
875
gettext('invalid kind %r specified') % (kind,))
943
raise errors.BzrCommandError(gettext('invalid kind %r specified') % (kind,))
877
945
revision = _get_one_revision('inventory', revision)
878
946
work_tree, file_list = WorkingTree.open_containing_paths(file_list)
879
self.enter_context(work_tree.lock_read())
947
self.add_cleanup(work_tree.lock_read().unlock)
880
948
if revision is not None:
881
949
tree = revision.as_tree(work_tree.branch)
883
951
extra_trees = [work_tree]
884
self.enter_context(tree.lock_read())
952
self.add_cleanup(tree.lock_read().unlock)
889
self.enter_context(tree.lock_read())
957
self.add_cleanup(tree.lock_read().unlock)
890
958
if file_list is not None:
891
paths = tree.find_related_paths_across_trees(
892
file_list, extra_trees, require_versioned=True)
959
file_ids = tree.paths2ids(file_list, trees=extra_trees,
960
require_versioned=True)
893
961
# find_ids_across_trees may include some paths that don't
894
962
# exist in 'tree'.
895
entries = tree.iter_entries_by_dir(specific_files=paths)
963
entries = tree.iter_entries_by_dir(specific_file_ids=file_ids)
897
965
entries = tree.iter_entries_by_dir()
899
967
for path, entry in sorted(entries):
900
968
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')))
973
self.outf.write('%-50s %s\n' % (path, entry.file_id))
908
975
self.outf.write(path)
909
976
self.outf.write('\n')
912
class cmd_cp(Command):
913
__doc__ = """Copy a file.
916
brz cp OLDNAME NEWNAME
918
brz cp SOURCE... DESTINATION
920
If the last argument is a versioned directory, all the other names
921
are copied into it. Otherwise, there must be exactly two arguments
922
and the file is copied to a new name.
924
Files cannot be copied between branches. Only files can be copied
928
takes_args = ['names*']
931
encoding_type = 'replace'
933
def run(self, names_list):
934
if names_list is None:
936
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)
940
for file_name in rel_names[0:-1]:
942
raise errors.CommandError(
943
gettext("can not copy root of branch"))
944
self.enter_context(tree.lock_tree_write())
945
into_existing = osutils.isdir(names_list[-1])
946
if not into_existing:
948
(src, dst) = rel_names
950
raise errors.CommandError(
951
gettext('to copy multiple files the'
952
' destination must be a versioned'
957
(n, osutils.joinpath([rel_names[-1], osutils.basename(n)]))
958
for n in rel_names[:-1]]
960
for src, dst in pairs:
962
src_kind = tree.stored_kind(src)
963
except errors.NoSuchFile:
964
raise errors.CommandError(
965
gettext('Could not copy %s => %s: %s is not versioned.')
968
raise errors.CommandError(
969
gettext('Could not copy %s => %s . %s is not versioned\\.'
971
if src_kind == 'directory':
972
raise errors.CommandError(
973
gettext('Could not copy %s => %s . %s is a directory.'
975
dst_parent = osutils.split(dst)[0]
978
dst_parent_kind = tree.stored_kind(dst_parent)
979
except errors.NoSuchFile:
980
raise errors.CommandError(
981
gettext('Could not copy %s => %s: %s is not versioned.')
982
% (src, dst, dst_parent))
983
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))
988
tree.copy_one(src, dst)
991
979
class cmd_mv(Command):
992
980
__doc__ = """Move or rename a file.
1024
1011
return self.run_auto(names_list, after, dry_run)
1026
raise errors.CommandError(gettext('--dry-run requires --auto.'))
1013
raise errors.BzrCommandError(gettext('--dry-run requires --auto.'))
1027
1014
if names_list is None:
1028
1015
names_list = []
1029
1016
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)
1017
raise errors.BzrCommandError(gettext("missing file argument"))
1018
tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
1033
1019
for file_name in rel_names[0:-1]:
1034
1020
if file_name == '':
1035
raise errors.CommandError(
1036
gettext("can not move root of branch"))
1037
self.enter_context(tree.lock_tree_write())
1021
raise errors.BzrCommandError(gettext("can not move root of branch"))
1022
self.add_cleanup(tree.lock_tree_write().unlock)
1038
1023
self._run(tree, names_list, rel_names, after)
1040
1025
def run_auto(self, names_list, after, dry_run):
1041
1026
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.'))
1027
raise errors.BzrCommandError(gettext('Only one path may be specified to'
1045
raise errors.CommandError(
1046
gettext('--after cannot be specified with --auto.'))
1030
raise errors.BzrCommandError(gettext('--after cannot be specified with'
1047
1032
work_tree, file_list = WorkingTree.open_containing_paths(
1048
1033
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)
1034
self.add_cleanup(work_tree.lock_tree_write().unlock)
1035
rename_map.RenameMap.guess_renames(work_tree, dry_run)
1053
1037
def _run(self, tree, names_list, rel_names, after):
1054
1038
into_existing = osutils.isdir(names_list[-1])
1311
1293
_see_also = ['pull', 'update', 'working-trees']
1312
1294
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.")
1295
Option('create-prefix',
1296
help='Create the path leading up to the branch '
1297
'if it does not already exist.'),
1298
custom_help('directory',
1299
help='Branch to push from, '
1300
'rather than the one containing the working directory.'),
1301
Option('use-existing-dir',
1302
help='By default push will fail if the target'
1303
' directory exists, but does not already'
1304
' have a control directory. This flag will'
1305
' allow push to proceed.'),
1307
help='Create a stacked branch that references the public location '
1308
'of the parent branch.'),
1309
Option('stacked-on',
1310
help='Create a stacked branch that refers to another branch '
1311
'for the commit history. Only the work not present in the '
1312
'referenced branch is included in the branch created.',
1315
help='Refuse to push if there are uncommitted changes in'
1316
' the working tree, --no-strict disables the check.'),
1318
help="Don't populate the working tree, even for protocols"
1319
" that support it."),
1320
Option('overwrite-tags',
1321
help="Overwrite tags only."),
1343
1323
takes_args = ['location?']
1344
1324
encoding_type = 'replace'
1346
1326
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
1327
create_prefix=False, verbose=False, revision=None,
1328
use_existing_dir=False, directory=None, stacked_on=None,
1329
stacked=False, strict=None, no_tree=False,
1330
overwrite_tags=False):
1352
1331
from .push import _show_push_branch
1433
1410
To retrieve the branch as of a particular revision, supply the --revision
1434
1411
parameter, as in "branch foo/bar -r 5".
1413
The synonyms 'clone' and 'get' for this command are deprecated.
1438
1416
_see_also = ['checkout']
1439
1417
takes_args = ['from_location', 'to_location?']
1440
1418
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.'),
1419
Option('hardlink', help='Hard-link working tree files where possible.'),
1420
Option('files-from', type=str,
1421
help="Get file contents from this tree."),
1423
help="Create a branch without a working-tree."),
1425
help="Switch the checkout in the current directory "
1426
"to the new branch."),
1428
help='Create a stacked branch referring to the source branch. '
1429
'The new branch will depend on the availability of the source '
1430
'branch for all operations.'),
1431
Option('standalone',
1432
help='Do not use a shared repository, even if available.'),
1433
Option('use-existing-dir',
1434
help='By default branch will fail if the target'
1435
' directory exists, but does not already'
1436
' have a control directory. This flag will'
1437
' allow branch to proceed.'),
1439
help="Bind new branch to from location."),
1441
aliases = ['get', 'clone']
1469
1443
def run(self, from_location, to_location=None, revision=None,
1470
1444
hardlink=False, stacked=False, standalone=False, no_tree=False,
1471
1445
use_existing_dir=False, switch=False, bind=False,
1472
files_from=None, no_recurse_nested=False, colocated_branch=None):
1473
1447
from breezy import switch as _mod_switch
1448
if self.invoked_as in ['get', 'clone']:
1449
ui.ui_factory.show_user_warning(
1450
'deprecated_command',
1451
deprecated_name=self.invoked_as,
1452
recommended_name='branch',
1453
deprecated_in_version='2.4')
1474
1454
accelerator_tree, br_from = controldir.ControlDir.open_tree_or_branch(
1475
from_location, name=colocated_branch)
1476
if no_recurse_nested:
1480
1456
if not (hardlink or files_from):
1481
1457
# accelerator_tree is usually slower because you have to read N
1482
1458
# files (no readahead, lots of seeks, etc), but allow the user to
1517
1495
raise errors.AlreadyBranchError(to_location)
1518
1496
except errors.NoSuchFile:
1519
raise errors.CommandError(gettext('Parent of "%s" does not exist.')
1497
raise errors.BzrCommandError(gettext('Parent of "%s" does not exist.')
1523
1501
if to_dir is None:
1525
1503
# preserve whatever source format we have.
1526
to_dir = br_from.controldir.sprout(
1527
to_transport.base, revision_id,
1528
possible_transports=[to_transport],
1529
accelerator_tree=accelerator_tree, hardlink=hardlink,
1530
stacked=stacked, force_new_repo=standalone,
1531
create_tree_if_local=not no_tree, source_branch=br_from,
1504
to_dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1505
possible_transports=[to_transport],
1506
accelerator_tree=accelerator_tree,
1507
hardlink=hardlink, stacked=stacked,
1508
force_new_repo=standalone,
1509
create_tree_if_local=not no_tree,
1510
source_branch=br_from)
1533
1511
branch = to_dir.open_branch(
1534
1512
possible_transports=[
1535
br_from.controldir.root_transport, to_transport])
1513
br_from.bzrdir.root_transport, to_transport])
1536
1514
except errors.NoSuchRevision:
1537
1515
to_transport.delete_tree('.')
1538
1516
msg = gettext("The branch {0} has no revision {1}.").format(
1539
1517
from_location, revision)
1540
raise errors.CommandError(msg)
1518
raise errors.BzrCommandError(msg)
1543
1521
to_repo = to_dir.open_repository()
1544
1522
except errors.NoRepositoryPresent:
1545
1523
to_repo = to_dir.create_repository()
1546
1524
to_repo.fetch(br_from.repository, revision_id=revision_id)
1547
branch = br_from.sprout(
1548
to_dir, revision_id=revision_id)
1525
branch = br_from.sprout(to_dir, revision_id=revision_id)
1549
1526
br_from.tags.merge_to(branch.tags)
1551
1528
# If the source branch is stacked, the new branch may
1918
1860
class cmd_remove(Command):
1919
1861
__doc__ = """Remove files or directories.
1921
This makes Breezy stop tracking changes to the specified files. Breezy will
1863
This makes Bazaar stop tracking changes to the specified files. Bazaar will
1922
1864
delete them if they can easily be recovered using revert otherwise they
1923
1865
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.
1866
parameters are given Bazaar will scan for files that are being tracked by
1867
Bazaar but missing in your tree and stop tracking them for you.
1927
1869
takes_args = ['file*']
1928
1870
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.'),
1871
Option('new', help='Only remove files that have never been committed.'),
1872
RegistryOption.from_kwargs('file-deletion-strategy',
1873
'The file deletion mode to be used.',
1874
title='Deletion Strategy', value_switches=True, enum_switch=False,
1875
safe='Backup changed files (default).',
1876
keep='Delete from brz but leave the working copy.',
1877
no_backup='Don\'t backup changed files.'),
1938
1879
aliases = ['rm', 'del']
1939
1880
encoding_type = 'replace'
1941
1882
def run(self, file_list, verbose=False, new=False,
1942
file_deletion_strategy='safe'):
1883
file_deletion_strategy='safe'):
1944
1885
tree, file_list = WorkingTree.open_containing_paths(file_list)
1946
1887
if file_list is not None:
1947
1888
file_list = [f for f in file_list]
1949
self.enter_context(tree.lock_write())
1890
self.add_cleanup(tree.lock_write().unlock)
1950
1891
# Heuristics should probably all move into tree.remove_smart or
1953
1894
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)
1895
specific_files=file_list).added
1896
file_list = sorted([f[0] for f in added], reverse=True)
1956
1897
if len(file_list) == 0:
1957
raise errors.CommandError(gettext('No matching files.'))
1898
raise errors.BzrCommandError(gettext('No matching files.'))
1958
1899
elif file_list is None:
1959
1900
# missing files show up in iter_changes(basis) as
1960
1901
# versioned-with-no-kind.
1962
1903
for change in tree.iter_changes(tree.basis_tree()):
1963
1904
# 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])
1905
if change[1][1] is not None and change[6][1] is None:
1906
missing.append(change[1][1])
1966
1907
file_list = sorted(missing, reverse=True)
1967
1908
file_deletion_strategy = 'keep'
1968
1909
tree.remove(file_list, verbose=verbose, to_file=self.outf,
1969
keep_files=file_deletion_strategy == 'keep',
1970
force=(file_deletion_strategy == 'no-backup'))
1910
keep_files=file_deletion_strategy=='keep',
1911
force=(file_deletion_strategy=='no-backup'))
1914
class cmd_file_id(Command):
1915
__doc__ = """Print file_id of a particular file or directory.
1917
The file_id is assigned when the file is first added and remains the
1918
same through all revisions where the file exists, even when it is
1923
_see_also = ['inventory', 'ls']
1924
takes_args = ['filename']
1927
def run(self, filename):
1928
tree, relpath = WorkingTree.open_containing(filename)
1929
i = tree.path2id(relpath)
1931
raise errors.NotVersionedError(filename)
1933
self.outf.write(i + '\n')
1936
class cmd_file_path(Command):
1937
__doc__ = """Print path of file_ids to a file or directory.
1939
This prints one line for each directory down to the target,
1940
starting at the branch root.
1944
takes_args = ['filename']
1947
def run(self, filename):
1948
tree, relpath = WorkingTree.open_containing(filename)
1949
fid = tree.path2id(relpath)
1951
raise errors.NotVersionedError(filename)
1952
segments = osutils.splitpath(relpath)
1953
for pos in range(1, len(segments) + 1):
1954
path = osutils.joinpath(segments[:pos])
1955
self.outf.write("%s\n" % tree.path2id(path))
1973
1958
class cmd_reconcile(Command):
2136
2118
branch = create_branch(to_transport.base, format=format,
2137
2119
possible_transports=[to_transport],
2138
2120
force_new_tree=force_new_tree)
2139
a_controldir = branch.controldir
2121
a_bzrdir = branch.bzrdir
2141
2123
from .transport.local import LocalTransport
2142
if a_controldir.has_branch():
2124
if a_bzrdir.has_branch():
2143
2125
if (isinstance(to_transport, LocalTransport)
2144
and not a_controldir.has_workingtree()):
2145
raise errors.BranchExistsWithoutWorkingTree(location)
2126
and not a_bzrdir.has_workingtree()):
2127
raise errors.BranchExistsWithoutWorkingTree(location)
2146
2128
raise errors.AlreadyBranchError(location)
2147
branch = a_controldir.create_branch()
2148
if not no_tree and not a_controldir.has_workingtree():
2149
a_controldir.create_workingtree()
2129
branch = a_bzrdir.create_branch()
2130
if not no_tree and not a_bzrdir.has_workingtree():
2131
a_bzrdir.create_workingtree()
2150
2132
if append_revisions_only:
2152
2134
branch.set_append_revisions_only(True)
2153
2135
except errors.UpgradeRequired:
2154
raise errors.CommandError(gettext('This branch format cannot be set'
2155
' to append-revisions-only. Try --default.'))
2136
raise errors.BzrCommandError(gettext('This branch format cannot be set'
2137
' to append-revisions-only. Try --default.'))
2156
2138
if not is_quiet():
2157
2139
from .info import describe_layout, describe_format
2159
tree = a_controldir.open_workingtree(recommend_upgrade=False)
2141
tree = a_bzrdir.open_workingtree(recommend_upgrade=False)
2160
2142
except (errors.NoWorkingTree, errors.NotLocalUrl):
2162
2144
repository = branch.repository
2163
2145
layout = describe_layout(repository, branch, tree).lower()
2164
format = describe_format(a_controldir, repository, branch, tree)
2146
format = describe_format(a_bzrdir, repository, branch, tree)
2165
2147
self.outf.write(gettext("Created a {0} (format: {1})\n").format(
2167
2149
if repository.is_shared():
2168
# XXX: maybe this can be refactored into transport.path_or_url()
2169
url = repository.controldir.root_transport.external_url()
2150
#XXX: maybe this can be refactored into transport.path_or_url()
2151
url = repository.bzrdir.root_transport.external_url()
2171
2153
url = urlutils.local_path_from_url(url)
2172
except urlutils.InvalidURL:
2154
except errors.InvalidURL:
2174
2156
self.outf.write(gettext("Using shared repository: %s\n") % url)
2177
class cmd_init_shared_repository(Command):
2159
class cmd_init_repository(Command):
2178
2160
__doc__ = """Create a shared repository for branches to share storage space.
2180
2162
New branches created under the repository directory will store their
2181
2163
revisions in the repository, not in the branch directory. For branches
2182
with shared history, this reduces the amount of storage needed and
2164
with shared history, this reduces the amount of storage needed and
2183
2165
speeds up the creation of new branches.
2185
2167
If the --no-trees option is given then the branches in the repository
2186
will not have working trees by default. They will still exist as
2187
directories on disk, but they will not have separate copies of the
2168
will not have working trees by default. They will still exist as
2169
directories on disk, but they will not have separate copies of the
2188
2170
files at a certain revision. This can be useful for repositories that
2189
2171
store branches which are interacted with through checkouts or remote
2190
2172
branches, such as on a server.
2205
2187
_see_also = ['init', 'branch', 'checkout', 'repositories']
2206
2188
takes_args = ["location"]
2207
2189
takes_options = [RegistryOption('format',
2208
help='Specify a format for this repository. See'
2209
' "brz help formats" for details.',
2211
'breezy.controldir', 'format_registry'),
2212
converter=lambda name: controldir.format_registry.make_controldir(
2214
value_switches=True, title='Repository format'),
2190
help='Specify a format for this repository. See'
2191
' "brz help formats" for details.',
2192
lazy_registry=('breezy.controldir', 'format_registry'),
2193
converter=lambda name: controldir.format_registry.make_bzrdir(name),
2194
value_switches=True, title='Repository format'),
2215
2195
Option('no-trees',
2216
help='Branches in the repository will default to'
2217
' not having a working tree.'),
2219
aliases = ["init-shared-repo", "init-repo"]
2196
help='Branches in the repository will default to'
2197
' not having a working tree.'),
2199
aliases = ["init-repo"]
2221
2201
def run(self, location, format=None, no_trees=False):
2222
2202
if format is None:
2223
format = controldir.format_registry.make_controldir('default')
2203
format = controldir.format_registry.make_bzrdir('default')
2225
2205
if location is None:
2228
to_transport = transport.get_transport(location, purpose='write')
2230
if format.fixed_components:
2231
repo_format_name = None
2233
repo_format_name = format.repository_format.get_format_string()
2208
to_transport = transport.get_transport(location)
2235
2210
(repo, newdir, require_stacking, repository_policy) = (
2236
2211
format.initialize_on_transport_ex(to_transport,
2237
create_prefix=True, make_working_trees=not no_trees,
2238
shared_repo=True, force_new_repo=True,
2239
use_existing_dir=True,
2240
repo_format_name=repo_format_name))
2212
create_prefix=True, make_working_trees=not no_trees,
2213
shared_repo=True, force_new_repo=True,
2214
use_existing_dir=True,
2215
repo_format_name=format.repository_format.get_format_string()))
2241
2216
if not is_quiet():
2242
2217
from .info import show_bzrdir_info
2243
2218
show_bzrdir_info(newdir, verbose=0, outfile=self.outf)
2339
2314
help='Set prefixes added to old and new filenames, as '
2340
2315
'two values separated by a colon. (eg "old/:new/").'),
2342
help='Branch/tree to compare from.',
2317
help='Branch/tree to compare from.',
2346
help='Branch/tree to compare to.',
2321
help='Branch/tree to compare to.',
2351
2326
Option('using',
2352
help='Use this command to compare files.',
2327
help='Use this command to compare files.',
2355
2330
RegistryOption('format',
2357
help='Diff format to use.',
2358
lazy_registry=('breezy.diff', 'format_registry'),
2359
title='Diff format'),
2332
help='Diff format to use.',
2333
lazy_registry=('breezy.diff', 'format_registry'),
2334
title='Diff format'),
2360
2335
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'
2336
help='How many lines of context to show.',
2378
2340
aliases = ['di', 'dif']
2379
2341
encoding_type = 'exact'
2381
2343
@display_command
2382
2344
def run(self, revision=None, file_list=None, diff_options=None,
2383
2345
prefix=None, old=None, new=None, using=None, format=None,
2384
context=None, color='never'):
2385
2347
from .diff import (get_trees_and_branches_to_diff_locked,
2389
2351
# diff -p0 format
2392
elif prefix == u'1' or prefix is None:
2354
elif prefix == '1' or prefix is None:
2393
2355
old_label = 'old/'
2394
2356
new_label = 'new/'
2395
elif u':' in prefix:
2396
old_label, new_label = prefix.split(u":")
2358
old_label, new_label = prefix.split(":")
2398
raise errors.CommandError(gettext(
2360
raise errors.BzrCommandError(gettext(
2399
2361
'--prefix expects two values separated by a colon'
2400
2362
' (eg "old/:new/")'))
2402
2364
if revision and len(revision) > 2:
2403
raise errors.CommandError(gettext('brz diff --revision takes exactly'
2404
' one or two revision specifiers'))
2365
raise errors.BzrCommandError(gettext('brz diff --revision takes exactly'
2366
' one or two revision specifiers'))
2406
2368
if using is not None and format is not None:
2407
raise errors.CommandError(gettext(
2369
raise errors.BzrCommandError(gettext(
2408
2370
'{0} and {1} are mutually exclusive').format(
2409
2371
'--using', '--format'))
2411
2373
(old_tree, new_tree,
2412
2374
old_branch, new_branch,
2413
2375
specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
2414
file_list, revision, old, new, self._exit_stack, apply_view=True)
2376
file_list, revision, old, new, self.add_cleanup, apply_view=True)
2415
2377
# GNU diff on Windows uses ANSI encoding for filenames
2416
2378
path_encoding = osutils.get_diff_header_encoding()
2419
from .terminal import has_ansi_colors
2420
if has_ansi_colors():
2424
if 'always' == color:
2425
from .colordiff import DiffWriter
2426
outf = DiffWriter(outf)
2427
return show_diff_trees(old_tree, new_tree, outf,
2379
return show_diff_trees(old_tree, new_tree, sys.stdout,
2428
2380
specific_files=specific_files,
2429
2381
external_diff_options=diff_options,
2430
2382
old_label=old_label, new_label=new_label,
2698
2651
takes_args = ['file*']
2699
2652
_see_also = ['log-formats', 'revisionspec']
2700
2653
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',
2655
help='Show from oldest to newest.'),
2657
custom_help('verbose',
2658
help='Show files changed in each revision.'),
2662
type=breezy.option._parse_revision_str,
2664
help='Show just the specified revision.'
2665
' See also "help revisionspec".'),
2667
RegistryOption('authors',
2668
'What names to list as authors - first, all or committer.',
2670
lazy_registry=('breezy.log', 'author_list_registry'),
2674
help='Number of levels to display - 0 for all, 1 for flat.',
2676
type=_parse_levels),
2678
help='Show revisions whose message matches this '
2679
'regular expression.',
2684
help='Limit the output to the first N revisions.',
2689
help='Show changes made in each revision as a patch.'),
2690
Option('include-merged',
2691
help='Show merged revisions like --levels 0 does.'),
2692
Option('include-merges', hidden=True,
2693
help='Historical alias for --include-merged.'),
2694
Option('omit-merges',
2695
help='Do not report commits with more than one parent.'),
2696
Option('exclude-common-ancestry',
2697
help='Display only the revisions that are not part'
2698
' of both ancestries (require -rX..Y).'
2700
Option('signatures',
2701
help='Show digital signature validity.'),
2704
help='Show revisions whose properties match this '
2707
ListOption('match-message',
2708
help='Show revisions whose message matches this '
2711
ListOption('match-committer',
2760
2712
help='Show revisions whose committer matches this '
2763
ListOption('match-author',
2715
ListOption('match-author',
2764
2716
help='Show revisions whose authors match this '
2767
ListOption('match-bugs',
2719
ListOption('match-bugs',
2768
2720
help='Show revisions whose bugs match this '
2772
2724
encoding_type = 'replace'
2774
2726
@display_command
3018
2969
_see_also = ['status', 'cat']
3019
2970
takes_args = ['path?']
3020
2971
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.'),
2974
Option('recursive', short_name='R',
2975
help='Recurse into subdirectories.'),
2977
help='Print paths relative to the root of the branch.'),
2978
Option('unknown', short_name='u',
2979
help='Print unknown files.'),
2980
Option('versioned', help='Print versioned files.',
2982
Option('ignored', short_name='i',
2983
help='Print ignored files.'),
2984
Option('kind', short_name='k',
2985
help='List entries of a particular kind: file, directory, symlink.',
3042
2991
@display_command
3043
2992
def run(self, revision=None, verbose=False,
3044
2993
recursive=False, from_root=False,
3045
2994
unknown=False, versioned=False, ignored=False,
3046
2995
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'))
2997
if kind and kind not in ('file', 'directory', 'symlink'):
2998
raise errors.BzrCommandError(gettext('invalid kind specified'))
3051
3000
if verbose and null:
3052
raise errors.CommandError(
3053
gettext('Cannot set both --verbose and --null'))
3001
raise errors.BzrCommandError(gettext('Cannot set both --verbose and --null'))
3054
3002
all = not (unknown or versioned or ignored)
3056
selection = {'I': ignored, '?': unknown, 'V': versioned}
3004
selection = {'I':ignored, '?':unknown, 'V':versioned}
3058
3006
if path is None:
3062
raise errors.CommandError(gettext('cannot specify both --from-root'
3010
raise errors.BzrCommandError(gettext('cannot specify both --from-root'
3065
3013
tree, branch, relpath = \
3066
3014
_open_directory_or_containing_tree_or_branch(fs_path, directory)
3443
3368
def run(self, filename, revision=None, name_from_revision=False,
3444
3369
filters=False, directory=None):
3445
3370
if revision is not None and len(revision) != 1:
3446
raise errors.CommandError(gettext("brz cat --revision takes exactly"
3447
" one revision specifier"))
3371
raise errors.BzrCommandError(gettext("brz cat --revision takes exactly"
3372
" one revision specifier"))
3448
3373
tree, branch, relpath = \
3449
3374
_open_directory_or_containing_tree_or_branch(filename, directory)
3450
self.enter_context(branch.lock_read())
3375
self.add_cleanup(branch.lock_read().unlock)
3451
3376
return self._run(tree, branch, relpath, filename, revision,
3452
3377
name_from_revision, filters)
3454
3379
def _run(self, tree, b, relpath, filename, revision, name_from_revision,
3457
3381
if tree is None:
3458
3382
tree = b.basis_tree()
3459
3383
rev_tree = _get_one_revision_tree('cat', revision, branch=b)
3460
self.enter_context(rev_tree.lock_read())
3384
self.add_cleanup(rev_tree.lock_read().unlock)
3386
old_file_id = rev_tree.path2id(relpath)
3388
# TODO: Split out this code to something that generically finds the
3389
# best id for a path across one or more trees; it's like
3390
# find_ids_across_trees but restricted to find just one. -- mbp
3462
3392
if name_from_revision:
3463
3393
# Try in revision if requested
3464
if not rev_tree.is_versioned(relpath):
3465
raise errors.CommandError(gettext(
3394
if old_file_id is None:
3395
raise errors.BzrCommandError(gettext(
3466
3396
"{0!r} is not present in revision {1}").format(
3467
3397
filename, rev_tree.get_revision_id()))
3468
rev_tree_path = relpath
3399
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
3401
cur_file_id = tree.path2id(relpath)
3402
if cur_file_id is not None and rev_tree.has_id(cur_file_id):
3403
actual_file_id = cur_file_id
3404
elif old_file_id is not None:
3405
actual_file_id = old_file_id
3407
raise errors.BzrCommandError(gettext(
3408
"{0!r} is not present in revision {1}").format(
3409
filename, rev_tree.get_revision_id()))
3487
3411
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)
3412
filter_tree = ContentFilterTree(rev_tree,
3413
rev_tree._content_filter_stack)
3414
content = filter_tree.get_file_text(actual_file_id)
3492
fileobj = rev_tree.get_file(rev_tree_path)
3493
shutil.copyfileobj(fileobj, self.outf)
3416
content = rev_tree.get_file_text(actual_file_id)
3494
3417
self.cleanup_now()
3418
self.outf.write(content)
3497
3421
class cmd_local_time_offset(Command):
3498
3422
__doc__ = """Show the offset in seconds from GMT to local time."""
3501
3424
@display_command
3503
3426
self.outf.write("%s\n" % osutils.local_time_offset())
3506
3430
class cmd_commit(Command):
3507
3431
__doc__ = """Commit changes into a new revision.
3563
3487
_see_also = ['add', 'bugs', 'hooks', 'uncommit']
3564
3488
takes_args = ['selected*']
3565
3489
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 '
3490
ListOption('exclude', type=str, short_name='x',
3491
help="Do not consider changes made to a given path."),
3492
Option('message', type=text_type,
3494
help="Description of the new revision."),
3497
help='Commit even if nothing has changed.'),
3498
Option('file', type=str,
3501
help='Take commit message from this file.'),
3503
help="Refuse to commit if there are unknown "
3504
"files in the working tree."),
3505
Option('commit-time', type=str,
3506
help="Manually set a commit time using commit date "
3507
"format, e.g. '2009-10-10 08:00:00 +0100'."),
3508
ListOption('fixes', type=str,
3509
help="Mark a bug as being fixed by this revision "
3510
"(see \"brz help bugs\")."),
3511
ListOption('author', type=text_type,
3512
help="Set the author's name, if it's different "
3513
"from the committer."),
3515
help="Perform a local commit in a bound "
3516
"branch. Local commits are not pushed to "
3517
"the master branch until a normal commit "
3520
Option('show-diff', short_name='p',
3521
help='When no message is supplied, show the diff along'
3522
' with the status summary in the message editor.'),
3524
help='When committing to a foreign version control '
3525
'system do not push data that can not be natively '
3609
3528
aliases = ['ci', 'checkin']
3611
def _iter_bug_urls(self, bugs, branch, status):
3612
default_bugtracker = None
3530
def _iter_bug_fix_urls(self, fixes, branch):
3531
default_bugtracker = None
3613
3532
# Configure the properties for bug fixing attributes.
3615
tokens = bug.split(':')
3533
for fixed_bug in fixes:
3534
tokens = fixed_bug.split(':')
3616
3535
if len(tokens) == 1:
3617
3536
if default_bugtracker is None:
3618
3537
branch_config = branch.get_config_stack()
3619
3538
default_bugtracker = branch_config.get(
3621
3540
if default_bugtracker is None:
3622
raise errors.CommandError(gettext(
3541
raise errors.BzrCommandError(gettext(
3623
3542
"No tracker specified for bug %s. Use the form "
3624
3543
"'tracker:id' or specify a default bug tracker "
3625
3544
"using the `bugtracker` option.\nSee "
3626
3545
"\"brz help bugs\" for more information on this "
3627
"feature. Commit refused.") % bug)
3546
"feature. Commit refused.") % fixed_bug)
3628
3547
tag = default_bugtracker
3629
3548
bug_id = tokens[0]
3630
3549
elif len(tokens) != 2:
3631
raise errors.CommandError(gettext(
3550
raise errors.BzrCommandError(gettext(
3632
3551
"Invalid bug %s. Must be in the form of 'tracker:id'. "
3633
3552
"See \"brz help bugs\" for more information on this "
3634
"feature.\nCommit refused.") % bug)
3553
"feature.\nCommit refused.") % fixed_bug)
3636
3555
tag, bug_id = tokens
3638
yield bugtracker.get_bug_url(tag, branch, bug_id), status
3639
except bugtracker.UnknownBugTrackerAbbreviation:
3640
raise errors.CommandError(gettext(
3641
'Unrecognized bug %s. Commit refused.') % bug)
3642
except bugtracker.MalformedBugIdentifier as e:
3643
raise errors.CommandError(gettext(
3644
u"%s\nCommit refused.") % (e,))
3557
yield bugtracker.get_bug_url(tag, branch, bug_id)
3558
except errors.UnknownBugTrackerAbbreviation:
3559
raise errors.BzrCommandError(gettext(
3560
'Unrecognized bug %s. Commit refused.') % fixed_bug)
3561
except errors.MalformedBugIdentifier as e:
3562
raise errors.BzrCommandError(gettext(
3563
"%s\nCommit refused.") % (str(e),))
3646
3565
def run(self, message=None, file=None, verbose=False, selected_list=None,
3647
unchanged=False, strict=False, local=False, fixes=None, bugs=None,
3566
unchanged=False, strict=False, local=False, fixes=None,
3648
3567
author=None, show_diff=False, exclude=None, commit_time=None,
3651
from .commit import (
3569
from .errors import (
3652
3570
PointlessCommit,
3654
from .errors import (
3655
3571
ConflictsInTree,
3656
3572
StrictCommitFailed
4217
4124
# too heavily. The call should be as early as possible, as
4218
4125
# error reporting for past duplicate imports won't have useful
4220
if sys.version_info[0] < 3:
4221
# TODO(pad.lv/1696545): Allow proxying on Python 3, since
4222
# disallowing it currently leads to failures in many places.
4223
lazy_import.disallow_proxying()
4127
lazy_import.disallow_proxying()
4227
except ImportError as e:
4228
raise errors.CommandError("tests not available. Install the "
4229
"breezy tests to run the breezy testsuite.")
4231
4131
if testspecs_list is not None:
4232
4132
pattern = '|'.join(testspecs_list)
4237
from .tests import SubUnitBzrRunnerv1
4137
from .tests import SubUnitBzrRunner
4238
4138
except ImportError:
4239
raise errors.CommandError(gettext(
4240
"subunit not available. subunit needs to be installed "
4241
"to use --subunit."))
4242
self.additional_selftest_args['runner_class'] = SubUnitBzrRunnerv1
4139
raise errors.BzrCommandError(gettext("subunit not available. subunit "
4140
"needs to be installed to use --subunit."))
4141
self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
4243
4142
# On Windows, disable automatic conversion of '\n' to '\r\n' in
4244
# stdout, which would corrupt the subunit stream.
4143
# stdout, which would corrupt the subunit stream.
4245
4144
# FIXME: This has been fixed in subunit trunk (>0.0.5) so the
4246
4145
# following code can be deleted when it's sufficiently deployed
4247
4146
# -- vila/mgz 20100514
4248
4147
if (sys.platform == "win32"
4249
and getattr(sys.stdout, 'fileno', None) is not None):
4148
and getattr(sys.stdout, 'fileno', None) is not None):
4251
4150
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
4254
from .tests import SubUnitBzrRunnerv2
4256
raise errors.CommandError(gettext(
4257
"subunit not available. subunit "
4258
"needs to be installed to use --subunit2."))
4259
self.additional_selftest_args['runner_class'] = SubUnitBzrRunnerv2
4262
4152
self.additional_selftest_args.setdefault(
4263
4153
'suite_decorators', []).append(parallel)
4265
raise errors.CommandError(gettext(
4155
raise errors.BzrCommandError(gettext(
4266
4156
"--benchmark is no longer supported from brz 2.2; "
4267
4157
"use bzr-usertest instead"))
4268
4158
test_suite_factory = None
4502
4395
change_reporter = delta._ChangeReporter(
4503
4396
unversioned_filter=tree.is_ignored, view_info=view_info)
4504
4397
pb = ui.ui_factory.nested_progress_bar()
4505
self.enter_context(pb)
4506
self.enter_context(tree.lock_write())
4398
self.add_cleanup(pb.finished)
4399
self.add_cleanup(tree.lock_write().unlock)
4507
4400
if location is not None:
4509
mergeable = _mod_mergeable.read_mergeable_from_url(
4510
location, possible_transports=possible_transports)
4402
mergeable = bundle.read_mergeable_from_url(location,
4403
possible_transports=possible_transports)
4511
4404
except errors.NotABundle:
4512
4405
mergeable = None
4514
4407
if uncommitted:
4515
raise errors.CommandError(gettext('Cannot use --uncommitted'
4516
' with bundles or merge directives.'))
4408
raise errors.BzrCommandError(gettext('Cannot use --uncommitted'
4409
' with bundles or merge directives.'))
4518
4411
if revision is not None:
4519
raise errors.CommandError(gettext(
4412
raise errors.BzrCommandError(gettext(
4520
4413
'Cannot use -r with merge directives or bundles'))
4521
4414
merger, verified = _mod_merge.Merger.from_mergeable(tree,
4524
4417
if merger is None and uncommitted:
4525
4418
if revision is not None and len(revision) > 0:
4526
raise errors.CommandError(gettext('Cannot use --uncommitted and'
4527
' --revision at the same time.'))
4419
raise errors.BzrCommandError(gettext('Cannot use --uncommitted and'
4420
' --revision at the same time.'))
4528
4421
merger = self.get_merger_from_uncommitted(tree, location, None)
4529
4422
allow_pending = False
4531
4424
if merger is None:
4532
4425
merger, allow_pending = self._get_merger_from_branch(tree,
4533
location, revision, remember, possible_transports, None)
4426
location, revision, remember, possible_transports, None)
4535
4428
merger.merge_type = merge_type
4536
4429
merger.reprocess = reprocess
4537
4430
merger.show_base = show_base
4538
4431
self.sanity_check_merger(merger)
4539
4432
if (merger.base_rev_id == merger.other_rev_id and
4540
merger.other_rev_id is not None):
4433
merger.other_rev_id is not None):
4541
4434
# check if location is a nonexistent file (and not a branch) to
4542
4435
# disambiguate the 'Nothing to do'
4543
4436
if merger.interesting_files:
4544
4437
if not merger.other_tree.has_filename(
4545
merger.interesting_files[0]):
4438
merger.interesting_files[0]):
4546
4439
note(gettext("merger: ") + str(merger))
4547
4440
raise errors.PathsDoNotExist([location])
4548
4441
note(gettext('Nothing to do.'))
4550
4443
if pull and not preview:
4551
4444
if merger.interesting_files is not None:
4552
raise errors.CommandError(
4553
gettext('Cannot pull individual files'))
4445
raise errors.BzrCommandError(gettext('Cannot pull individual files'))
4554
4446
if (merger.base_rev_id == tree.last_revision()):
4555
4447
result = tree.pull(merger.other_branch, False,
4556
4448
merger.other_rev_id)
4557
4449
result.report(self.outf)
4559
4451
if merger.this_basis is None:
4560
raise errors.CommandError(gettext(
4452
raise errors.BzrCommandError(gettext(
4561
4453
"This branch has no commits."
4562
4454
" (perhaps you would prefer 'brz pull')"))
4792
4674
if merge_type is None:
4793
4675
merge_type = _mod_merge.Merge3Merger
4794
4676
tree, file_list = WorkingTree.open_containing_paths(file_list)
4795
self.enter_context(tree.lock_write())
4677
self.add_cleanup(tree.lock_write().unlock)
4796
4678
parents = tree.get_parent_ids()
4797
4679
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
4680
raise errors.BzrCommandError(gettext("Sorry, remerge only works after normal"
4681
" merges. Not cherrypicking or"
4683
repository = tree.branch.repository
4684
interesting_ids = None
4802
4685
new_conflicts = []
4803
4686
conflicts = tree.conflicts()
4804
4687
if file_list is not None:
4805
interesting_files = set()
4688
interesting_ids = set()
4806
4689
for filename in file_list:
4807
if not tree.is_versioned(filename):
4690
file_id = tree.path2id(filename)
4808
4692
raise errors.NotVersionedError(filename)
4809
interesting_files.add(filename)
4810
if tree.kind(filename) != "directory":
4693
interesting_ids.add(file_id)
4694
if tree.kind(file_id) != "directory":
4813
for path, ie in tree.iter_entries_by_dir(
4814
specific_files=[filename]):
4815
interesting_files.add(path)
4697
# FIXME: Support nested trees
4698
for name, ie in tree.root_inventory.iter_entries(file_id):
4699
interesting_ids.add(ie.file_id)
4816
4700
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4818
4702
# Remerge only supports resolving contents conflicts
4819
4703
allowed_conflicts = ('text conflict', 'contents conflict')
4820
4704
restore_files = [c.path for c in conflicts
4821
4705
if c.typestring in allowed_conflicts]
4822
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_files)
4706
_mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
4823
4707
tree.set_conflicts(ConflictList(new_conflicts))
4824
4708
if file_list is not None:
4825
4709
restore_files = file_list
5289
5170
wt, branch, relpath = \
5290
5171
_open_directory_or_containing_tree_or_branch(filename, directory)
5291
5172
if wt is not None:
5292
self.enter_context(wt.lock_read())
5173
self.add_cleanup(wt.lock_read().unlock)
5294
self.enter_context(branch.lock_read())
5175
self.add_cleanup(branch.lock_read().unlock)
5295
5176
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)
5177
self.add_cleanup(tree.lock_read().unlock)
5178
if wt is not None and revision is None:
5179
file_id = wt.path2id(relpath)
5181
file_id = tree.path2id(relpath)
5183
raise errors.NotVersionedError(filename)
5184
if wt is not None and revision is None:
5300
5185
# If there is a tree and we're not annotating historical
5301
5186
# versions, annotate the working tree's content.
5302
annotate_file_tree(wt, relpath, self.outf, long, all,
5187
annotate_file_tree(wt, file_id, self.outf, long, all,
5305
if not tree.is_versioned(relpath):
5306
raise errors.NotVersionedError(relpath)
5307
annotate_file_tree(tree, relpath, self.outf, long, all,
5308
show_ids=show_ids, branch=branch)
5190
annotate_file_tree(tree, file_id, self.outf, long, all,
5191
show_ids=show_ids, branch=branch)
5311
5194
class cmd_re_sign(Command):
5312
5195
__doc__ = """Create a digital signature for an existing revision."""
5313
5196
# TODO be able to replace existing ones.
5315
hidden = True # is this right ?
5198
hidden = True # is this right ?
5316
5199
takes_args = ['revision_id*']
5317
5200
takes_options = ['directory', 'revision']
5319
5202
def run(self, revision_id_list=None, revision=None, directory=u'.'):
5320
5203
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'))
5204
raise errors.BzrCommandError(gettext('You can only supply one of revision_id or --revision'))
5323
5205
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'))
5206
raise errors.BzrCommandError(gettext('You must supply either --revision or a revision_id'))
5326
5207
b = WorkingTree.open_containing(directory)[0].branch
5327
self.enter_context(b.lock_write())
5208
self.add_cleanup(b.lock_write().unlock)
5328
5209
return self._run(b, revision_id_list, revision)
5330
5211
def _run(self, b, revision_id_list, revision):
5331
from .repository import WriteGroup
5332
5213
gpg_strategy = gpg.GPGStrategy(b.get_config_stack())
5333
5214
if revision_id_list is not None:
5334
with WriteGroup(b.repository):
5215
b.repository.start_write_group()
5335
5217
for revision_id in revision_id_list:
5336
revision_id = cache_utf8.encode(revision_id)
5337
5218
b.repository.sign_revision(revision_id, gpg_strategy)
5220
b.repository.abort_write_group()
5223
b.repository.commit_write_group()
5338
5224
elif revision is not None:
5339
5225
if len(revision) == 1:
5340
5226
revno, rev_id = revision[0].in_history(b)
5341
with WriteGroup(b.repository):
5227
b.repository.start_write_group()
5342
5229
b.repository.sign_revision(rev_id, gpg_strategy)
5231
b.repository.abort_write_group()
5234
b.repository.commit_write_group()
5343
5235
elif len(revision) == 2:
5344
5236
# are they both on rh- if so we can walk between them
5345
5237
# might be nice to have a range helper for arbitrary
6342
6232
except errors.NotBranchError:
6344
6234
had_explicit_nick = False
6346
possible_transports.append(branch.user_transport)
6347
6235
if create_branch:
6348
6236
if branch is None:
6349
raise errors.CommandError(
6237
raise errors.BzrCommandError(
6350
6238
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()
6239
to_location = lookup_new_sibling_branch(control_dir, to_location,
6240
possible_transports=possible_transports)
6241
to_branch = branch.bzrdir.sprout(to_location,
6242
possible_transports=possible_transports,
6243
source_branch=branch).open_branch()
6363
to_branch = Branch.open(
6364
to_location, possible_transports=possible_transports)
6246
to_branch = Branch.open(to_location,
6247
possible_transports=possible_transports)
6365
6248
except errors.NotBranchError:
6366
to_branch = open_sibling_branch(
6367
control_dir, to_location,
6249
to_branch = open_sibling_branch(control_dir, to_location,
6368
6250
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.'))
6251
if revision is not None:
6252
revision = revision.as_revision_id(to_branch)
6253
switch.switch(control_dir, to_branch, force, revision_id=revision,
6254
store_uncommitted=store)
6381
6255
if had_explicit_nick:
6382
branch = control_dir.open_branch() # get the new branch!
6256
branch = control_dir.open_branch() #get the new branch!
6383
6257
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'))
6258
note(gettext('Switched to branch: %s'),
6259
urlutils.unescape_for_display(to_branch.base, 'utf-8'))
6395
6263
class cmd_view(Command):
6779
6640
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))
6642
def run(self, path=None, location=None):
6644
if path is not None:
6646
tree, branch, relpath =(
6647
controldir.ControlDir.open_containing_tree_or_branch(branchdir))
6648
if path is not None:
6789
6650
if tree is None:
6790
6651
tree = branch.basis_tree()
6791
6652
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)
6653
info = viewitems(branch._get_all_reference_info())
6654
self._display_reference_info(tree, branch, info)
6798
if not tree.is_versioned(path) and not force_unversioned:
6656
file_id = tree.path2id(path)
6799
6658
raise errors.NotVersionedError(path)
6800
6659
if location is None:
6801
info = [(path, tree.get_reference_info(path, branch))]
6660
info = [(file_id, branch.get_reference_info(file_id))]
6802
6661
self._display_reference_info(tree, branch, info)
6804
tree.set_reference_info(path, location)
6663
branch.set_reference_info(file_id, path, location)
6806
6665
def _display_reference_info(self, tree, branch, info):
6808
for path, location in info:
6667
for file_id, (path, location) in info:
6669
path = tree.id2path(file_id)
6670
except errors.NoSuchId:
6809
6672
ref_list.append((path, location))
6810
6673
for path, location in sorted(ref_list):
6811
6674
self.outf.write('%s %s\n' % (path, location))
6883
6730
if len(installed) > 0:
6884
6731
self.outf.write("Installed:\n")
6885
6732
for rev in installed:
6886
self.outf.write(rev.decode('utf-8') + "\n")
6733
self.outf.write(rev + "\n")
6887
6734
if len(failed) > 0:
6888
6735
self.outf.write("Still missing:\n")
6889
6736
for rev in failed:
6890
self.outf.write(rev.decode('utf-8') + "\n")
6737
self.outf.write(rev + "\n")
6891
6738
if not no_fix and len(installed) > 0:
6892
6739
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
6742
def _register_lazy_builtins():
7117
6743
# register lazy builtins from other modules; called at startup and should
7118
6744
# be only called once.
7119
6745
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'),
6746
('cmd_bundle_info', [], 'breezy.bundle.commands'),
6747
('cmd_config', [], 'breezy.config'),
6748
('cmd_dpush', [], 'breezy.foreign'),
6749
('cmd_version_info', [], 'breezy.cmd_version_info'),
6750
('cmd_resolve', ['resolved'], 'breezy.conflicts'),
6751
('cmd_conflicts', [], 'breezy.conflicts'),
6752
('cmd_ping', [], 'breezy.smart.ping'),
6753
('cmd_sign_my_commits', [], 'breezy.commit_signature_commands'),
6754
('cmd_verify_signatures', [], 'breezy.commit_signature_commands'),
6755
('cmd_test_script', [], 'breezy.cmd_test_script'),
7134
6757
builtin_command_registry.register_lazy(name, aliases, module_name)