~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

(vila) Rename assertWarns in test_config to avoid clashing with unittest2
 assertWarns. (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
86
86
def _get_branch_location(control_dir, possible_transports=None):
87
87
    """Return location of branch for this control dir."""
88
88
    try:
89
 
        this_branch = control_dir.open_branch(
90
 
            possible_transports=possible_transports)
91
 
        # This may be a heavy checkout, where we want the master branch
92
 
        master_location = this_branch.get_bound_location()
93
 
        if master_location is not None:
94
 
            return master_location
95
 
        # If not, use a local sibling
96
 
        return this_branch.base
 
89
        target = control_dir.get_branch_reference()
97
90
    except errors.NotBranchError:
98
 
        format = control_dir.find_branch_format()
99
 
        if getattr(format, 'get_reference', None) is not None:
100
 
            return format.get_reference(control_dir)
101
 
        else:
102
 
            return control_dir.root_transport.base
 
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
103
102
 
104
103
 
105
104
def _is_colocated(control_dir, possible_transports=None):
106
105
    """Check if the branch in control_dir is colocated.
107
106
 
108
107
    :param control_dir: Control directory
109
 
    :return: Boolean indicating whether 
 
108
    :return: Tuple with boolean indicating whether the branch is colocated
 
109
        and the full URL to the actual branch
110
110
    """
111
111
    # This path is meant to be relative to the existing branch
112
112
    this_url = _get_branch_location(control_dir,
132
132
def lookup_new_sibling_branch(control_dir, location, possible_transports=None):
133
133
    """Lookup the location for a new sibling branch.
134
134
 
135
 
    :param control_dir: Control directory relative to which to look up
136
 
        the name.
 
135
    :param control_dir: Control directory to find sibling branches from
137
136
    :param location: Name of the new branch
138
137
    :return: Full location to the new branch
139
138
    """
150
149
 
151
150
 
152
151
def open_sibling_branch(control_dir, location, possible_transports=None):
153
 
    """Open a branch, possibly a sibling.
 
152
    """Open a branch, possibly a sibling of another.
154
153
 
155
154
    :param control_dir: Control directory relative to which to lookup the
156
155
        location.
189
188
        possible_transports=possible_transports)
190
189
 
191
190
 
192
 
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
193
 
def tree_files(file_list, default_branch=u'.', canonicalize=True,
194
 
    apply_view=True):
195
 
    return internal_tree_files(file_list, default_branch, canonicalize,
196
 
        apply_view)
 
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
197
221
 
198
222
 
199
223
def tree_files_for_add(file_list):
261
285
    return rev_tree
262
286
 
263
287
 
264
 
# XXX: Bad function name; should possibly also be a class method of
265
 
# WorkingTree rather than a function.
266
 
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
267
 
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
268
 
    apply_view=True):
269
 
    """Convert command-line paths to a WorkingTree and relative paths.
270
 
 
271
 
    Deprecated: use WorkingTree.open_containing_paths instead.
272
 
 
273
 
    This is typically used for command-line processors that take one or
274
 
    more filenames, and infer the workingtree that contains them.
275
 
 
276
 
    The filenames given are not required to exist.
277
 
 
278
 
    :param file_list: Filenames to convert.
279
 
 
280
 
    :param default_branch: Fallback tree path to use if file_list is empty or
281
 
        None.
282
 
 
283
 
    :param apply_view: if True and a view is set, apply it or check that
284
 
        specified files are within it
285
 
 
286
 
    :return: workingtree, [relative_paths]
287
 
    """
288
 
    return WorkingTree.open_containing_paths(
289
 
        file_list, default_directory='.',
290
 
        canonicalize=True,
291
 
        apply_view=True)
292
 
 
293
 
 
294
288
def _get_view_info_for_change_reporter(tree):
295
289
    """Get the view information from a tree for change reporting."""
296
290
    view_info = None
374
368
    This will produce the same results as calling 'bzr diff --summarize'.
