/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-05-20 03:57:29 UTC
  • mto: This revision was merged to the branch mainline in revision 7328.
  • Revision ID: jelmer@jelmer.uk-20190520035729-9rxvefxkvbbivygy
use default_user_agent function.

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
37
33
from breezy import (
38
34
    branch as _mod_branch,
39
35
    bugtracker,
 
36
    bundle,
40
37
    cache_utf8,
41
38
    controldir,
42
39
    directory_service,
43
40
    delta,
44
41
    config as _mod_config,
 
42
    errors,
45
43
    globbing,
46
44
    gpg,
47
45
    hooks,
48
46
    lazy_regex,
49
47
    log,
50
48
    merge as _mod_merge,
51
 
    mergeable as _mod_mergeable,
52
49
    merge_directive,
53
50
    osutils,
54
51
    reconfigure,
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
 
1222
1210
        possible_transports = []
1223
1211
        if location is not None:
1224
1212
            try:
1225
 
                mergeable = _mod_mergeable.read_mergeable_from_url(
1226
 
                    location, possible_transports=possible_transports)
 
1213
                mergeable = bundle.read_mergeable_from_url(location,
 
1214
                                                           possible_transports=possible_transports)
1227
1215
            except errors.NotABundle:
1228
1216
                mergeable = None
1229
1217
 
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
 
                mergeable = _mod_mergeable.read_mergeable_from_url(
4519
 
                    location, possible_transports=possible_transports)
 
4441
                mergeable = bundle.read_mergeable_from_url(location,
 
4442
                                                           possible_transports=possible_transports)
4520
4443
            except errors.NotABundle:
4521
4444
                mergeable = None
4522
4445
            else:
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):
5340
 
        from .repository import WriteGroup
5341
5263
        gpg_strategy = gpg.GPGStrategy(b.get_config_stack())
5342
5264
        if revision_id_list is not None:
5343
 
            with WriteGroup(b.repository):
 
5265
            b.repository.start_write_group()
 
5266
            try:
5344
5267
                for revision_id in revision_id_list:
5345
5268
                    revision_id = cache_utf8.encode(revision_id)
5346
5269
                    b.repository.sign_revision(revision_id, gpg_strategy)
 
5270
            except BaseException:
 
5271
                b.repository.abort_write_group()
 
5272
                raise
 
5273
            else:
 
5274
                b.repository.commit_write_group()
5347
5275
        elif revision is not None:
5348
5276
            if len(revision) == 1:
5349
5277
                revno, rev_id = revision[0].in_history(b)
5350
 
                with WriteGroup(b.repository):
 
5278
                b.repository.start_write_group()
 
5279
                try:
5351
5280
                    b.repository.sign_revision(rev_id, gpg_strategy)
 
5281
                except BaseException:
 
5282
                    b.repository.abort_write_group()
 
5283
                    raise
 
5284
                else:
 
5285
                    b.repository.commit_write_group()
5352
5286
            elif len(revision) == 2:
5353
5287
                # are they both on rh- if so we can walk between them
5354
5288
                # might be nice to have a range helper for arbitrary
5360
5294
                if from_revno is None or to_revno is None:
5361
5295
                    raise errors.BzrCommandError(
5362
5296
                        gettext('Cannot sign a range of non-revision-history revisions'))
5363
 
                with WriteGroup(b.repository):
 
5297
                b.repository.start_write_group()
 
5298
                try:
5364
5299
                    for revno in range(from_revno, to_revno + 1):
5365
5300
                        b.repository.sign_revision(b.get_rev_id(revno),
5366
5301
                                                   gpg_strategy)
 
5302
                except BaseException:
 
5303
                    b.repository.abort_write_group()
 
5304
                    raise
 
5305
                else:
 
5306
                    b.repository.commit_write_group()
5367
5307
            else:
5368
5308
                raise errors.BzrCommandError(
5369
5309
                    gettext('Please supply either one revision, or a range.'))
5479
5419
            b = control.open_branch()
5480
5420
 
5481
5421
        if tree is not None:
5482
 
            self.enter_context(tree.lock_write())
 
5422
            self.add_cleanup(tree.lock_write().unlock)
5483
5423
        else:
5484
 
            self.enter_context(b.lock_write())
 
5424
            self.add_cleanup(b.lock_write().unlock)
