/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/builtins.py

  • Committer: Jelmer Vernooij
  • Date: 2019-06-03 23:48:08 UTC
  • mfrom: (7316 work)
  • mto: This revision was merged to the branch mainline in revision 7328.
  • Revision ID: jelmer@jelmer.uk-20190603234808-15yk5c7054tj8e2b
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
import breezy.bzr
26
26
import breezy.git
27
27
 
28
 
from . import (
29
 
    errors,
30
 
    )
31
 
 
32
28
from . import lazy_import
33
29
lazy_import.lazy_import(globals(), """
34
30
import time
42
38
    directory_service,
43
39
    delta,
44
40
    config as _mod_config,
 
41
    errors,
45
42
    globbing,
46
43
    gpg,
47
44
    hooks,
555
552
 
556
553
    def run(self, revision=None, directory='.', force=False):
557
554
        tree, _ = WorkingTree.open_containing(directory)
558
 
        self.enter_context(tree.lock_tree_write())
 
555
        self.add_cleanup(tree.lock_tree_write().unlock)
559
556
        if not force:
560
557
            try:
561
558
                tree.check_state()
605
602
        if tree:
606
603
            try:
607
604
                wt = WorkingTree.open_containing(location)[0]
608
 
                self.enter_context(wt.lock_read())
 
605
                self.add_cleanup(wt.lock_read().unlock)
609
606
            except (errors.NoWorkingTree, errors.NotLocalUrl):
610
607
                raise errors.NoWorkingTree(location)
611
608
            b = wt.branch
612
609
            revid = wt.last_revision()
613
610
        else:
614
611
            b = Branch.open_containing(location)[0]
615
 
            self.enter_context(b.lock_read())
 
612
            self.add_cleanup(b.lock_read().unlock)
616
613
            if revision:
617
614
                if len(revision) != 1:
618
615
                    raise errors.BzrCommandError(gettext(
649
646
        try:
650
647
            wt = WorkingTree.open_containing(directory)[0]
651
648
            b = wt.branch
652
 
            self.enter_context(wt.lock_read())
 
649
            self.add_cleanup(wt.lock_read().unlock)
653
650
        except (errors.NoWorkingTree, errors.NotLocalUrl):
654
651
            wt = None
655
652
            b = Branch.open_containing(directory)[0]
656
 
            self.enter_context(b.lock_read())
 
653
            self.add_cleanup(b.lock_read().unlock)
657
654
        revision_ids = []
658
655
        if revision is not None:
659
656
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
750
747
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
751
748
            file_ids_from=None):
752
749
        import breezy.add
753
 
        tree, file_list = tree_files_for_add(file_list)
754
 
 
755
 
        if file_ids_from is not None and not tree.supports_setting_file_ids():
756
 
            warning(
757
 
                gettext('Ignoring --file-ids-from, since the tree does not '
758
 
                        'support setting file ids.'))
759
 
            file_ids_from = None
760
750
 
761
751
        base_tree = None
762
752
        if file_ids_from is not None:
776
766
                to_file=self.outf, should_print=(not is_quiet()))
777
767
 
778
768
        if base_tree:
779
 
            self.enter_context(base_tree.lock_read())
 
769
            self.add_cleanup(base_tree.lock_read().unlock)
 
770
        tree, file_list = tree_files_for_add(file_list)
780
771
        added, ignored = tree.smart_add(
781
772
            file_list, not no_recurse, action=action, save=not dry_run)
782
773
        self.cleanup_now()
866
857
    takes_options = [
867
858
        'revision',
868
859
        'show-ids',
869
 
        Option('include-root',
870
 
               help='Include the entry for the root of the tree, if any.'),
871
860
        Option('kind',
872
861
               help='List entries of a particular kind: file, directory, '
873
862
                    'symlink.',
876
865
    takes_args = ['file*']
877
866
 
878
867
    @display_command
879
 
    def run(self, revision=None, show_ids=False, kind=None, include_root=False,
880
 
            file_list=None):
 
868
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
881
869
        if kind and kind not in ['file', 'directory', 'symlink']:
882
870
            raise errors.BzrCommandError(
883
871
                gettext('invalid kind %r specified') % (kind,))
884
872
 
885
873
        revision = _get_one_revision('inventory', revision)
886
874
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
887
 
        self.enter_context(work_tree.lock_read())
 
875
        self.add_cleanup(work_tree.lock_read().unlock)
888
876
        if revision is not None:
889
877
            tree = revision.as_tree(work_tree.branch)
890
878
 
891
879
            extra_trees = [work_tree]
892
 
            self.enter_context(tree.lock_read())
 
880
            self.add_cleanup(tree.lock_read().unlock)
893
881
        else:
894
882
            tree = work_tree
895
883
            extra_trees = []
896
884
 
897
 
        self.enter_context(tree.lock_read())
 
885
        self.add_cleanup(tree.lock_read().unlock)
898
886
        if file_list is not None:
899
887
            paths = tree.find_related_paths_across_trees(
900
888
                file_list, extra_trees, require_versioned=True)
907
895
        for path, entry in sorted(entries):
908
896
            if kind and kind != entry.kind:
909
897
                continue
910
 
            if path == "" and not include_root:
 
898
            if path == "":
911
899
                continue
912
900
            if show_ids:
913
901
                self.outf.write('%-50s %s\n' % (
949
937
            if file_name == '':
950
938
                raise errors.BzrCommandError(
951
939
                    gettext("can not copy root of branch"))
952
 
        self.enter_context(tree.lock_tree_write())
 
940
        self.add_cleanup(tree.lock_tree_write().unlock)
953
941
        into_existing = osutils.isdir(names_list[-1])
954
942
        if not into_existing:
955
943
            try:
1042
1030
            if file_name == '':
1043
1031
                raise errors.BzrCommandError(
1044
1032
                    gettext("can not move root of branch"))
1045
 
        self.enter_context(tree.lock_tree_write())
 
1033
        self.add_cleanup(tree.lock_tree_write().unlock)
1046
1034
        self._run(tree, names_list, rel_names, after)
1047
1035
 
1048
1036
    def run_auto(self, names_list, after, dry_run):
1054
1042
                gettext('--after cannot be specified with --auto.'))
1055
1043
        work_tree, file_list = WorkingTree.open_containing_paths(
1056
1044
            names_list, default_directory='.')
1057
 
        self.enter_context(work_tree.lock_tree_write())
 
1045
        self.add_cleanup(work_tree.lock_tree_write().unlock)
1058
1046
        rename_map.RenameMap.guess_renames(
1059
1047
            work_tree.basis_tree(), work_tree, dry_run)
1060
1048
 
1208
1196
        try:
1209
1197
            tree_to = WorkingTree.open_containing(directory)[0]
1210
1198
            branch_to = tree_to.branch
1211
 
            self.enter_context(tree_to.lock_write())
 
1199
            self.add_cleanup(tree_to.lock_write().unlock)
1212
1200
        except errors.NoWorkingTree:
1213
1201
            tree_to = None
1214
1202
            branch_to = Branch.open_containing(directory)[0]
1215
 
            self.enter_context(branch_to.lock_write())
 
1203
            self.add_cleanup(branch_to.lock_write().unlock)
1216
1204
            if show_base:
1217
1205
                warning(gettext("No working tree, ignoring --show-base"))
1218
1206
 
1252
1240
        else:
1253
1241
            branch_from = Branch.open(location,
1254
1242
                                      possible_transports=possible_transports)
1255
 
            self.enter_context(branch_from.lock_read())
 
1243
            self.add_cleanup(branch_from.lock_read().unlock)
1256
1244
            # Remembers if asked explicitly or no previous location is set
1257
1245
            if (remember
1258
1246
                    or (remember is None and branch_to.get_parent() is None)):
1442
1430
    parameter, as in "branch foo/bar -r 5".
1443
1431
    """
1444
1432
 
1445
 
    aliase = ['sprout']
1446
1433
    _see_also = ['checkout']
1447
1434
    takes_args = ['from_location', 'to_location?']
1448
1435
    takes_options = ['revision',
1468
1455
                            ' allow branch to proceed.'),
1469
1456
                     Option('bind',
1470
1457
                            help="Bind new branch to from location."),
1471
 
                     Option('no-recurse-nested',
1472
 
                            help='Do not recursively check out nested trees.'),
1473
 
                     Option('colocated-branch', short_name='b',
1474
 
                            type=str, help='Name of colocated branch to sprout.'),
1475
1458
                     ]