375
369
    """
376
370
 
377
 
    # TODO: --no-recurse, --recurse options
 
371
    # TODO: --no-recurse/-N, --recurse options
378
372
 
379
373
    takes_args = ['file*']
380
374
    takes_options = ['show-ids', 'revision', 'change', 'verbose',
691
685
            if revision:
692
686
                if len(revision) != 1:
693
687
                    raise errors.BzrCommandError(gettext(
694
 
                        "Tags can only be placed on a single revision, "
695
 
                        "not on a range"))
 
688
                        "Revision numbers only make sense for single "
 
689
                        "revisions, not ranges"))
696
690
                revid = revision[0].as_revision_id(b)
697
691
            else:
698
692
                revid = b.last_revision()
809
803
    takes_args = ['file*']
810
804
    takes_options = [
811
805
        Option('no-recurse',
812
 
               help="Don't recursively add the contents of directories."),
 
806
               help="Don't recursively add the contents of directories.",
 
807
               short_name='N'),
813
808
        Option('dry-run',
814
809
               help="Show what would be done, but don't actually do anything."),
815
810
        'verbose',
1158
1153
                 "the master branch."
1159
1154
            ),
1160
1155
        Option('show-base',
1161
 
            help="Show base revision text in conflicts.")
 
1156
            help="Show base revision text in conflicts."),
 
1157
        Option('overwrite-tags',
 
1158
            help="Overwrite tags only."),
1162
1159
        ]
1163
1160
    takes_args = ['location?']
1164
1161
    encoding_type = 'replace'
1166
1163
    def run(self, location=None, remember=None, overwrite=False,
1167
1164
            revision=None, verbose=False,
1168
1165
            directory=None, local=False,
1169
 
            show_base=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 = []
1170
1174
        # FIXME: too much stuff is in the command class
1171
1175
        revision_id = None
1172
1176
        mergeable = None
1180
1184
            tree_to = None
1181
1185
            branch_to = Branch.open_containing(directory)[0]
1182
1186
            self.add_cleanup(branch_to.lock_write().unlock)
1183
 
 
1184
 
        if tree_to is None and show_base:
1185
 
            raise errors.BzrCommandError(gettext("Need working tree for --show-base."))
 
1187
            if show_base:
 
1188
                warning(gettext("No working tree, ignoring --show-base"))
1186
1189
 
1187
1190
        if local and not branch_to.get_bound_location():
1188
1191
            raise errors.LocalRequiresBoundBranch()
1310
1313
        Option('no-tree',
1311
1314
               help="Don't populate the working tree, even for protocols"
1312
1315
               " that support it."),
 
1316
        Option('overwrite-tags',
 
1317
              help="Overwrite tags only."),
1313
1318
        ]
1314
1319
    takes_args = ['location?']
1315
1320
    encoding_type = 'replace'
1317
1322
    def run(self, location=None, remember=None, overwrite=False,
1318
1323
        create_prefix=False, verbose=False, revision=None,
1319
1324
        use_existing_dir=False, directory=None, stacked_on=None,
1320
 
        stacked=False, strict=None, no_tree=False):
 
1325
        stacked=False, strict=None, no_tree=False,
 
1326
        overwrite_tags=False):
1321
1327
        from bzrlib.push import _show_push_branch
1322
1328
 
 
1329
        if overwrite:
 
1330
            overwrite = ["history", "tags"]
 
1331
        elif overwrite_tags:
 
1332
            overwrite = ["tags"]
 
1333
        else:
 
1334
            overwrite = []
 
1335
 
1323
1336
        if directory is None:
1324
1337
            directory = '.'
1325
1338
        # Get the source branch
1559
1572
                active_branch = dir.open_branch(name="")
1560
1573
            except errors.NotBranchError:
1561
1574
                active_branch = None
1562
 
            branches = dir.get_branches()
1563
1575
            names = {}
1564
 
            for name, branch in branches.iteritems():
 
1576
            for name, branch in iter_sibling_branches(dir):
1565
1577
                if name == "":
1566
1578
                    continue
1567
1579
                active = (active_branch is not None and
1602
1614
    code.)
1603
1615
    """
1604
1616
 
1605
 
    _see_also = ['checkouts', 'branch']
 
1617
    _see_also = ['checkouts', 'branch', 'working-trees', 'remove-tree']
