/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 bzrlib/builtins.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
83
83
    )
84
84
 
85
85
 
86
 
def _get_branch_location(control_dir, possible_transports=None):
87
 
    """Return location of branch for this control dir."""
88
 
    try:
89
 
        target = control_dir.get_branch_reference()
90
 
    except errors.NotBranchError:
91
 
        return control_dir.root_transport.base
92
 
    if target is not None:
93
 
        return target
94
 
    this_branch = control_dir.open_branch(
95
 
        possible_transports=possible_transports)
96
 
    # This may be a heavy checkout, where we want the master branch
97
 
    master_location = this_branch.get_bound_location()
98
 
    if master_location is not None:
99
 
        return master_location
100
 
    # If not, use a local sibling
101
 
    return this_branch.base
102
 
 
103
 
 
104
 
def _is_colocated(control_dir, possible_transports=None):
105
 
    """Check if the branch in control_dir is colocated.
106
 
 
107
 
    :param control_dir: Control directory
108
 
    :return: Tuple with boolean indicating whether the branch is colocated
109
 
        and the full URL to the actual branch
110
 
    """
111
 
    # This path is meant to be relative to the existing branch
112
 
    this_url = _get_branch_location(control_dir,
113
 
        possible_transports=possible_transports)
114
 
    # Perhaps the target control dir supports colocated branches?
115
 
    try:
116
 
        root = controldir.ControlDir.open(this_url,
117
 
            possible_transports=possible_transports)
118
 
    except errors.NotBranchError:
119
 
        return (False, this_url)
120
 
    else:
121
 
        try:
122
 
            wt = control_dir.open_workingtree()
123
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
124
 
            return (False, this_url)
125
 
        else:
126
 
            return (
127
 
                root._format.colocated_branches and
128
 
                control_dir.control_url == root.control_url,
129
 
                this_url)
130
 
 
131
 
 
132
 
def lookup_new_sibling_branch(control_dir, location, possible_transports=None):
133
 
    """Lookup the location for a new sibling branch.
134
 
 
135
 
    :param control_dir: Control directory to find sibling branches from
136
 
    :param location: Name of the new branch
137
 
    :return: Full location to the new branch
138
 
    """
139
 
    location = directory_service.directories.dereference(location)
140
 
    if '/' not in location and '\\' not in location:
141
 
        (colocated, this_url) = _is_colocated(control_dir, possible_transports)
142
 
 
143
 
        if colocated:
144
 
            return urlutils.join_segment_parameters(this_url,
145
 
                {"branch": urlutils.escape(location)})
146
 
        else:
147
 
            return urlutils.join(this_url, '..', urlutils.escape(location))
148
 
    return location
149
 
 
150
 
 
151
 
def open_sibling_branch(control_dir, location, possible_transports=None):
152
 
    """Open a branch, possibly a sibling of another.
153
 
 
154
 
    :param control_dir: Control directory relative to which to lookup the
155
 
        location.
156
 
    :param location: Location to look up
157
 
    :return: branch to open
158
 
    """
159
 
    try:
160
 
        # Perhaps it's a colocated branch?
161
 
        return control_dir.open_branch(location, 
162
 
            possible_transports=possible_transports)
163
 
    except (errors.NotBranchError, errors.NoColocatedBranchSupport):
164
 
        this_url = _get_branch_location(control_dir)
165
 
        return Branch.open(
166
 
            urlutils.join(
167
 
                this_url, '..', urlutils.escape(location)))
168
 
 
169
 
 
170
 
def open_nearby_branch(near=None, location=None, possible_transports=None):
171
 
    """Open a nearby branch.
172
 
 
173
 
    :param near: Optional location of container from which to open branch
174
 
    :param location: Location of the branch
175
 
    :return: Branch instance
176
 
    """
177
 
    if near is None:
178
 
        if location is None:
179
 
            location = "."
180
 
        try:
181
 
            return Branch.open(location,
182
 
                possible_transports=possible_transports)
183
 
        except errors.NotBranchError:
184
 
            near = "."
185
 
    cdir = controldir.ControlDir.open(near,
186
 
        possible_transports=possible_transports)
187
 
    return open_sibling_branch(cdir, location,
188
 
        possible_transports=possible_transports)
189
 
 
190
 
 
191
 
def iter_sibling_branches(control_dir, possible_transports=None):
192
 
    """Iterate over the siblings of a branch.
193
 
 
194
 
    :param control_dir: Control directory for which to look up the siblings
195
 
    :return: Iterator over tuples with branch name and branch object
196
 
    """
197
 
    seen_urls = set()
198
 
    try:
199
 
        reference = control_dir.get_branch_reference()