1476
1459
 
1477
1460
    def run(self, from_location, to_location=None, revision=None,
1478
1461
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1479
1462
            use_existing_dir=False, switch=False, bind=False,
1480
 
            files_from=None, no_recurse_nested=False, colocated_branch=None):
 
1463
            files_from=None):
1481
1464
        from breezy import switch as _mod_switch
1482
1465
        accelerator_tree, br_from = controldir.ControlDir.open_tree_or_branch(
1483
 
            from_location, name=colocated_branch)
1484
 
        if no_recurse_nested:
1485
 
            recurse = 'none'
1486
 
        else:
1487
 
            recurse = 'down'
 
1466
            from_location)
1488
1467
        if not (hardlink or files_from):
1489
1468
            # accelerator_tree is usually slower because you have to read N
1490
1469
            # files (no readahead, lots of seeks, etc), but allow the user to
1493
1472
        if files_from is not None and files_from != from_location:
1494
1473
            accelerator_tree = WorkingTree.open(files_from)
1495
1474
        revision = _get_one_revision('branch', revision)
1496
 
        self.enter_context(br_from.lock_read())
 
1475
        self.add_cleanup(br_from.lock_read().unlock)
1497
1476
        if revision is not None:
1498
1477
            revision_id = revision.as_revision_id(br_from)
1499
1478
        else:
1536
1515
                    possible_transports=[to_transport],
1537
1516
                    accelerator_tree=accelerator_tree, hardlink=hardlink,
1538
1517
                    stacked=stacked, force_new_repo=standalone,
1539
 
                    create_tree_if_local=not no_tree, source_branch=br_from,
1540
 
                    recurse=recurse)
 
1518
                    create_tree_if_local=not no_tree, source_branch=br_from)
1541
1519
                branch = to_dir.open_branch(
1542
1520
                    possible_transports=[
1543
1521
                        br_from.controldir.root_transport, to_transport])
1552
1530
            except errors.NoRepositoryPresent:
1553
1531
                to_repo = to_dir.create_repository()
1554
1532
            to_repo.fetch(br_from.repository, revision_id=revision_id)
1555
 
            branch = br_from.sprout(
1556
 
                to_dir, revision_id=revision_id)
 
1533
            branch = br_from.sprout(to_dir, revision_id=revision_id)
1557
1534
        br_from.tags.merge_to(branch.tags)
1558
1535
 
1559
1536
        # If the source branch is stacked, the new branch may
1707
1684
                               accelerator_tree, hardlink)
1708
1685
 
1709
1686
 
1710
 
class cmd_clone(Command):
1711
 
    __doc__ = """Clone a control directory.
1712
 
    """
1713
 
 
1714
 
    takes_args = ['from_location', 'to_location?']
1715
 
    takes_options = ['revision',
1716
 
                     Option('no-recurse-nested',
1717
 
                            help='Do not recursively check out nested trees.'),
1718
 
                     ]
1719
 
 
1720
 
    def run(self, from_location, to_location=None, revision=None, no_recurse_nested=False):
1721
 
        accelerator_tree, br_from = controldir.ControlDir.open_tree_or_branch(
1722
 
            from_location)
1723
 
        if no_recurse_nested:
1724
 
            recurse = 'none'
1725
 
        else:
1726
 
            recurse = 'down'
1727
 
        revision = _get_one_revision('branch', revision)
1728
 
        self.enter_context(br_from.lock_read())
1729
 
        if revision is not None:
1730
 
            revision_id = revision.as_revision_id(br_from)
1731
 
        else:
1732
 
            # FIXME - wt.last_revision, fallback to branch, fall back to
1733
 
            # None or perhaps NULL_REVISION to mean copy nothing
1734
 
            # RBC 20060209
1735
 
            revision_id = br_from.last_revision()
1736
 
        if to_location is None:
1737
 
            to_location = urlutils.derive_to_location(from_location)
1738
 
        target_controldir = br_from.controldir.clone(to_location, revision_id=revision_id)
1739
 
        note(gettext('Created new control directory.'))
1740
 
 
1741
 
 
1742
1687
class cmd_renames(Command):
1743
1688
    __doc__ = """Show list of renamed files.
1744
1689
    """
1751
1696
    @display_command
1752
1697
    def run(self, dir=u'.'):
1753
1698
        tree = WorkingTree.open_containing(dir)[0]
1754
 
        self.enter_context(tree.lock_read())
 
1699
        self.add_cleanup(tree.lock_read().unlock)
1755
1700
        old_tree = tree.basis_tree()
1756
 
        self.enter_context(old_tree.lock_read())
 
1701
        self.add_cleanup(old_tree.lock_read().unlock)
1757
1702
        renames = []
1758
1703
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1759
 
        for change in iterator:
1760
 
            if change.path[0] == change.path[1]:
1761
 
                continue
1762
 
            if None in change.path:
1763
 
                continue
1764
 
            renames.append(change.path)
 
1704
        for f, paths, c, v, p, n, k, e in iterator:
 
1705
            if paths[0] == paths[1]:
 
1706
                continue
 
1707
            if None in (paths):
 
1708
                continue
 
1709
            renames.append(paths)
1765
1710
        renames.sort()
1766
1711
        for old_name, new_name in renames:
1767
1712
            self.outf.write("%s => %s\n" % (old_name, new_name))
1824
1769
            possible_transports=possible_transports)
1825
1770
        if master is not None:
1826
1771
            branch_location = master.base
1827
 
            self.enter_context(tree.lock_write())
 
1772
            tree.lock_write()
1828
1773
        else:
1829
1774
            branch_location = tree.branch.base
1830
 
            self.enter_context(tree.lock_tree_write())
 
1775
            tree.lock_tree_write()
 
1776
        self.add_cleanup(tree.unlock)
1831
1777
        # get rid of the final '/' and be ready for display