1606
1618
    takes_args = ['branch_location?', 'to_location?']
1607
1619
    takes_options = ['revision',
1608
1620
                     Option('lightweight',
1846
1858
 
1847
1859
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
1848
1860
    delete them if they can easily be recovered using revert otherwise they
1849
 
    will be backed up (adding an extention of the form .~#~). If no options or
 
1861
    will be backed up (adding an extension of the form .~#~). If no options or
1850
1862
    parameters are given Bazaar will scan for files that are being tracked by
1851
1863
    Bazaar but missing in your tree and stop tracking them for you.
1852
1864
    """
1858
1870
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1859
1871
            safe='Backup changed files (default).',
1860
1872
            keep='Delete from bzr but leave the working copy.',
1861
 
            no_backup='Don\'t backup changed files.',
1862
 
            force='Delete all the specified files, even if they can not be '
1863
 
                'recovered and even if they are non-empty directories. '
1864
 
                '(deprecated, use no-backup)')]
 
1873
            no_backup='Don\'t backup changed files.'),
 
1874
        ]
1865
1875
    aliases = ['rm', 'del']
1866
1876
    encoding_type = 'replace'
1867
1877
 
1868
1878
    def run(self, file_list, verbose=False, new=False,
1869
1879
        file_deletion_strategy='safe'):
1870
 
        if file_deletion_strategy == 'force':
1871
 
            note(gettext("(The --force option is deprecated, rather use --no-backup "
1872
 
                "in future.)"))
1873
 
            file_deletion_strategy = 'no-backup'
1874
1880
 
1875
1881
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1876
1882
 
2060
2066
         RegistryOption('format',
2061
2067
                help='Specify a format for this branch. '
2062
2068
                'See "help formats".',
2063
 
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
2069
                lazy_registry=('bzrlib.controldir', 'format_registry'),
2064
2070
                converter=lambda name: controldir.format_registry.make_bzrdir(name),
2065
2071
                value_switches=True,
2066
2072
                title="Branch format",
2322
2328
            help='Diff format to use.',
2323
2329
            lazy_registry=('bzrlib.diff', 'format_registry'),
2324
2330
            title='Diff format'),
 
2331
        Option('context',
 
2332
            help='How many lines of context to show.',
 
2333
            type=int,
 
2334
            ),
2325
2335
        ]
2326
2336
    aliases = ['di', 'dif']
2327
2337
    encoding_type = 'exact'
2328
2338
 
2329
2339
    @display_command
2330
2340
    def run(self, revision=None, file_list=None, diff_options=None,
2331
 
            prefix=None, old=None, new=None, using=None, format=None):
 
2341
            prefix=None, old=None, new=None, using=None, format=None, 
 
2342
            context=None):
2332
2343
        from bzrlib.diff import (get_trees_and_branches_to_diff_locked,
2333
2344
            show_diff_trees)
2334
2345
 
2367
2378
                               old_label=old_label, new_label=new_label,
2368
2379
                               extra_trees=extra_trees,
2369
2380
                               path_encoding=path_encoding,
2370
 
                               using=using,
 
2381
                               using=using, context=context,
2371
2382
                               format_cls=format)
2372
2383
 
2373
2384
 
4734
4745
 
4735
4746
 
4736
4747
class cmd_revert(Command):
4737
 
    __doc__ = """Revert files to a previous revision.
 
4748
    __doc__ = """\
 
4749
    Set files in the working tree back to the contents of a previous revision.
4738
4750
 
4739
4751
    Giving a list of files will revert only those files.  Otherwise, all files
4740
4752
    will be reverted.  If the revision is not specified with '--revision', the
4741
 
    last committed revision is used.
 
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.
4742
4756
 
4743
4757
    To remove only some changes, without reverting to a prior version, use
4744
4758
    merge instead.  For example, "merge . -r -2..-3" (don't forget the ".")
4745
4759
    will remove the changes introduced by the second last commit (-2), without
4746
4760
    affecting the changes introduced by the last commit (-1).  To remove
4747
4761
    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.
4748
4765
 
4749
 
    By default, any files that have been manually changed will be backed up
4750
 
    first.  (Files changed only by merge are not backed up.)  Backup files have
4751
 
    '.~#~' appended to their name, where # is a number.
 
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.
4752
4770
 
4753
4771
    When you provide files, you can use their current pathname or the pathname
4754
4772
    from the target revision.  So you can use revert to "undelete" a file by
5001
5019
                             "You have %d extra revisions:\n", 
5002
5020
                             len(local_extra)) %
5003
5021
                len(local_extra))
 
5022
            rev_tag_dict = {}
 
5023
            if local_branch.supports_tags():
 
5024
                rev_tag_dict = local_branch.tags.get_reverse_tag_dict()
5004
5025
            for revision in iter_log_revisions(local_extra,
5005
5026
                                local_branch.repository,
5006
 
                                verbose):
 
5027
                                verbose,
 
5028
                                rev_tag_dict):
5007
5029
                lf.log_revision(revision)
5008
5030
            printed_local = True
5009
5031
            status_code = 1
5017
5039
                             "You are missing %d revisions:\n",
5018
5040
                             len(remote_extra)) %
5019
5041
                len(remote_extra))
 
5042
            if remote_branch.supports_tags():
 
5043
                rev_tag_dict = remote_branch.tags.get_reverse_tag_dict()
5020
5044
            for revision in iter_log_revisions(remote_extra,
5021
5045
                                remote_branch.repository,
5022
 
                                verbose):
 
5046
                                verbose,
 
5047
                                rev_tag_dict):
5023
5048
                lf.log_revision(revision)
5024
5049
            status_code = 1
5025
5050
 
5115
5140
            Option('strict',
5116
5141
                   help='Produce a strict-format testament.')]
5117
5142
    takes_args = ['branch?']
 
5143
    encoding_type = 'exact'
5118
5144
    @display_command
5119
5145
    def run(self, branch=u'.', revision=None, long=False, strict=False):
5120
5146
        from bzrlib.testament import Testament, StrictTestament
5133
5159
            rev_id = revision[0].as_revision_id(b)
5134
5160
        t = testament_class.from_revision(b.repository, rev_id)
5135
5161
        if long:
5136
 
            sys.stdout.writelines(t.as_text_lines())
 
5162
            self.outf.writelines(t.as_text_lines())
5137
5163
        else:
5138
 
            sys.stdout.write(t.as_short_text())
 
5164
            self.outf.write(t.as_short_text())
5139
5165
 
5140
5166
 
5141
5167
class cmd_annotate(Command):
5497
5523
               help="Protocol to serve.",
5498
5524
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
5499
5525
               value_switches=True),
 
5526
        Option('listen',
 
5527
               help='Listen for connections on nominated address.', type=str),
5500
5528
        Option('port',
5501
 
               help='Listen for connections on nominated port of the form '
5502
 
                    '[hostname:]portnumber.  Passing 0 as the port number will '
5503
 
                    'result in a dynamically allocated port.  The default port '
5504
 
                    'depends on the protocol.',
5505
 
               type=str),
 
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),
5506
5533
        custom_help('directory',
5507
5534
               help='Serve contents of this directory.'),
5508
5535
        Option('allow-writes',
5518
5545
               help='Override the default idle client timeout (5min).'),
5519
5546
        ]
5520
5547
 
5521
 
    def get_host_and_port(self, port):
5522
 
        """Return the host and port to run the smart server on.
5523
 
 
5524
 
        If 'port' is None, None will be returned for the host and port.
5525
 
 
5526
 
        If 'port' has a colon in it, the string before the colon will be
5527
 
        interpreted as the host.
5528
 
 
5529
 
        :param port: A string of the port to run the server on.
5530
 
        :return: A tuple of (host, port), where 'host' is a host name or IP,
5531
 
            and port is an integer TCP/IP port.
5532
 
        """
5533
 
        host = None
5534
 
        if port is not None:
5535
 
            if ':' in port:
5536
 
                host, port = port.split(':')
5537
 
            port = int(port)
5538
 
        return host, port
5539
 
 
5540
 
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
5541
 
            protocol=None, client_timeout=None):
 
5548
    def run(self, listen=None, port=None, inet=False, directory=None,
 
5549
            allow_writes=False, protocol=None, client_timeout=None):
5542
5550
        from bzrlib import transport
5543
5551
        if directory is None:
5544
5552
            directory = os.getcwd()
5545
5553
        if protocol is None:
5546
5554
            protocol = transport.transport_server_registry.get()
5547
 
        host, port = self.get_host_and_port(port)
5548
5555
        url = transport.location_to_url(directory)
5549
5556
        if not allow_writes:
5550
5557
            url = 'readonly+' + url
5551
5558
        t = transport.get_transport_from_url(url)
5552
 
        try:
5553
 
            protocol(t, host, port, inet, client_timeout)
5554
 
        except TypeError, e:
5555
 
            # We use symbol_versioning.deprecated_in just so that people
5556
 
            # grepping can find it here.
5557
 
            # symbol_versioning.deprecated_in((2, 5, 0))
5558
 
            symbol_versioning.warn(
5559
 
                'Got TypeError(%s)\ntrying to call protocol: %s.%s\n'
5560
 
                'Most likely it needs to be updated to support a'
5561
 
                ' "timeout" parameter (added in bzr 2.5.0)'
5562
 
                % (e, protocol.__module__, protocol),
5563
 
                DeprecationWarning)
5564
 
            protocol(t, host, port, inet)
 
5559
        protocol(t, listen, port, inet, client_timeout)
5565
5560
 
5566
5561
 
5567
5562
class cmd_join(Command):
6237
6232
                     Option('create-branch', short_name='b',
6238
6233
                        help='Create the target branch from this one before'
6239
6234
                             ' switching to it.'),
 
6235
                     Option('store',
 
6236
                        help='Store and restore uncommitted changes in the'
 
6237
                             ' branch.'),
6240
6238
                    ]
6241
6239
 
6242
6240
    def run(self, to_location=None, force=False, create_branch=False,
6243
 
            revision=None, directory=u'.'):
 
6241
            revision=None, directory=u'.', store=False):
6244
6242
        from bzrlib import switch
6245
6243
        tree_location = directory
6246
6244
        revision = _get_one_revision('switch', revision)
6277
6275
                    possible_transports=possible_transports)
6278
6276
        if revision is not None:
6279
6277
            revision = revision.as_revision_id(to_branch)
6280
 
        switch.switch(control_dir, to_branch, force, revision_id=revision)
 
6278
        switch.switch(control_dir, to_branch, force, revision_id=revision,
 
6279
                      store_uncommitted=store)
6281
6280
        if had_explicit_nick:
6282
6281
            branch = control_dir.open_branch() #get the new branch!
6283
6282
            branch.nick = to_branch.nick
6477
6476
 
6478
6477
    takes_args = ["location?"]
6479
6478
 
6480
 
    takes_options = ['directory']
 
6479
    takes_options = ['directory',
 
6480
        Option('force', help='Remove branch even if it is the active branch.')]
6481
6481
 
6482
6482
    aliases = ["rmbranch"]
6483
6483
 
6484
 
    def run(self, directory=None, location=None):
 
6484
    def run(self, directory=None, location=None, force=False):
6485
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."))
6486
6495
        br.bzrdir.destroy_branch(br.name)
6487
6496
 
6488
6497
 
6718
6727
        ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
6719
6728
        ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
6720
6729
        ('cmd_conflicts', [], 'bzrlib.conflicts'),
 
6730
        ('cmd_ping', [], 'bzrlib.smart.ping'),
6721
6731
        ('cmd_sign_my_commits', [], 'bzrlib.commit_signature_commands'),
6722
 
        ('cmd_verify_signatures', [],
6723
 
                                        'bzrlib.commit_signature_commands'),
 
6732
        ('cmd_verify_signatures', [], 'bzrlib.commit_signature_commands'),
6724
6733
        ('cmd_test_script', [], 'bzrlib.cmd_test_script'),
6725
6734
        ]:
6726
6735
        builtin_command_registry.register_lazy(name, aliases, module_name)