200
 
    except errors.NotBranchError:
201
 
        # There is no active branch, just return the colocated branches.
202
 
        for name, branch in control_dir.get_branches().iteritems():
203
 
            yield name, branch
204
 
        return
205
 
    if reference is not None:
206
 
        ref_branch = Branch.open(reference,
207
 
            possible_transports=possible_transports)
208
 
    else:
209
 
        ref_branch = None
210
 
    if ref_branch is None or ref_branch.name:
211
 
        if ref_branch is not None:
212
 
            control_dir = ref_branch.bzrdir
213
 
        for name, branch in control_dir.get_branches().iteritems():
214
 
            yield name, branch
215
 
    else:
216
 
        repo = ref_branch.bzrdir.find_repository()
217
 
        for branch in repo.find_branches(using=True):
218
 
            name = urlutils.relative_url(repo.user_url,
219
 
                branch.user_url).rstrip("/")
220
 
            yield name, branch
 
86
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
 
87
def tree_files(file_list, default_branch=u'.', canonicalize=True,
 
88
    apply_view=True):
 
89
    return internal_tree_files(file_list, default_branch, canonicalize,
 
90
        apply_view)
221
91
 
222
92
 
223
93
def tree_files_for_add(file_list):
285
155
    return rev_tree
286
156
 
287
157
 
 
158
# XXX: Bad function name; should possibly also be a class method of
 
159
# WorkingTree rather than a function.
 
160
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
 
161
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
 
162
    apply_view=True):
 
163
    """Convert command-line paths to a WorkingTree and relative paths.
 
164
 
 
165
    Deprecated: use WorkingTree.open_containing_paths instead.
 
166
 
 
167
    This is typically used for command-line processors that take one or
 
168
    more filenames, and infer the workingtree that contains them.
 
169
 
 
170
    The filenames given are not required to exist.
 
171
 
 
172
    :param file_list: Filenames to convert.
 
173
 
 
174
    :param default_branch: Fallback tree path to use if file_list is empty or
 
175
        None.
 
176
 
 
177
    :param apply_view: if True and a view is set, apply it or check that
 
178
        specified files are within it
 
179
 
 
180
    :return: workingtree, [relative_paths]
 
181
    """
 
182
    return WorkingTree.open_containing_paths(
 
183
        file_list, default_directory='.',
 
184
        canonicalize=True,
 
185
        apply_view=True)
 
186
 
 
187
 
288
188
def _get_view_info_for_change_reporter(tree):
289
189
    """Get the view information from a tree for change reporting."""
290
190
    view_info = None
368
268
    This will produce the same results as calling 'bzr diff --summarize'.