5485
5425
        return self._run(b, tree, dry_run, verbose, revision, force,
5486
5426
                         local, keep_tags, location)
5487
5427
 
6064
6004
            revision=None,
6065
6005
            ):
6066
6006
        branch, relpath = Branch.open_containing(directory)
6067
 
        self.enter_context(branch.lock_write())
 
6007
        self.add_cleanup(branch.lock_write().unlock)
6068
6008
        if delete:
6069
6009
            if tag_name is None:
6070
6010
                raise errors.BzrCommandError(
6128
6068
        if not tags:
6129
6069
            return
6130
6070
 
6131
 
        self.enter_context(branch.lock_read())
 
6071
        self.add_cleanup(branch.lock_read().unlock)
6132
6072
        if revision:
6133
6073
            # Restrict to the specified range
6134
6074
            tags = self._tags_for_range(branch, revision)
6337
6277
        from . import switch
6338
6278
        tree_location = directory
6339
6279
        revision = _get_one_revision('switch', revision)
6340
 
        control_dir = controldir.ControlDir.open_containing(tree_location)[0]
6341
 
        possible_transports = [control_dir.root_transport]
 
6280
        possible_transports = []
 
6281
        control_dir = controldir.ControlDir.open_containing(tree_location,
 
6282
                                                            possible_transports=possible_transports)[0]
6342
6283
        if to_location is None:
6343
6284
            if revision is None:
6344
6285
                raise errors.BzrCommandError(gettext('You must supply either a'
6351
6292
        except errors.NotBranchError:
6352
6293
            branch = None
6353
6294
            had_explicit_nick = False
6354
 
        else:
6355
 
            possible_transports.append(branch.user_transport)
6356
6295
        if create_branch:
6357
6296
            if branch is None:
6358
6297
                raise errors.BzrCommandError(
6369
6308
                source_branch=branch).open_branch()
6370
6309
        else:
6371
6310
            try:
6372
 
                to_branch = Branch.open(
6373
 
                    to_location, possible_transports=possible_transports)
 
6311
                to_branch = Branch.open(to_location,
 
6312
                                        possible_transports=possible_transports)
6374
6313
            except errors.NotBranchError:
6375
6314
                to_branch = open_sibling_branch(
6376
6315
                    control_dir, to_location,
6377
6316
                    possible_transports=possible_transports)
6378
6317
            if revision is not None:
6379
6318
                revision = revision.as_revision_id(to_branch)
6380
 
        possible_transports.append(to_branch.user_transport)
6381
6319
        try:
6382
6320
            switch.switch(control_dir, to_branch, force, revision_id=revision,
6383
 
                          store_uncommitted=store,
6384
 
                          possible_transports=possible_transports)
 
6321
                          store_uncommitted=store)
6385
6322
        except controldir.BranchReferenceLoop:
6386
6323
            raise errors.BzrCommandError(
6387
6324
                gettext('switching would create a branch reference loop. '
6645
6582
    editor program to decide what the file remaining in the working copy
6646
6583
    should look like.  To do this, add the configuration option
6647
6584
 
6648
 
        change_editor = PROGRAM {new_path} {old_path}
 
6585
        change_editor = PROGRAM @new_path @old_path
6649
6586
 
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
 
6587
    where @new_path is replaced with the path of the new version of the
 
6588
    file and @old_path is replaced with the path of the old version of
6652
6589
    the file.  The PROGRAM should save the new file with the desired
6653
6590
    contents of the file in the working tree.
6654
6591
 
6692
6629
        if directory is None:
6693
6630
            directory = u'.'
6694
6631
        tree = WorkingTree.open_containing(directory)[0]
6695
 
        self.enter_context(tree.lock_read())
 
6632
        self.add_cleanup(tree.lock_read().unlock)
6696
6633
        manager = tree.get_shelf_manager()
6697
6634
        shelves = manager.active_shelves()
6698
6635
        if len(shelves) == 0:
6787
6724
 
6788
6725
    takes_args = ['path?', 'location?']
6789
6726
    takes_options = [
6790
 
        'directory',
6791
6727
        Option('force-unversioned',
6792
6728
               help='Set reference even if path is not versioned.'),
6793
6729
        ]
6794
6730
 
6795
 
    def run(self, path=None, directory='.', location=None, force_unversioned=False):
 
6731
    def run(self, path=None, location=None, force_unversioned=False):
 
6732
        branchdir = '.'
 
6733
        if path is not None:
 
6734
            branchdir = path
6796
6735
        tree, branch, relpath = (
6797
 
            controldir.ControlDir.open_containing_tree_or_branch(directory))
 
6736
            controldir.ControlDir.open_containing_tree_or_branch(branchdir))
 
6737
        if path is not None:
 
6738
            path = relpath
6798
6739
        if tree is None:
6799
6740
            tree = branch.basis_tree()
6800
6741
        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)
 
6742
            info = viewitems(branch._get_all_reference_info())
 
6743
            self._display_reference_info(tree, branch, info)
6806
6744
        else:
6807
6745
            if not tree.is_versioned(path) and not force_unversioned:
6808
6746
                raise errors.NotVersionedError(path)
6809
6747
            if location is None:
6810
 
                info = [(path, tree.get_reference_info(path, branch))]
 
6748
                info = [(path, branch.get_reference_info(path))]
6811
6749
                self._display_reference_info(tree, branch, info)
6812
6750
            else:
6813
 
                tree.set_reference_info(path, location)
 
6751
                branch.set_reference_info(
 
6752
                    path, location, file_id=tree.path2id(path))
6814
6753
 
6815
6754
    def _display_reference_info(self, tree, branch, info):
6816
6755
        ref_list = []
6817
 
        for path, location in info:
 
6756
        for path, (location, file_id) in info:
6818
6757
            ref_list.append((path, location))
6819
6758
        for path, location in sorted(ref_list):
6820
6759
            self.outf.write('%s %s\n' % (path, location))
7079
7018
            grep.versioned_grep(opts)
7080
7019
 
7081
7020
 
7082
 
class cmd_patch(Command):
7083
 
    """Apply a named patch to the current tree.
7084
 
 
7085
 
    """
7086
 
 
7087
 
    takes_args = ['filename?']
7088
 
    takes_options = [Option('strip', type=int, short_name='p',
7089
 
                            help=("Strip the smallest prefix containing num "
7090
 
                                  "leading slashes from filenames.")),
7091
 
                     Option('silent', help='Suppress chatter.')]
7092
 
 
7093
 
    def run(self, filename=None, strip=None, silent=False):
7094
 
        from .patch import patch_tree
7095
 
        wt = WorkingTree.open_containing('.')[0]
7096
 
        if strip is None:
7097
 
            strip = 1
7098
 
        my_file = None
7099
 
        if filename is None:
7100
 
            my_file = getattr(sys.stdin, 'buffer', sys.stdin)
7101
 
        else:
7102
 
            my_file = open(filename, 'rb')
7103
 
        patches = [my_file.read()]
7104
 
        return patch_tree(wt, patches, strip, quiet=is_quiet(), out=self.outf)
7105
 
 
7106
 
 
7107
 
class cmd_resolve_location(Command):
7108
 
    __doc__ = """Expand a location to a full URL.
7109
 
 
7110
 
    :Examples:
7111
 
        Look up a Launchpad URL.
7112
 
 
7113
 
            brz resolve-location lp:brz
7114
 
    """
7115
 
    takes_args = ['location']
7116
 
    hidden = True
7117
 
 
7118
 
    def run(self, location):
7119
 
        from .location import location_to_url
7120
 
        url = location_to_url(location)
7121
 
        display_url = urlutils.unescape_for_display(url, self.outf.encoding)
7122
 
        self.outf.write('%s\n' % display_url)
7123
 
 
7124
 
 
7125
7021
def _register_lazy_builtins():
7126
7022
    # register lazy builtins from other modules; called at startup and should
7127
7023
    # be only called once.
7128
7024
    for (name, aliases, module_name) in [
7129
7025
            ('cmd_bisect', [], 'breezy.bisect'),
7130
 
            ('cmd_bundle_info', [], 'breezy.bzr.bundle.commands'),
 
7026
            ('cmd_bundle_info', [], 'breezy.bundle.commands'),
7131
7027
            ('cmd_config', [], 'breezy.config'),
7132
7028
            ('cmd_dump_btree', [], 'breezy.bzr.debug_commands'),
7133
7029
            ('cmd_file_id', [], 'breezy.bzr.debug_commands'),