1832
1778
        branch_location = urlutils.unescape_for_display(
1833
1779
            branch_location.rstrip('/'),
1955
1901
        if file_list is not None:
1956
1902
            file_list = [f for f in file_list]
1957
1903
 
1958
 
        self.enter_context(tree.lock_write())
 
1904
        self.add_cleanup(tree.lock_write().unlock)
1959
1905
        # Heuristics should probably all move into tree.remove_smart or
1960
1906
        # some such?
1961
1907
        if new:
1962
1908
            added = tree.changes_from(tree.basis_tree(),
1963
1909
                                      specific_files=file_list).added
1964
 
            file_list = sorted([f.path[1] for f in added], reverse=True)
 
1910
            file_list = sorted([f[0] for f in added], reverse=True)
1965
1911
            if len(file_list) == 0:
1966
1912
                raise errors.BzrCommandError(gettext('No matching files.'))
1967
1913
        elif file_list is None:
1970
1916
            missing = []
1971
1917
            for change in tree.iter_changes(tree.basis_tree()):
1972
1918
                # Find paths in the working tree that have no kind:
1973
 
                if change.path[1] is not None and change.kind[1] is None:
1974
 
                    missing.append(change.path[1])
 
1919
                if change[1][1] is not None and change[6][1] is None:
 
1920
                    missing.append(change[1][1])
1975
1921
            file_list = sorted(missing, reverse=True)
1976
1922
            file_deletion_strategy = 'keep'
1977
1923
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
2024
1970
    @display_command
2025
1971
    def run(self, location="."):
2026
1972
        branch = Branch.open_containing(location)[0]
2027
 
        self.enter_context(branch.lock_read())
 
1973
        self.add_cleanup(branch.lock_read().unlock)
2028
1974
        graph = branch.repository.get_graph()
2029
1975
        history = list(graph.iter_lefthand_ancestry(branch.last_revision(),
2030
1976
                                                    [_mod_revision.NULL_REVISION]))
2052
1998
            b = wt.branch
2053
1999
            last_revision = wt.last_revision()
2054
2000
 
2055
 
        self.enter_context(b.repository.lock_read())
 
2001
        self.add_cleanup(b.repository.lock_read().unlock)
2056
2002
        graph = b.repository.get_graph()
2057
2003
        revisions = [revid for revid, parents in
2058
2004
                     graph.iter_ancestry([last_revision])]
2085
2031
        brz commit -m "imported project"
2086
2032
    """
2087
2033
 
2088
 
    _see_also = ['init-shared-repository', 'branch', 'checkout']
 
2034
    _see_also = ['init-repository', 'branch', 'checkout']
2089
2035
    takes_args = ['location?']
2090
2036
    takes_options = [
2091
2037
        Option('create-prefix',
2183
2129
                self.outf.write(gettext("Using shared repository: %s\n") % url)
2184
2130
 
2185
2131
 
2186
 
class cmd_init_shared_repository(Command):
 
2132
class cmd_init_repository(Command):
2187
2133
    __doc__ = """Create a shared repository for branches to share storage space.
2188
2134
 
2189
2135
    New branches created under the repository directory will store their
2201
2147
    :Examples:
2202
2148
        Create a shared repository holding just branches::
2203
2149
 
2204
 
            brz init-shared-repo --no-trees repo
 
2150
            brz init-repo --no-trees repo
2205
2151
            brz init repo/trunk
2206
2152
 
2207
2153
        Make a lightweight checkout elsewhere::
2225
2171
                            help='Branches in the repository will default to'
2226
2172
                            ' not having a working tree.'),
2227
2173
                     ]
2228
 
    aliases = ["init-shared-repo", "init-repo"]
 
2174
    aliases = ["init-repo"]
2229
2175
 
2230
2176
    def run(self, location, format=None, no_trees=False):
2231
2177
        if format is None:
2370
2316
               help='How many lines of context to show.',
2371
2317
               type=int,
2372
2318
               ),
2373
 
        RegistryOption.from_kwargs(
2374
 
            'color',
2375
 
            help='Color mode to use.',
2376
 
            title='Color Mode', value_switches=False, enum_switch=True,
2377
 
            never='Never colorize output.',
2378
 
            auto='Only colorize output if terminal supports it and STDOUT is a'
2379
 
            ' TTY.',
2380
 
            always='Always colorize output (default).'),
2381
 
        Option(
2382
 
            'check-style',
2383
 
            help=('Warn if trailing whitespace or spurious changes have been'
2384
 
                  '  added.'))
2385
2319
        ]
2386
 
 
2387
2320
    aliases = ['di', 'dif']
2388
2321
    encoding_type = 'exact'
2389
2322
 
2390
2323
    @display_command
2391
2324
    def run(self, revision=None, file_list=None, diff_options=None,
2392
2325
            prefix=None, old=None, new=None, using=None, format=None,
2393
 
            context=None, color='never'):
 
2326
            context=None):
2394
2327
        from .diff import (get_trees_and_branches_to_diff_locked,
2395
2328
                           show_diff_trees)
2396
2329
 
2420
2353
        (old_tree, new_tree,
2421
2354
         old_branch, new_branch,
2422
2355
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
2423
 
            file_list, revision, old, new, self._exit_stack, apply_view=True)
 
2356
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
2424
2357
        # GNU diff on Windows uses ANSI encoding for filenames
2425
2358
        path_encoding = osutils.get_diff_header_encoding()