369
269
    """
370
270
 
371
 
    # TODO: --no-recurse/-N, --recurse options
 
271
    # TODO: --no-recurse, --recurse options
372
272
 
373
273
    takes_args = ['file*']
374
274
    takes_options = ['show-ids', 'revision', 'change', 'verbose',
685
585
            if revision:
686
586
                if len(revision) != 1:
687
587
                    raise errors.BzrCommandError(gettext(
688
 
                        "Revision numbers only make sense for single "
689
 
                        "revisions, not ranges"))
 
588
                        "Tags can only be placed on a single revision, "
 
589
                        "not on a range"))
690
590
                revid = revision[0].as_revision_id(b)
691
591
            else:
692
592
                revid = b.last_revision()
803
703
    takes_args = ['file*']
804
704
    takes_options = [
805
705
        Option('no-recurse',
806
 
               help="Don't recursively add the contents of directories.",
807
 
               short_name='N'),
 
706
               help="Don't recursively add the contents of directories."),
808
707
        Option('dry-run',
809
708
               help="Show what would be done, but don't actually do anything."),
810
709
        'verbose',
950
849
            tree = work_tree
951
850
            extra_trees = []
952
851
 
953
 
        self.add_cleanup(tree.lock_read().unlock)
954
852
        if file_list is not None:
955
853
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
956
854
                                      require_versioned=True)
957
855
            # find_ids_across_trees may include some paths that don't
958
856
            # exist in 'tree'.
959
 
            entries = tree.iter_entries_by_dir(specific_file_ids=file_ids)
 
857
            entries = sorted(
 
858
                (tree.id2path(file_id), tree.inventory[file_id])
 
859
                for file_id in file_ids if tree.has_id(file_id))
960
860
        else:
961
 
            entries = tree.iter_entries_by_dir()
 
861
            entries = tree.inventory.entries()
962
862
 
963
 
        for path, entry in sorted(entries):
 
863
        self.cleanup_now()
 
864
        for path, entry in entries:
964
865
            if kind and kind != entry.kind:
965
866
                continue
966
 
            if path == "":
967
 
                continue
968
867
            if show_ids:
969
868
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
970
869
            else:
1042
941
                and rel_names[0].lower() == rel_names[1].lower()):
1043
942
                into_existing = False
1044
943
            else:
 
944
                inv = tree.inventory
1045
945
                # 'fix' the case of a potential 'from'
1046
946
                from_id = tree.path2id(
1047
947
                            tree.get_canonical_inventory_path(rel_names[0]))
1048
948
                if (not osutils.lexists(names_list[0]) and
1049
 
                    from_id and tree.stored_kind(from_id) == "directory"):
 
949
                    from_id and inv.get_file_kind(from_id) == "directory"):
1050
950
                    into_existing = False
1051
951
        # move/rename
1052
952
        if into_existing:
1153
1053
                 "the master branch."
1154
1054
            ),
1155
1055
        Option('show-base',
1156
 
            help="Show base revision text in conflicts."),
1157
 
        Option('overwrite-tags',
1158
 
            help="Overwrite tags only."),
 
1056
            help="Show base revision text in conflicts.")
1159
1057
        ]
1160
1058
    takes_args = ['location?']
1161
1059
    encoding_type = 'replace'
1163
1061
    def run(self, location=None, remember=None, overwrite=False,
1164
1062
            revision=None, verbose=False,
1165
1063
            directory=None, local=False,
1166
 
            show_base=False, overwrite_tags=False):
1167
 
 
1168
 
        if overwrite:
1169
 
            overwrite = ["history", "tags"]
1170
 
        elif overwrite_tags:
1171
 
            overwrite = ["tags"]
1172
 
        else:
1173
 
            overwrite = []
 
1064
            show_base=False):
1174
1065
        # FIXME: too much stuff is in the command class
1175
1066
        revision_id = None
1176
1067
        mergeable = None
1184
1075
            tree_to = None
1185
1076
            branch_to = Branch.open_containing(directory)[0]
1186
1077
            self.add_cleanup(branch_to.lock_write().unlock)
1187
 
            if show_base:
1188
 
                warning(gettext("No working tree, ignoring --show-base"))
 
1078
 
 
1079
        if tree_to is None and show_base:
 
1080
            raise errors.BzrCommandError(gettext("Need working tree for --show-base."))
1189
1081
 
1190
1082
        if local and not branch_to.get_bound_location():
1191
1083
            raise errors.LocalRequiresBoundBranch()
1313
1205
        Option('no-tree',
1314
1206
               help="Don't populate the working tree, even for protocols"
1315
1207
               " that support it."),
1316
 
        Option('overwrite-tags',
1317
 
              help="Overwrite tags only."),
1318
1208
        ]
1319
1209
    takes_args = ['location?']
1320
1210
    encoding_type = 'replace'
1322
1212
    def run(self, location=None, remember=None, overwrite=False,
1323
1213
        create_prefix=False, verbose=False, revision=None,
1324
1214
        use_existing_dir=False, directory=None, stacked_on=None,
1325
 
        stacked=False, strict=None, no_tree=False,
1326
 
        overwrite_tags=False):
 
1215
        stacked=False, strict=None, no_tree=False):
1327
1216
        from bzrlib.push import _show_push_branch
1328
1217
 
1329
 
        if overwrite:
1330
 
            overwrite = ["history", "tags"]
1331
 
        elif overwrite_tags:
1332
 
            overwrite = ["tags"]
1333
 
        else:
1334
 
            overwrite = []
1335
 
 
1336
1218
        if directory is None:
1337
1219
            directory = '.'
1338
1220
        # Get the source branch
1468
1350
            revision_id = br_from.last_revision()
1469
1351
        if to_location is None:
1470
1352
            to_location = getattr(br_from, "name", None)
1471
 
            if not to_location:
 
1353
            if to_location is None:
1472
1354
                to_location = urlutils.derive_to_location(from_location)
1473
1355
        to_transport = transport.get_transport(to_location)
1474
1356
        try:
1514
1396
                    from_location, revision)
1515
1397
                raise errors.BzrCommandError(msg)
1516
1398
        else:
1517
 
            try:
1518
 
                to_repo = to_dir.open_repository()
1519
 
            except errors.NoRepositoryPresent:
1520
 
                to_repo = to_dir.create_repository()
1521
 
            to_repo.fetch(br_from.repository, revision_id=revision_id)
1522
1399
            branch = br_from.sprout(to_dir, revision_id=revision_id)
1523
1400
        _merge_tags_if_possible(br_from, branch)
1524
1401
        # If the source branch is stacked, the new branch may
1569
1446
        else:
1570
1447
            dir = controldir.ControlDir.open_containing(location)[0]
1571
1448
            try:
1572
 
                active_branch = dir.open_branch(name="")
 
1449
                active_branch = dir.open_branch(name=None)
1573
1450
            except errors.NotBranchError:
1574
1451
                active_branch = None
 
1452
            branches = dir.get_branches()
1575
1453
            names = {}
1576
 
            for name, branch in iter_sibling_branches(dir):
1577
 
                if name == "":
 
1454
            for name, branch in branches.iteritems():
 
1455
                if name is None:
1578
1456
                    continue
1579
1457
                active = (active_branch is not None and
1580
1458
                          active_branch.base == branch.base)
1614
1492
    code.)
1615
1493
    """
1616
1494
 
1617
 
    _see_also = ['checkouts', 'branch', 'working-trees', 'remove-tree']
 
1495
    _see_also = ['checkouts', 'branch']
1618
1496
    takes_args = ['branch_location?', 'to_location?']
1619
1497
    takes_options = ['revision',
1620
1498
                     Option('lightweight',
1680
1558
    def run(self, dir=u'.'):
1681
1559
        tree = WorkingTree.open_containing(dir)[0]
1682
1560
        self.add_cleanup(tree.lock_read().unlock)
 
1561
        new_inv = tree.inventory
1683
1562
        old_tree = tree.basis_tree()
1684
1563
        self.add_cleanup(old_tree.lock_read().unlock)
 
1564
        old_inv = old_tree.inventory
1685
1565
        renames = []
1686
1566
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1687
1567
        for f, paths, c, v, p, n, k, e in iterator:
1858
1738
 
1859
1739
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
1860
1740
    delete them if they can easily be recovered using revert otherwise they
1861
 
    will be backed up (adding an extension of the form .~#~). If no options or
 
1741
    will be backed up (adding an extention of the form .~#~). If no options or
1862
1742
    parameters are given Bazaar will scan for files that are being tracked by
1863
1743
    Bazaar but missing in your tree and stop tracking them for you.
1864
1744
    """
1870
1750
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1871
1751
            safe='Backup changed files (default).',
1872
1752
            keep='Delete from bzr but leave the working copy.',
1873
 
            no_backup='Don\'t backup changed files.'),
1874
 
        ]
 
1753
            no_backup='Don\'t backup changed files.',
 
1754
            force='Delete all the specified files, even if they can not be '
 
1755
                'recovered and even if they are non-empty directories. '
 
1756
                '(deprecated, use no-backup)')]
1875
1757
    aliases = ['rm', 'del']
1876
1758
    encoding_type = 'replace'
1877
1759
 
1878
1760
    def run(self, file_list, verbose=False, new=False,
1879
1761
        file_deletion_strategy='safe'):
 
1762
        if file_deletion_strategy == 'force':
 
1763
            note(gettext("(The --force option is deprecated, rather use --no-backup "
 
1764
                "in future.)"))
 
1765
            file_deletion_strategy = 'no-backup'
1880
1766
 
1881
1767
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1882
1768
 
2066
1952
         RegistryOption('format',
2067
1953
                help='Specify a format for this branch. '
2068
1954
                'See "help formats".',
2069
 
                lazy_registry=('bzrlib.controldir', 'format_registry'),
 
1955
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
2070
1956
                converter=lambda name: controldir.format_registry.make_bzrdir(name),
2071
1957
                value_switches=True,
2072
1958
                title="Branch format",
2328
2214
            help='Diff format to use.',
2329
2215
            lazy_registry=('bzrlib.diff', 'format_registry'),
2330
2216
            title='Diff format'),
2331
 
        Option('context',
2332
 
            help='How many lines of context to show.',
2333
 
            type=int,
2334
 
            ),
2335
2217
        ]
2336
2218
    aliases = ['di', 'dif']
2337
2219
    encoding_type = 'exact'
2338
2220
 
2339
2221
    @display_command
2340
2222
    def run(self, revision=None, file_list=None, diff_options=None,
2341
 
            prefix=None, old=None, new=None, using=None, format=None, 
2342
 
            context=None):
 
2223
            prefix=None, old=None, new=None, using=None, format=None):
2343
2224
        from bzrlib.diff import (get_trees_and_branches_to_diff_locked,
2344
2225
            show_diff_trees)
2345
2226
 
2378
2259
                               old_label=old_label, new_label=new_label,
2379
2260
                               extra_trees=extra_trees,
2380
2261
                               path_encoding=path_encoding,
2381
 
                               using=using, context=context,
 
2262
                               using=using,
2382
2263
                               format_cls=format)
2383
2264
 
2384
2265
 
2400
2281
        self.add_cleanup(tree.lock_read().unlock)
2401
2282
        old = tree.basis_tree()
2402
2283
        self.add_cleanup(old.lock_read().unlock)
2403
 
        for path, ie in old.iter_entries_by_dir():
 
2284
        for path, ie in old.inventory.iter_entries():
2404
2285
            if not tree.has_id(ie.file_id):
2405
2286
                self.outf.write(path)
2406
2287
                if show_ids:
2444
2325
        self.add_cleanup(wt.lock_read().unlock)
2445
2326
        basis = wt.basis_tree()
2446
2327
        self.add_cleanup(basis.lock_read().unlock)
2447
 
        root_id = wt.get_root_id()
2448
 
        for file_id in wt.all_file_ids():
2449
 
            if basis.has_id(file_id):
2450
 
                continue
2451
 
            if root_id == file_id:
2452
 
                continue
2453
 
            path = wt.id2path(file_id)
 
2328
        basis_inv = basis.inventory
 
2329
        inv = wt.inventory
 
2330
        for file_id in inv:
 
2331
            if basis_inv.has_id(file_id):
 
2332
                continue
 
2333
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
2334
                continue
 
2335
            path = inv.id2path(file_id)
2454
2336
            if not os.access(osutils.pathjoin(wt.basedir, path), os.F_OK):
2455
2337
                continue
2456
2338
            if null:
2818
2700
            self.add_cleanup(b.lock_read().unlock)
2819
2701
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2820
2702
 
2821
 
        if b.get_config_stack().get('validate_signatures_in_log'):
 
2703
        if b.get_config().validate_signatures_in_log():
2822
2704
            signatures = True
2823
2705
 
2824
2706
        if signatures:
3544
3426
            tokens = fixed_bug.split(':')
3545
3427
            if len(tokens) == 1:
3546
3428
                if default_bugtracker is None:
3547
 
                    branch_config = branch.get_config_stack()
3548
 
                    default_bugtracker = branch_config.get(
 
3429
                    branch_config = branch.get_config()
 
3430
                    default_bugtracker = branch_config.get_user_option(
3549
3431
                        "bugtracker")
3550
3432
                if default_bugtracker is None:
3551
3433
                    raise errors.BzrCommandError(gettext(
3901
3783
class cmd_nick(Command):
3902
3784
    __doc__ = """Print or set the branch nickname.
3903
3785
 
3904
 
    If unset, the colocated branch name is used for colocated branches, and
3905
 
    the branch directory name is used for other branches.  To print the
3906
 
    current nickname, execute with no argument.
 
3786
    If unset, the tree root directory name is used as the nickname.
 
3787
    To print the current nickname, execute with no argument.
3907
3788
 
3908
3789
    Bound branches use the nickname of its master branch unless it is set
3909
3790
    locally.
4291
4172
    Merge will do its best to combine the changes in two branches, but there
4292
4173
    are some kinds of problems only a human can fix.  When it encounters those,
4293
4174
    it will mark a conflict.  A conflict means that you need to fix something,
4294
 
    before you can commit.
 
4175
    before you should commit.
4295
4176
 
4296
4177
    Use bzr resolve when you have fixed a problem.  See also bzr conflicts.
4297
4178
 
4705
4586
                if tree.kind(file_id) != "directory":
4706
4587
                    continue
4707
4588
 
4708
 
                # FIXME: Support nested trees
4709
 
                for name, ie in tree.root_inventory.iter_entries(file_id):
 
4589
                for name, ie in tree.inventory.iter_entries(file_id):
4710
4590
                    interesting_ids.add(ie.file_id)
4711
4591
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
4712
4592
        else:
4745
4625
 
4746
4626
 
4747
4627
class cmd_revert(Command):
4748
 
    __doc__ = """\
4749
 
    Set files in the working tree back to the contents of a previous revision.
 
4628
    __doc__ = """Revert files to a previous revision.
4750
4629
 
4751
4630
    Giving a list of files will revert only those files.  Otherwise, all files
4752
4631
    will be reverted.  If the revision is not specified with '--revision', the
4753
 
    working tree basis revision is used. A revert operation affects only the
4754
 
    working tree, not any revision history like the branch and repository or
4755
 
    the working tree basis revision.
 
4632
    last committed revision is used.
4756
4633
 
4757
4634
    To remove only some changes, without reverting to a prior version, use
4758
4635
    merge instead.  For example, "merge . -r -2..-3" (don't forget the ".")
4759
4636
    will remove the changes introduced by the second last commit (-2), without
4760
4637
    affecting the changes introduced by the last commit (-1).  To remove
4761
4638
    certain changes on a hunk-by-hunk basis, see the shelve command.
4762
 
    To update the branch to a specific revision or the latest revision and
4763
 
    update the working tree accordingly while preserving local changes, see the
4764
 
    update command.
4765
4639
 
4766
 
    Uncommitted changes to files that are reverted will be discarded.
4767
 
    Howver, by default, any files that have been manually changed will be
4768
 
    backed up first.  (Files changed only by merge are not backed up.)  Backup
4769
 
    files have '.~#~' appended to their name, where # is a number.
 
4640
    By default, any files that have been manually changed will be backed up
 
4641
    first.  (Files changed only by merge are not backed up.)  Backup files have
 
4642
    '.~#~' appended to their name, where # is a number.
4770
4643
 
4771
4644
    When you provide files, you can use their current pathname or the pathname
4772
4645
    from the target revision.  So you can use revert to "undelete" a file by
5019
4892
                             "You have %d extra revisions:\n", 
5020
4893
                             len(local_extra)) %
5021
4894
                len(local_extra))
5022
 
            rev_tag_dict = {}
5023
 
            if local_branch.supports_tags():
5024
 
                rev_tag_dict = local_branch.tags.get_reverse_tag_dict()
5025
4895
            for revision in iter_log_revisions(local_extra,
5026
4896
                                local_branch.repository,
5027
 
                                verbose,
5028
 
                                rev_tag_dict):
 
4897
                                verbose):
5029
4898
                lf.log_revision(revision)
5030
4899
            printed_local = True
5031
4900
            status_code = 1
5039
4908
                             "You are missing %d revisions:\n",
5040
4909
                             len(remote_extra)) %
5041
4910
                len(remote_extra))