2426
 
        outf = self.outf
2427
 
        if color == 'auto':
2428
 
            from .terminal import has_ansi_colors
2429
 
            if has_ansi_colors():
2430
 
                color = 'always'
2431
 
            else:
2432
 
                color = 'never'
2433
 
        if 'always' == color:
2434
 
            from .colordiff import DiffWriter
2435
 
            outf = DiffWriter(outf)
2436
 
        return show_diff_trees(old_tree, new_tree, outf,
 
2359
        return show_diff_trees(old_tree, new_tree, self.outf,
2437
2360
                               specific_files=specific_files,
2438
2361
                               external_diff_options=diff_options,
2439
2362
                               old_label=old_label, new_label=new_label,
2458
2381
    @display_command
2459
2382
    def run(self, show_ids=False, directory=u'.'):
2460
2383
        tree = WorkingTree.open_containing(directory)[0]
2461
 
        self.enter_context(tree.lock_read())
 
2384
        self.add_cleanup(tree.lock_read().unlock)
2462
2385
        old = tree.basis_tree()
2463
 
        self.enter_context(old.lock_read())
2464
 
        delta = tree.changes_from(old)
2465
 
        for change in delta.removed:
2466
 
            self.outf.write(change.path[0])
2467
 
            if show_ids:
2468
 
                self.outf.write(' ')
2469
 
                self.outf.write(change.file_id)
2470
 
            self.outf.write('\n')
 
2386
        self.add_cleanup(old.lock_read().unlock)
 
2387
        for path, ie in old.iter_entries_by_dir():
 
2388
            if not tree.has_id(ie.file_id):
 
2389
                self.outf.write(path)
 
2390
                if show_ids:
 
2391
                    self.outf.write(' ')
 
2392
                    self.outf.write(ie.file_id)
 
2393
                self.outf.write('\n')
2471
2394
 
2472
2395
 
2473
2396
class cmd_modified(Command):
2481
2404
    @display_command
2482
2405
    def run(self, null=False, directory=u'.'):
2483
2406
        tree = WorkingTree.open_containing(directory)[0]
2484
 
        self.enter_context(tree.lock_read())
 
2407
        self.add_cleanup(tree.lock_read().unlock)
2485
2408
        td = tree.changes_from(tree.basis_tree())
2486
2409
        self.cleanup_now()
2487
 
        for change in td.modified:
 
2410
        for path, id, kind, text_modified, meta_modified in td.modified:
2488
2411
            if null:
2489
 
                self.outf.write(change.path[1] + '\0')
 
2412
                self.outf.write(path + '\0')
2490
2413
            else:
2491
 
                self.outf.write(osutils.quotefn(change.path[1]) + '\n')
 
2414
                self.outf.write(osutils.quotefn(path) + '\n')
2492
2415
 
2493
2416
 
2494
2417
class cmd_added(Command):
2502
2425
    @display_command
2503
2426
    def run(self, null=False, directory=u'.'):
2504
2427
        wt = WorkingTree.open_containing(directory)[0]
2505
 
        self.enter_context(wt.lock_read())
 
2428
        self.add_cleanup(wt.lock_read().unlock)
2506
2429
        basis = wt.basis_tree()
2507
 
        self.enter_context(basis.lock_read())
 
2430
        self.add_cleanup(basis.lock_read().unlock)
2508
2431
        for path in wt.all_versioned_paths():
2509
2432
            if basis.has_filename(path):
2510
2433
                continue
2838
2761
        if file_list:
2839
2762
            # find the file ids to log and check for directory filtering
2840
2763
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2841
 
                revision, file_list, self._exit_stack)
 
2764
                revision, file_list, self.add_cleanup)
2842
2765
            for relpath, file_id, kind in file_info_list:
2843
2766
                if file_id is None:
2844
2767
                    raise errors.BzrCommandError(gettext(
2862
2785
                location = '.'
2863
2786
            dir, relpath = controldir.ControlDir.open_containing(location)
2864
2787
            b = dir.open_branch()
2865
 
            self.enter_context(b.lock_read())
 
2788
            self.add_cleanup(b.lock_read().unlock)
2866
2789
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2867
2790
 
2868
2791
        if b.get_config_stack().get('validate_signatures_in_log'):
3093
3016
                view_str = views.view_display_str(view_files)
3094
3017
                note(gettext("Ignoring files outside view. View is %s") % view_str)
3095
3018
 
3096
 
        self.enter_context(tree.lock_read())
 
3019
        self.add_cleanup(tree.lock_read().unlock)
3097
3020
        for fp, fc, fkind, entry in tree.list_files(
3098
3021
                include_root=False, from_dir=relpath, recursive=recursive):
3099
3022
            # Apply additional masking
3270
3193
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
3271
3194
        ignored = globbing.Globster(name_pattern_list)
3272
3195
        matches = []
3273
 
        self.enter_context(tree.lock_read())
 
3196
        self.add_cleanup(tree.lock_read().unlock)
3274
3197
        for filename, fc, fkind, entry in tree.list_files():
3275
3198
            id = getattr(entry, 'file_id', None)
3276
3199
            if id is not None:
3301
3224
    @display_command
3302
3225
    def run(self, directory=u'.'):
3303
3226
        tree = WorkingTree.open_containing(directory)[0]
3304
 
        self.enter_context(tree.lock_read())
 
3227
        self.add_cleanup(tree.lock_read().unlock)
3305
3228
        for path, file_class, kind, entry in tree.list_files():
3306
3229
            if file_class != 'I':
3307
3230
                continue
3392
3315
        (tree, b, subdir) = controldir.ControlDir.open_containing_tree_or_branch(
3393
3316
            branch_or_subdir)
3394
3317
        if tree is not None:
3395
 
            self.enter_context(tree.lock_read())
 
3318
            self.add_cleanup(tree.lock_read().unlock)
3396
3319
 
3397
3320
        if uncommitted:
3398
3321
            if tree is None:
3456
3379
                                                 " one revision specifier"))