5042
 
            if remote_branch.supports_tags():
5043
 
                rev_tag_dict = remote_branch.tags.get_reverse_tag_dict()
5044
4911
            for revision in iter_log_revisions(remote_extra,
5045
4912
                                remote_branch.repository,
5046
 
                                verbose,
5047
 
                                rev_tag_dict):
 
4913
                                verbose):
5048
4914
                lf.log_revision(revision)
5049
4915
            status_code = 1
5050
4916
 
5140
5006
            Option('strict',
5141
5007
                   help='Produce a strict-format testament.')]
5142
5008
    takes_args = ['branch?']
5143
 
    encoding_type = 'exact'
5144
5009
    @display_command
5145
5010
    def run(self, branch=u'.', revision=None, long=False, strict=False):
5146
5011
        from bzrlib.testament import Testament, StrictTestament
5159
5024
            rev_id = revision[0].as_revision_id(b)
5160
5025
        t = testament_class.from_revision(b.repository, rev_id)
5161
5026
        if long:
5162
 
            self.outf.writelines(t.as_text_lines())
 
5027
            sys.stdout.writelines(t.as_text_lines())
5163
5028
        else:
5164
 
            self.outf.write(t.as_short_text())
 
5029
            sys.stdout.write(t.as_short_text())
5165
5030
 
5166
5031
 
5167
5032
class cmd_annotate(Command):
5523
5388
               help="Protocol to serve.",
5524
5389
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
5525
5390
               value_switches=True),
5526
 
        Option('listen',
5527
 
               help='Listen for connections on nominated address.', type=str),
5528
5391
        Option('port',
5529
 
               help='Listen for connections on nominated port.  Passing 0 as '
5530
 
                    'the port number will result in a dynamically allocated '
5531
 
                    'port.  The default port depends on the protocol.',
5532
 
               type=int),
 
5392
               help='Listen for connections on nominated port of the form '
 
5393
                    '[hostname:]portnumber.  Passing 0 as the port number will '
 
5394
                    'result in a dynamically allocated port.  The default port '
 
5395
                    'depends on the protocol.',
 
5396
               type=str),
5533
5397
        custom_help('directory',
5534
5398
               help='Serve contents of this directory.'),
5535
5399
        Option('allow-writes',
5545
5409
               help='Override the default idle client timeout (5min).'),
5546
5410
        ]
5547
5411
 
5548
 
    def run(self, listen=None, port=None, inet=False, directory=None,
5549
 
            allow_writes=False, protocol=None, client_timeout=None):
 
5412
    def get_host_and_port(self, port):
 
5413
        """Return the host and port to run the smart server on.
 
5414
 
 
5415
        If 'port' is None, None will be returned for the host and port.
 
5416
 
 
5417
        If 'port' has a colon in it, the string before the colon will be
 
5418
        interpreted as the host.
 
5419
 
 
5420
        :param port: A string of the port to run the server on.
 
5421
        :return: A tuple of (host, port), where 'host' is a host name or IP,
 
5422
            and port is an integer TCP/IP port.
 
5423
        """
 