3457
3380
        tree, branch, relpath = \
3458
3381
            _open_directory_or_containing_tree_or_branch(filename, directory)
3459
 
        self.enter_context(branch.lock_read())
 
3382
        self.add_cleanup(branch.lock_read().unlock)
3460
3383
        return self._run(tree, branch, relpath, filename, revision,
3461
3384
                         name_from_revision, filters)
3462
3385
 
3466
3389
        if tree is None:
3467
3390
            tree = b.basis_tree()
3468
3391
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
3469
 
        self.enter_context(rev_tree.lock_read())
 
3392
        self.add_cleanup(rev_tree.lock_read().unlock)
3470
3393
 
3471
3394
        if name_from_revision:
3472
3395
            # Try in revision if requested
3980
3903
                c = Branch.open_containing(u'.')[0].get_config_stack()
3981
3904
            else:
3982
3905
                b = Branch.open(directory)
3983
 
                self.enter_context(b.lock_write())
 
3906
                self.add_cleanup(b.lock_write().unlock)
3984
3907
                c = b.get_config_stack()
3985
3908
        else:
3986
3909
            c = _mod_config.GlobalStack()
4358
4281
 
4359
4282
        branch1 = Branch.open_containing(branch)[0]
4360
4283
        branch2 = Branch.open_containing(other)[0]
4361
 
        self.enter_context(branch1.lock_read())
4362
 
        self.enter_context(branch2.lock_read())
 
4284
        self.add_cleanup(branch1.lock_read().unlock)
 
4285
        self.add_cleanup(branch2.lock_read().unlock)
4363
4286
        last1 = ensure_null(branch1.last_revision())
4364
4287
        last2 = ensure_null(branch2.last_revision())
4365
4288
 
4511
4434
        change_reporter = delta._ChangeReporter(
4512
4435
            unversioned_filter=tree.is_ignored, view_info=view_info)
4513
4436
        pb = ui.ui_factory.nested_progress_bar()
4514
 
        self.enter_context(pb)
4515
 
        self.enter_context(tree.lock_write())
 
4437
        self.add_cleanup(pb.finished)
 
4438
        self.add_cleanup(tree.lock_write().unlock)
4516
4439
        if location is not None:
4517
4440
            try:
4518
4441
                mergeable = _mod_mergeable.read_mergeable_from_url(
4580
4503
    def _get_preview(self, merger):
4581
4504
        tree_merger = merger.make_merger()
4582
4505
        tt = tree_merger.make_preview_transform()
4583
 
        self.enter_context(tt)
 
4506
        self.add_cleanup(tt.finalize)
4584
4507
        result_tree = tt.get_preview_tree()
4585
4508
        return result_tree
4586
4509
 
4801
4724
        if merge_type is None:
4802
4725
            merge_type = _mod_merge.Merge3Merger
4803
4726
        tree, file_list = WorkingTree.open_containing_paths(file_list)
4804
 
        self.enter_context(tree.lock_write())
 
4727
        self.add_cleanup(tree.lock_write().unlock)
4805
4728
        parents = tree.get_parent_ids()
4806
4729
        if len(parents) != 2:
4807
4730
            raise errors.BzrCommandError(
4924
4847
    def run(self, revision=None, no_backup=False, file_list=None,
4925
4848
            forget_merges=None):
4926
4849
        tree, file_list = WorkingTree.open_containing_paths(file_list)
4927
 
        self.enter_context(tree.lock_tree_write())
 
4850
        self.add_cleanup(tree.lock_tree_write().unlock)
4928
4851
        if forget_merges:
4929
4852
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4930
4853
        else:
5073
4996
            restrict = 'remote'
5074
4997
 
5075
4998
        local_branch = Branch.open_containing(directory)[0]
5076
 
        self.enter_context(local_branch.lock_read())
 
4999
        self.add_cleanup(local_branch.lock_read().unlock)
5077
5000
 
5078
5001
        parent = local_branch.get_parent()
5079
5002
        if other_branch is None:
5090
5013
        if remote_branch.base == local_branch.base:
5091
5014
            remote_branch = local_branch
5092
5015
        else:
5093
 
            self.enter_context(remote_branch.lock_read())
 
5016
            self.add_cleanup(remote_branch.lock_read().unlock)
5094
5017
 
5095
5018
        local_revid_range = _revision_range_to_revid_range(
5096
5019
            _get_revision_range(my_revision, local_branch,
5162
5085
            message(gettext("Branches are up to date.\n"))
5163
5086
        self.cleanup_now()
5164
5087
        if not status_code and parent is None and other_branch is not None:
5165
 
            self.enter_context(local_branch.lock_write())
 
5088
            self.add_cleanup(local_branch.lock_write().unlock)
5166
5089
            # handle race conditions - a parent might be set while we run.
5167
5090
            if local_branch.get_parent() is None:
5168
5091
                local_branch.set_parent(remote_branch.base)
5255
5178
            b = Branch.open_containing(branch)[0]
5256
5179
        else:
5257
5180
            b = Branch.open(branch)
5258
 
        self.enter_context(b.lock_read())
 
5181
        self.add_cleanup(b.lock_read().unlock)
5259
5182
        if revision is None:
5260
5183
            rev_id = b.last_revision()
5261
5184
        else:
5298
5221
        wt, branch, relpath = \
5299
5222
            _open_directory_or_containing_tree_or_branch(filename, directory)
5300
5223
        if wt is not None:
5301
 
            self.enter_context(wt.lock_read())
 
5224
            self.add_cleanup(wt.lock_read().unlock)
5302
5225
        else:
5303
 
            self.enter_context(branch.lock_read())
 
5226
            self.add_cleanup(branch.lock_read().unlock)
5304
5227
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
5305
 
        self.enter_context(tree.lock_read())
 
5228
        self.add_cleanup(tree.lock_read().unlock)
5306
5229
        if wt is not None and revision is None:
5307
5230
            if not wt.is_versioned(relpath):
5308
5231
                raise errors.NotVersionedError(relpath)
5333
5256
            raise errors.BzrCommandError(
5334
5257
                gettext('You must supply either --revision or a revision_id'))
5335
5258
        b = WorkingTree.open_containing(directory)[0].branch
5336
 
        self.enter_context(b.lock_write())
 
5259
        self.add_cleanup(b.lock_write().unlock)
5337
5260
        return self._run(b, revision_id_list, revision)
5338
5261
 
5339
5262
    def _run(self, b, revision_id_list, revision):
5479
5402
            b = control.open_branch()
5480
5403
 
5481
5404
        if tree is not None:
5482
 
            self.enter_context(tree.lock_write())
 
5405
            self.add_cleanup(tree.lock_write().unlock)
5483
5406
        else:
5484
 
            self.enter_context(b.lock_write())
 
5407
            self.add_cleanup(b.lock_write().unlock)
5485
5408
        return self._run(b, tree, dry_run, verbose, revision, force,
5486
5409
                         local, keep_tags, location)
5487
5410
 
6064
5987
            revision=None,
6065
5988
            ):
6066
5989
        branch, relpath = Branch.open_containing(directory)
6067
 
        self.enter_context(branch.lock_write())
 
5990
        self.add_cleanup(branch.lock_write().unlock)
6068
5991
        if delete:
6069
5992
            if tag_name is None:
6070
5993
                raise errors.BzrCommandError(
6128
6051
        if not tags:
6129
6052
            return
6130
6053
 
6131
 
        self.enter_context(branch.lock_read())
 
6054
        self.add_cleanup(branch.lock_read().unlock)
6132
6055
        if revision:
6133
6056
            # Restrict to the specified range
6134
6057
            tags = self._tags_for_range(branch, revision)
6337
6260
        from . import switch
6338
6261
        tree_location = directory
6339
6262
        revision = _get_one_revision('switch', revision)
6340
 
        control_dir = controldir.ControlDir.open_containing(tree_location)[0]
6341
 
        possible_transports = [control_dir.root_transport]
 
6263
        possible_transports = []
 
6264
        control_dir = controldir.ControlDir.open_containing(tree_location,
 
6265
                                                            possible_transports=possible_transports)[0]
6342
6266
        if to_location is None:
6343
6267
            if revision is None:
6344
6268
                raise errors.BzrCommandError(gettext('You must supply either a'
6351
6275
        except errors.NotBranchError:
6352
6276
            branch = None
6353
6277
            had_explicit_nick = False
6354
 
        else:
6355
 
            possible_transports.append(branch.user_transport)
6356
6278
        if create_branch:
6357
6279
            if branch is None:
6358
6280
                raise errors.BzrCommandError(
6369
6291
                source_branch=branch).open_branch()
6370
6292
        else:
6371
6293
            try:
6372
 
                to_branch = Branch.open(
6373
 
                    to_location, possible_transports=possible_transports)
 
6294
                to_branch = Branch.open(to_location,
 
6295
                                        possible_transports=possible_transports)
6374
6296
            except errors.NotBranchError:
6375
6297
                to_branch = open_sibling_branch(
6376
6298
                    control_dir, to_location,
6377
6299
                    possible_transports=possible_transports)
6378
6300
            if revision is not None:
6379
6301
                revision = revision.as_revision_id(to_branch)
6380
 
        possible_transports.append(to_branch.user_transport)
6381
6302
        try:
6382
6303
            switch.switch(control_dir, to_branch, force, revision_id=revision,
6383
 
                          store_uncommitted=store,
6384
 
                          possible_transports=possible_transports)
 
6304
                          store_uncommitted=store)
6385
6305
        except controldir.BranchReferenceLoop:
6386
6306
            raise errors.BzrCommandError(
6387
6307
                gettext('switching would create a branch reference loop. '
6645
6565
    editor program to decide what the file remaining in the working copy
6646
6566
    should look like.  To do this, add the configuration option
6647
6567
 
6648
 
        change_editor = PROGRAM {new_path} {old_path}
 
6568
        change_editor = PROGRAM @new_path @old_path
6649
6569
 
6650
 
    where {new_path} is replaced with the path of the new version of the
6651
 
    file and {old_path} is replaced with the path of the old version of
 
6570
    where @new_path is replaced with the path of the new version of the
 
6571
    file and @old_path is replaced with the path of the old version of
6652
6572
    the file.  The PROGRAM should save the new file with the desired
6653
6573
    contents of the file in the working tree.
6654
6574
 
6692
6612
        if directory is None:
6693
6613
            directory = u'.'
6694
6614
        tree = WorkingTree.open_containing(directory)[0]
6695
 
        self.enter_context(tree.lock_read())
 
6615
        self.add_cleanup(tree.lock_read().unlock)
6696
6616
        manager = tree.get_shelf_manager()
6697
6617
        shelves = manager.active_shelves()
6698
6618
        if len(shelves) == 0:
6787
6707
 
6788
6708
    takes_args = ['path?', 'location?']
6789
6709
    takes_options = [
6790
 
        'directory',
6791
6710
        Option('force-unversioned',
6792
6711
               help='Set reference even if path is not versioned.'),
6793
6712
        ]
6794
6713
 
6795
 
    def run(self, path=None, directory='.', location=None, force_unversioned=False):
 
6714
    def run(self, path=None, location=None, force_unversioned=False):
 
6715
        branchdir = '.'
 
6716
        if path is not None:
 
6717
            branchdir = path
6796
6718
        tree, branch, relpath = (
6797
 
            controldir.ControlDir.open_containing_tree_or_branch(directory))
 
6719
            controldir.ControlDir.open_containing_tree_or_branch(branchdir))
 
6720
        if path is not None:
 
6721
            path = relpath
6798
6722
        if tree is None:
6799
6723
            tree = branch.basis_tree()
6800
6724
        if path is None:
6801
 
            with tree.lock_read():
6802
 
                info = [
6803
 
                    (path, tree.get_reference_info(path, branch))
6804
 
                    for path in tree.iter_references()]
6805
 
                self._display_reference_info(tree, branch, info)
 
6725
            info = viewitems(branch._get_all_reference_info())
 
6726
            self._display_reference_info(tree, branch, info)
6806
6727
        else:
6807
6728
            if not tree.is_versioned(path) and not force_unversioned:
6808
6729
                raise errors.NotVersionedError(path)
6809
6730
            if location is None:
6810
 
                info = [(path, tree.get_reference_info(path, branch))]
 
6731
                info = [(path, branch.get_reference_info(path))]
6811
6732
                self._display_reference_info(tree, branch, info)
6812
6733
            else:
6813
 
                tree.set_reference_info(path, location)
 
6734
                branch.set_reference_info(
 
6735
                    path, location, file_id=tree.path2id(path))
6814
6736
 
6815
6737
    def _display_reference_info(self, tree, branch, info):
6816
6738
        ref_list = []
6817
 
        for path, location in info:
 
6739
        for path, (location, file_id) in info:
6818
6740
            ref_list.append((path, location))
6819
6741
        for path, location in sorted(ref_list):
6820
6742
            self.outf.write('%s %s\n' % (path, location))
7127
7049
    # be only called once.
7128
7050
    for (name, aliases, module_name) in [
7129
7051
            ('cmd_bisect', [], 'breezy.bisect'),
7130
 
            ('cmd_bundle_info', [], 'breezy.bzr.bundle.commands'),
 
7052
            ('cmd_bundle_info', [], 'breezy.bundle.commands'),
7131
7053
            ('cmd_config', [], 'breezy.config'),
7132
7054
            ('cmd_dump_btree', [], 'breezy.bzr.debug_commands'),
7133
7055
            ('cmd_file_id', [], 'breezy.bzr.debug_commands'),