5424
        host = None
 
5425
        if port is not None:
 
5426
            if ':' in port:
 
5427
                host, port = port.split(':')
 
5428
            port = int(port)
 
5429
        return host, port
 
5430
 
 
5431
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
 
5432
            protocol=None, client_timeout=None):
5550
5433
        from bzrlib import transport
5551
5434
        if directory is None:
5552
5435
            directory = os.getcwd()
5553
5436
        if protocol is None:
5554
5437
            protocol = transport.transport_server_registry.get()
 
5438
        host, port = self.get_host_and_port(port)
5555
5439
        url = transport.location_to_url(directory)
5556
5440
        if not allow_writes:
5557
5441
            url = 'readonly+' + url
5558
5442
        t = transport.get_transport_from_url(url)
5559
 
        protocol(t, listen, port, inet, client_timeout)
 
5443
        try:
 
5444
            protocol(t, host, port, inet, client_timeout)
 
5445
        except TypeError, e:
 
5446
            # We use symbol_versioning.deprecated_in just so that people
 
5447
            # grepping can find it here.
 
5448
            # symbol_versioning.deprecated_in((2, 5, 0))
 
5449
            symbol_versioning.warn(
 
5450
                'Got TypeError(%s)\ntrying to call protocol: %s.%s\n'
 
5451
                'Most likely it needs to be updated to support a'
 
5452
                ' "timeout" parameter (added in bzr 2.5.0)'
 
5453
                % (e, protocol.__module__, protocol),
 
5454
                DeprecationWarning)
 
5455
            protocol(t, host, port, inet)
5560
5456
 
5561
5457
 
5562
5458
class cmd_join(Command):
6232
6128
                     Option('create-branch', short_name='b',
6233
6129
                        help='Create the target branch from this one before'
6234
6130
                             ' switching to it.'),
6235
 
                     Option('store',
6236
 
                        help='Store and restore uncommitted changes in the'
6237
 
                             ' branch.'),
6238
6131
                    ]
6239
6132
 
6240
6133
    def run(self, to_location=None, force=False, create_branch=False,
6241
 
            revision=None, directory=u'.', store=False):
 
6134
            revision=None, directory=u'.'):
6242
6135
        from bzrlib import switch
6243
6136
        tree_location = directory
6244
6137
        revision = _get_one_revision('switch', revision)
6245
 
        possible_transports = []
6246
 
        control_dir = controldir.ControlDir.open_containing(tree_location,
6247
 
            possible_transports=possible_transports)[0]
 
6138
        control_dir = controldir.ControlDir.open_containing(tree_location)[0]
6248
6139
        if to_location is None:
6249
6140
            if revision is None:
6250
6141
                raise errors.BzrCommandError(gettext('You must supply either a'
6251
6142
                                             ' revision or a location'))
6252
6143
            to_location = tree_location
6253
6144
        try:
6254
 
            branch = control_dir.open_branch(
6255
 
                possible_transports=possible_transports)
 
6145
            branch = control_dir.open_branch()
6256
6146
            had_explicit_nick = branch.get_config().has_explicit_nickname()
6257
6147
        except errors.NotBranchError:
6258
6148
            branch = None
6259
6149
            had_explicit_nick = False
6260
6150
        if create_branch:
6261
6151
            if branch is None:
6262
 
                raise errors.BzrCommandError(
6263
 
                    gettext('cannot create branch without source branch'))
6264
 
            to_location = lookup_new_sibling_branch(control_dir, to_location,
6265
 
                 possible_transports=possible_transports)
 
6152
                raise errors.BzrCommandError(gettext('cannot create branch without'
 
6153
                                             ' source branch'))
 
6154
            to_location = directory_service.directories.dereference(
 
6155
                              to_location)
 
6156
            if '/' not in to_location and '\\' not in to_location:
 
6157
                # This path is meant to be relative to the existing branch
 
6158
                this_url = self._get_branch_location(control_dir)
 
6159
                # Perhaps the target control dir supports colocated branches?
 
6160
                try:
 
6161
                    root = controldir.ControlDir.open(this_url,
 
6162
                        possible_transports=[control_dir.user_transport])
 
6163
                except errors.NotBranchError:
 
6164
                    colocated = False
 
6165
                else:
 
6166
                    colocated = root._format.colocated_branches
 
6167
                if colocated:
 
6168
                    to_location = urlutils.join_segment_parameters(this_url,
 
6169
                        {"branch": urlutils.escape(to_location)})
 
6170
                else:
 
6171
                    to_location = urlutils.join(
 
6172
                        this_url, '..', urlutils.escape(to_location))
6266
6173
            to_branch = branch.bzrdir.sprout(to_location,
6267
 
                 possible_transports=possible_transports,
6268
 
                 source_branch=branch).open_branch()
 
6174
                                 possible_transports=[branch.bzrdir.root_transport],
 
6175
                                 source_branch=branch).open_branch()
6269
6176
        else:
 
6177
            # Perhaps it's a colocated branch?
6270
6178
            try:
6271
 
                to_branch = Branch.open(to_location,
6272
 
                    possible_transports=possible_transports)
6273
 
            except errors.NotBranchError:
6274
 
                to_branch = open_sibling_branch(control_dir, to_location,
6275
 
                    possible_transports=possible_transports)
 
6179
                to_branch = control_dir.open_branch(to_location)
 
6180
            except (errors.NotBranchError, errors.NoColocatedBranchSupport):
 
6181
                try:
 
6182
                    to_branch = Branch.open(to_location)
 
6183
                except errors.NotBranchError:
 
6184
                    this_url = self._get_branch_location(control_dir)
 
6185
                    to_branch = Branch.open(
 
6186
                        urlutils.join(
 
6187
                            this_url, '..', urlutils.escape(to_location)))
6276
6188
        if revision is not None:
6277
6189
            revision = revision.as_revision_id(to_branch)
6278
 
        switch.switch(control_dir, to_branch, force, revision_id=revision,
6279
 
                      store_uncommitted=store)
 
6190
        switch.switch(control_dir, to_branch, force, revision_id=revision)
6280
6191
        if had_explicit_nick:
6281
6192
            branch = control_dir.open_branch() #get the new branch!
6282
6193
            branch.nick = to_branch.nick
6283
6194
        note(gettext('Switched to branch: %s'),
6284
6195
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
6285
6196
 
 
6197
    def _get_branch_location(self, control_dir):
 
6198
        """Return location of branch for this control dir."""
 
6199
        try:
 
6200
            this_branch = control_dir.open_branch()
 
6201
            # This may be a heavy checkout, where we want the master branch
 
6202
            master_location = this_branch.get_bound_location()
 
6203
            if master_location is not None:
 
6204
                return master_location
 
6205
            # If not, use a local sibling
 
6206
            return this_branch.base
 
6207
        except errors.NotBranchError:
 
6208
            format = control_dir.find_branch_format()
 
6209
            if getattr(format, 'get_reference', None) is not None:
 
6210
                return format.get_reference(control_dir)
 
6211
            else:
 
6212
                return control_dir.root_transport.base
6286
6213
 
6287
6214
 
6288
6215
class cmd_view(Command):
6476
6403
 
6477
6404
    takes_args = ["location?"]
6478
6405
 
6479
 
    takes_options = ['directory',
6480
 
        Option('force', help='Remove branch even if it is the active branch.')]
6481
 
 
6482
6406
    aliases = ["rmbranch"]
6483
6407
 
6484
 
    def run(self, directory=None, location=None, force=False):
6485
 
        br = open_nearby_branch(near=directory, location=location)
6486
 
        if not force and br.bzrdir.has_workingtree():
6487
 
            try:
6488
 
                active_branch = br.bzrdir.open_branch(name="")
6489
 
            except errors.NotBranchError:
6490
 
                active_branch = None
6491
 
            if (active_branch is not None and
6492
 
                br.control_url == active_branch.control_url):
6493
 
                raise errors.BzrCommandError(
6494
 
                    gettext("Branch is active. Use --force to remove it."))
6495
 
        br.bzrdir.destroy_branch(br.name)
 
6408
    def run(self, location=None):
 
6409
        if location is None:
 
6410
            location = "."
 
6411
        branch = Branch.open_containing(location)[0]
 
6412
        branch.bzrdir.destroy_branch()
6496
6413
 
6497
6414
 
6498
6415
class cmd_shelve(Command):
6727
6644
        ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
6728
6645
        ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
6729
6646
        ('cmd_conflicts', [], 'bzrlib.conflicts'),
6730
 
        ('cmd_ping', [], 'bzrlib.smart.ping'),
6731
6647
        ('cmd_sign_my_commits', [], 'bzrlib.commit_signature_commands'),
6732
 
        ('cmd_verify_signatures', [], 'bzrlib.commit_signature_commands'),
 
6648
        ('cmd_verify_signatures', [],
 
6649
                                        'bzrlib.commit_signature_commands'),
6733
6650
        ('cmd_test_script', [], 'bzrlib.cmd_test_script'),
6734
6651
        ]:
6735
6652
        builtin_command_registry.register_lazy(name, aliases, module_name)