/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

merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""builtin bzr commands"""
18
18
 
19
19
import os
20
 
from StringIO import StringIO
21
20
 
22
21
from bzrlib.lazy_import import lazy_import
23
22
lazy_import(globals(), """
24
23
import codecs
25
 
import errno
 
24
import cStringIO
26
25
import sys
27
 
import tempfile
28
26
import time
29
27
 
30
28
import bzrlib
31
29
from bzrlib import (
32
 
    branch,
33
30
    bugtracker,
34
31
    bundle,
 
32
    btree_index,
35
33
    bzrdir,
36
34
    delta,
37
35
    config,
38
36
    errors,
39
37
    globbing,
40
 
    ignores,
 
38
    hooks,
41
39
    log,
42
40
    merge as _mod_merge,
43
41
    merge_directive,
44
42
    osutils,
45
 
    registry,
46
 
    repository,
 
43
    reconfigure,
 
44
    rename_map,
47
45
    revision as _mod_revision,
48
 
    revisionspec,
49
46
    symbol_versioning,
50
47
    transport,
51
48
    tree as _mod_tree,
52
49
    ui,
53
50
    urlutils,
 
51
    views,
54
52
    )
55
53
from bzrlib.branch import Branch
56
54
from bzrlib.conflicts import ConflictList
57
 
from bzrlib.revisionspec import RevisionSpec
 
55
from bzrlib.revisionspec import RevisionSpec, RevisionInfo
58
56
from bzrlib.smtp_connection import SMTPConnection
59
57
from bzrlib.workingtree import WorkingTree
60
58
""")
61
59
 
62
60
from bzrlib.commands import Command, display_command
63
 
from bzrlib.option import ListOption, Option, RegistryOption
64
 
from bzrlib.progress import DummyProgress, ProgressPhase
65
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
66
 
 
67
 
 
68
 
def tree_files(file_list, default_branch=u'.'):
 
61
from bzrlib.option import (
 
62
    ListOption,
 
63
    Option,
 
64
    RegistryOption,
 
65
    custom_help,
 
66
    _parse_revision_str,
 
67
    )
 
68
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
 
69
 
 
70
 
 
71
def tree_files(file_list, default_branch=u'.', canonicalize=True,
 
72
    apply_view=True):
69
73
    try:
70
 
        return internal_tree_files(file_list, default_branch)
 
74
        return internal_tree_files(file_list, default_branch, canonicalize,
 
75
            apply_view)
71
76
    except errors.FileInWrongBranch, e:
72
77
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
73
78
                                     (e.path, file_list[0]))
74
79
 
75
80
 
 
81
def tree_files_for_add(file_list):
 
82
    """
 
83
    Return a tree and list of absolute paths from a file list.
 
84
 
 
85
    Similar to tree_files, but add handles files a bit differently, so it a
 
86
    custom implementation.  In particular, MutableTreeTree.smart_add expects
 
87
    absolute paths, which it immediately converts to relative paths.
 
88
    """
 
89
    # FIXME Would be nice to just return the relative paths like
 
90
    # internal_tree_files does, but there are a large number of unit tests
 
91
    # that assume the current interface to mutabletree.smart_add
 
92
    if file_list:
 
93
        tree, relpath = WorkingTree.open_containing(file_list[0])
 
94
        if tree.supports_views():
 
95
            view_files = tree.views.lookup_view()
 
96
            if view_files:
 
97
                for filename in file_list:
 
98
                    if not osutils.is_inside_any(view_files, filename):
 
99
                        raise errors.FileOutsideView(filename, view_files)
 
100
        file_list = file_list[:]
 
101
        file_list[0] = tree.abspath(relpath)
 
102
    else:
 
103
        tree = WorkingTree.open_containing(u'.')[0]
 
104
        if tree.supports_views():
 
105
            view_files = tree.views.lookup_view()
 
106
            if view_files:
 
107
                file_list = view_files
 
108
                view_str = views.view_display_str(view_files)
 
109
                note("Ignoring files outside view. View is %s" % view_str)
 
110
    return tree, file_list
 
111
 
 
112
 
 
113
def _get_one_revision(command_name, revisions):
 
114
    if revisions is None:
 
115
        return None
 
116
    if len(revisions) != 1:
 
117
        raise errors.BzrCommandError(
 
118
            'bzr %s --revision takes exactly one revision identifier' % (
 
119
                command_name,))
 
120
    return revisions[0]
 
121
 
 
122
 
 
123
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
 
124
    if branch is None:
 
125
        branch = tree.branch
 
126
    if revisions is None:
 
127
        if tree is not None:
 
128
            rev_tree = tree.basis_tree()
 
129
        else:
 
130
            rev_tree = branch.basis_tree()
 
131
    else:
 
132
        revision = _get_one_revision(command_name, revisions)
 
133
        rev_tree = revision.as_tree(branch)
 
134
    return rev_tree
 
135
 
 
136
 
76
137
# XXX: Bad function name; should possibly also be a class method of
77
138
# WorkingTree rather than a function.
78
 
def internal_tree_files(file_list, default_branch=u'.'):
 
139
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
 
140
    apply_view=True):
79
141
    """Convert command-line paths to a WorkingTree and relative paths.
80
142
 
81
143
    This is typically used for command-line processors that take one or
83
145
 
84
146
    The filenames given are not required to exist.
85
147
 
86
 
    :param file_list: Filenames to convert.  
 
148
    :param file_list: Filenames to convert.
87
149
 
88
150
    :param default_branch: Fallback tree path to use if file_list is empty or
89
151
        None.
90
152
 
 
153
    :param apply_view: if True and a view is set, apply it or check that
 
154
        specified files are within it
 
155
 
91
156
    :return: workingtree, [relative_paths]
92
157
    """
93
158
    if file_list is None or len(file_list) == 0:
94
 
        return WorkingTree.open_containing(default_branch)[0], file_list
 
159
        tree = WorkingTree.open_containing(default_branch)[0]
 
160
        if tree.supports_views() and apply_view:
 
161
            view_files = tree.views.lookup_view()
 
162
            if view_files:
 
163
                file_list = view_files
 
164
                view_str = views.view_display_str(view_files)
 
165
                note("Ignoring files outside view. View is %s" % view_str)
 
166
        return tree, file_list
95
167
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
 
168
    return tree, safe_relpath_files(tree, file_list, canonicalize,
 
169
        apply_view=apply_view)
 
170
 
 
171
 
 
172
def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
 
173
    """Convert file_list into a list of relpaths in tree.
 
174
 
 
175
    :param tree: A tree to operate on.
 
176
    :param file_list: A list of user provided paths or None.
 
177
    :param apply_view: if True and a view is set, apply it or check that
 
178
        specified files are within it
 
179
    :return: A list of relative paths.
 
180
    :raises errors.PathNotChild: When a provided path is in a different tree
 
181
        than tree.
 
182
    """
 
183
    if file_list is None:
 
184
        return None
 
185
    if tree.supports_views() and apply_view:
 
186
        view_files = tree.views.lookup_view()
 
187
    else:
 
188
        view_files = []
96
189
    new_list = []
 
190
    # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
 
191
    # doesn't - fix that up here before we enter the loop.
 
192
    if canonicalize:
 
193
        fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
 
194
    else:
 
195
        fixer = tree.relpath
97
196
    for filename in file_list:
98
197
        try:
99
 
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
 
198
            relpath = fixer(osutils.dereference_path(filename))
 
199
            if  view_files and not osutils.is_inside_any(view_files, relpath):
 
200
                raise errors.FileOutsideView(filename, view_files)
 
201
            new_list.append(relpath)
100
202
        except errors.PathNotChild:
101
203
            raise errors.FileInWrongBranch(tree.branch, filename)
102
 
    return tree, new_list
103
 
 
104
 
 
105
 
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
106
 
def get_format_type(typestring):
107
 
    """Parse and return a format specifier."""
108
 
    # Have to use BzrDirMetaFormat1 directly, so that
109
 
    # RepositoryFormat.set_default_format works
110
 
    if typestring == "default":
111
 
        return bzrdir.BzrDirMetaFormat1()
 
204
    return new_list
 
205
 
 
206
 
 
207
def _get_view_info_for_change_reporter(tree):
 
208
    """Get the view information from a tree for change reporting."""
 
209
    view_info = None
112
210
    try:
113
 
        return bzrdir.format_registry.make_bzrdir(typestring)
114
 
    except KeyError:
115
 
        msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
116
 
        raise errors.BzrCommandError(msg)
 
211
        current_view = tree.views.get_view_info()[0]
 
212
        if current_view is not None:
 
213
            view_info = (current_view, tree.views.lookup_view())
 
214
    except errors.ViewsNotSupported:
 
215
        pass
 
216
    return view_info
117
217
 
118
218
 
119
219
# TODO: Make sure no commands unconditionally use the working directory as a
151
251
 
152
252
    To see ignored files use 'bzr ignored'.  For details on the
153
253
    changes to file texts, use 'bzr diff'.
154
 
    
155
 
    --short gives a status flags for each item, similar to the SVN's status
156
 
    command.
 
254
 
 
255
    Note that --short or -S gives status flags for each item, similar
 
256
    to Subversion's status command. To get output similar to svn -q,
 
257
    use bzr status -SV.
157
258
 
158
259
    If no arguments are specified, the status of the entire working
159
260
    directory is shown.  Otherwise, only the status of the specified
160
261
    files or directories is reported.  If a directory is given, status
161
262
    is reported for everything inside that directory.
162
263
 
 
264
    Before merges are committed, the pending merge tip revisions are
 
265
    shown. To see all pending merge revisions, use the -v option.
 
266
    To skip the display of pending merge information altogether, use
 
267
    the no-pending option or specify a file/directory.
 
268
 
163
269
    If a revision argument is given, the status is calculated against
164
270
    that revision, or between two revisions if two are provided.
165
271
    """
166
 
    
 
272
 
167
273
    # TODO: --no-recurse, --recurse options
168
 
    
 
274
 
169
275
    takes_args = ['file*']
170
 
    takes_options = ['show-ids', 'revision',
171
 
                     Option('short', help='Give short SVN-style status lines.'),
172
 
                     Option('versioned', help='Only show versioned files.')]
 
276
    takes_options = ['show-ids', 'revision', 'change', 'verbose',
 
277
                     Option('short', help='Use short status indicators.',
 
278
                            short_name='S'),
 
279
                     Option('versioned', help='Only show versioned files.',
 
280
                            short_name='V'),
 
281
                     Option('no-pending', help='Don\'t show pending merges.',
 
282
                           ),
 
283
                     ]
173
284
    aliases = ['st', 'stat']
174
285
 
175
286
    encoding_type = 'replace'
176
287
    _see_also = ['diff', 'revert', 'status-flags']
177
 
    
 
288
 
178
289
    @display_command
179
290
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
180
 
            versioned=False):
 
291
            versioned=False, no_pending=False, verbose=False):
181
292
        from bzrlib.status import show_tree_status
182
293
 
183
 
        tree, file_list = tree_files(file_list)
184
 
            
 
294
        if revision and len(revision) > 2:
 
295
            raise errors.BzrCommandError('bzr status --revision takes exactly'
 
296
                                         ' one or two revision specifiers')
 
297
 
 
298
        tree, relfile_list = tree_files(file_list)
 
299
        # Avoid asking for specific files when that is not needed.
 
300
        if relfile_list == ['']:
 
301
            relfile_list = None
 
302
            # Don't disable pending merges for full trees other than '.'.
 
303
            if file_list == ['.']:
 
304
                no_pending = True
 
305
        # A specific path within a tree was given.
 
306
        elif relfile_list is not None:
 
307
            no_pending = True
185
308
        show_tree_status(tree, show_ids=show_ids,
186
 
                         specific_files=file_list, revision=revision,
187
 
                         to_file=self.outf, short=short, versioned=versioned)
 
309
                         specific_files=relfile_list, revision=revision,
 
310
                         to_file=self.outf, short=short, versioned=versioned,
 
311
                         show_pending=(not no_pending), verbose=verbose)
188
312
 
189
313
 
190
314
class cmd_cat_revision(Command):
191
315
    """Write out metadata for a revision.
192
 
    
 
316
 
193
317
    The revision to print can either be specified by a specific
194
318
    revision identifier, or you can use --revision.
195
319
    """
199
323
    takes_options = ['revision']
200
324
    # cat-revision is more for frontends so should be exact
201
325
    encoding = 'strict'
202
 
    
 
326
 
203
327
    @display_command
204
328
    def run(self, revision_id=None, revision=None):
205
 
 
206
 
        revision_id = osutils.safe_revision_id(revision_id, warn=False)
207
329
        if revision_id is not None and revision is not None:
208
330
            raise errors.BzrCommandError('You can only supply one of'
209
331
                                         ' revision_id or --revision')
214
336
 
215
337
        # TODO: jam 20060112 should cat-revision always output utf-8?
216
338
        if revision_id is not None:
217
 
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
 
339
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
 
340
            try:
 
341
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
 
342
            except errors.NoSuchRevision:
 
343
                msg = "The repository %s contains no revision %s." % (b.repository.base,
 
344
                    revision_id)
 
345
                raise errors.BzrCommandError(msg)
218
346
        elif revision is not None:
219
347
            for rev in revision:
220
348
                if rev is None:
221
349
                    raise errors.BzrCommandError('You cannot specify a NULL'
222
350
                                                 ' revision.')
223
 
                revno, rev_id = rev.in_history(b)
 
351
                rev_id = rev.as_revision_id(b)
224
352
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
225
 
    
 
353
 
 
354
 
 
355
class cmd_dump_btree(Command):
 
356
    """Dump the contents of a btree index file to stdout.
 
357
 
 
358
    PATH is a btree index file, it can be any URL. This includes things like
 
359
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
 
360
 
 
361
    By default, the tuples stored in the index file will be displayed. With
 
362
    --raw, we will uncompress the pages, but otherwise display the raw bytes
 
363
    stored in the index.
 
364
    """
 
365
 
 
366
    # TODO: Do we want to dump the internal nodes as well?
 
367
    # TODO: It would be nice to be able to dump the un-parsed information,
 
368
    #       rather than only going through iter_all_entries. However, this is
 
369
    #       good enough for a start
 
370
    hidden = True
 
371
    encoding_type = 'exact'
 
372
    takes_args = ['path']
 
373
    takes_options = [Option('raw', help='Write the uncompressed bytes out,'
 
374
                                        ' rather than the parsed tuples.'),
 
375
                    ]
 
376
 
 
377
    def run(self, path, raw=False):
 
378
        dirname, basename = osutils.split(path)
 
379
        t = transport.get_transport(dirname)
 
380
        if raw:
 
381
            self._dump_raw_bytes(t, basename)
 
382
        else:
 
383
            self._dump_entries(t, basename)
 
384
 
 
385
    def _get_index_and_bytes(self, trans, basename):
 
386
        """Create a BTreeGraphIndex and raw bytes."""
 
387
        bt = btree_index.BTreeGraphIndex(trans, basename, None)
 
388
        bytes = trans.get_bytes(basename)
 
389
        bt._file = cStringIO.StringIO(bytes)
 
390
        bt._size = len(bytes)
 
391
        return bt, bytes
 
392
 
 
393
    def _dump_raw_bytes(self, trans, basename):
 
394
        import zlib
 
395
 
 
396
        # We need to parse at least the root node.
 
397
        # This is because the first page of every row starts with an
 
398
        # uncompressed header.
 
399
        bt, bytes = self._get_index_and_bytes(trans, basename)
 
400
        for page_idx, page_start in enumerate(xrange(0, len(bytes),
 
401
                                                     btree_index._PAGE_SIZE)):
 
402
            page_end = min(page_start + btree_index._PAGE_SIZE, len(bytes))
 
403
            page_bytes = bytes[page_start:page_end]
 
404
            if page_idx == 0:
 
405
                self.outf.write('Root node:\n')
 
406
                header_end, data = bt._parse_header_from_bytes(page_bytes)
 
407
                self.outf.write(page_bytes[:header_end])
 
408
                page_bytes = data
 
409
            self.outf.write('\nPage %d\n' % (page_idx,))
 
410
            decomp_bytes = zlib.decompress(page_bytes)
 
411
            self.outf.write(decomp_bytes)
 
412
            self.outf.write('\n')
 
413
 
 
414
    def _dump_entries(self, trans, basename):
 
415
        try:
 
416
            st = trans.stat(basename)
 
417
        except errors.TransportNotPossible:
 
418
            # We can't stat, so we'll fake it because we have to do the 'get()'
 
419
            # anyway.
 
420
            bt, _ = self._get_index_and_bytes(trans, basename)
 
421
        else:
 
422
            bt = btree_index.BTreeGraphIndex(trans, basename, st.st_size)
 
423
        for node in bt.iter_all_entries():
 
424
            # Node is made up of:
 
425
            # (index, key, value, [references])
 
426
            self.outf.write('%s\n' % (node[1:],))
 
427
 
226
428
 
227
429
class cmd_remove_tree(Command):
228
430
    """Remove the working tree from a given branch/checkout.
233
435
    To re-create the working tree, use "bzr checkout".
234
436
    """
235
437
    _see_also = ['checkout', 'working-trees']
236
 
 
237
438
    takes_args = ['location?']
 
439
    takes_options = [
 
440
        Option('force',
 
441
               help='Remove the working tree even if it has '
 
442
                    'uncommitted changes.'),
 
443
        ]
238
444
 
239
 
    def run(self, location='.'):
 
445
    def run(self, location='.', force=False):
240
446
        d = bzrdir.BzrDir.open(location)
241
 
        
 
447
 
242
448
        try:
243
449
            working = d.open_workingtree()
244
450
        except errors.NoWorkingTree:
246
452
        except errors.NotLocalUrl:
247
453
            raise errors.BzrCommandError("You cannot remove the working tree of a "
248
454
                                         "remote path")
249
 
        
 
455
        if not force:
 
456
            changes = working.changes_from(working.basis_tree())
 
457
            if changes.has_changed():
 
458
                raise errors.UncommittedChanges(working)
 
459
 
250
460
        working_path = working.bzrdir.root_transport.base
251
461
        branch_path = working.branch.bzrdir.root_transport.base
252
462
        if working_path != branch_path:
253
463
            raise errors.BzrCommandError("You cannot remove the working tree from "
254
464
                                         "a lightweight checkout")
255
 
        
 
465
 
256
466
        d.destroy_workingtree()
257
 
        
 
467
 
258
468
 
259
469
class cmd_revno(Command):
260
470
    """Show current revision number.
276
486
    """
277
487
    hidden = True
278
488
    takes_args = ['revision_info*']
279
 
    takes_options = ['revision']
 
489
    takes_options = [
 
490
        'revision',
 
491
        Option('directory',
 
492
            help='Branch to examine, '
 
493
                 'rather than the one containing the working directory.',
 
494
            short_name='d',
 
495
            type=unicode,
 
496
            ),
 
497
        ]
280
498
 
281
499
    @display_command
282
 
    def run(self, revision=None, revision_info_list=[]):
 
500
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
283
501
 
284
502
        revs = []
285
503
        if revision is not None:
288
506
            for rev in revision_info_list:
289
507
                revs.append(RevisionSpec.from_string(rev))
290
508
 
291
 
        b = Branch.open_containing(u'.')[0]
 
509
        b = Branch.open_containing(directory)[0]
292
510
 
293
511
        if len(revs) == 0:
294
512
            revs.append(RevisionSpec.from_string('-1'))
295
513
 
296
514
        for rev in revs:
297
 
            revinfo = rev.in_history(b)
298
 
            if revinfo.revno is None:
 
515
            revision_id = rev.as_revision_id(b)
 
516
            try:
 
517
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
 
518
            except errors.NoSuchRevision:
299
519
                dotted_map = b.get_revision_id_to_revno_map()
300
 
                revno = '.'.join(str(i) for i in dotted_map[revinfo.rev_id])
301
 
                print '%s %s' % (revno, revinfo.rev_id)
302
 
            else:
303
 
                print '%4d %s' % (revinfo.revno, revinfo.rev_id)
304
 
 
305
 
    
 
520
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
 
521
            print '%s %s' % (revno, revision_id)
 
522
 
 
523
 
306
524
class cmd_add(Command):
307
525
    """Add specified files or directories.
308
526
 
326
544
    you should never need to explicitly add a directory, they'll just
327
545
    get added when you add a file in the directory.
328
546
 
329
 
    --dry-run will show which files would be added, but not actually 
 
547
    --dry-run will show which files would be added, but not actually
330
548
    add them.
331
549
 
332
550
    --file-ids-from will try to use the file ids from the supplied path.
375
593
            base_tree.lock_read()
376
594
        try:
377
595
            file_list = self._maybe_expand_globs(file_list)
378
 
            if file_list:
379
 
                tree = WorkingTree.open_containing(file_list[0])[0]
380
 
            else:
381
 
                tree = WorkingTree.open_containing(u'.')[0]
 
596
            tree, file_list = tree_files_for_add(file_list)
382
597
            added, ignored = tree.smart_add(file_list, not
383
598
                no_recurse, action=action, save=not dry_run)
384
599
        finally:
388
603
            if verbose:
389
604
                for glob in sorted(ignored.keys()):
390
605
                    for path in ignored[glob]:
391
 
                        self.outf.write("ignored %s matching \"%s\"\n" 
 
606
                        self.outf.write("ignored %s matching \"%s\"\n"
392
607
                                        % (path, glob))
393
608
            else:
394
609
                match_len = 0
421
636
 
422
637
    takes_args = ['filename']
423
638
    hidden = True
424
 
    
 
639
 
425
640
    @display_command
426
641
    def run(self, filename):
427
642
        # TODO: jam 20050106 Can relpath return a munged path if
457
672
        if kind and kind not in ['file', 'directory', 'symlink']:
458
673
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
459
674
 
 
675
        revision = _get_one_revision('inventory', revision)
460
676
        work_tree, file_list = tree_files(file_list)
461
677
        work_tree.lock_read()
462
678
        try:
463
679
            if revision is not None:
464
 
                if len(revision) > 1:
465
 
                    raise errors.BzrCommandError(
466
 
                        'bzr inventory --revision takes exactly one revision'
467
 
                        ' identifier')
468
 
                revision_id = revision[0].in_history(work_tree.branch).rev_id
469
 
                tree = work_tree.branch.repository.revision_tree(revision_id)
 
680
                tree = revision.as_tree(work_tree.branch)
470
681
 
471
682
                extra_trees = [work_tree]
472
683
                tree.lock_read()
522
733
    takes_args = ['names*']
523
734
    takes_options = [Option("after", help="Move only the bzr identifier"
524
735
        " of the file, because the file has already been moved."),
 
736
        Option('auto', help='Automatically guess renames.'),
 
737
        Option('dry-run', help='Avoid making changes when guessing renames.'),
525
738
        ]
526
739
    aliases = ['move', 'rename']
527
740
    encoding_type = 'replace'
528
741
 
529
 
    def run(self, names_list, after=False):
 
742
    def run(self, names_list, after=False, auto=False, dry_run=False):
 
743
        if auto:
 
744
            return self.run_auto(names_list, after, dry_run)
 
745
        elif dry_run:
 
746
            raise errors.BzrCommandError('--dry-run requires --auto.')
530
747
        if names_list is None:
531
748
            names_list = []
532
 
 
533
749
        if len(names_list) < 2:
534
750
            raise errors.BzrCommandError("missing file argument")
535
 
        tree, rel_names = tree_files(names_list)
536
 
        
537
 
        if os.path.isdir(names_list[-1]):
 
751
        tree, rel_names = tree_files(names_list, canonicalize=False)
 
752
        tree.lock_write()
 
753
        try:
 
754
            self._run(tree, names_list, rel_names, after)
 
755
        finally:
 
756
            tree.unlock()
 
757
 
 
758
    def run_auto(self, names_list, after, dry_run):
 
759
        if names_list is not None and len(names_list) > 1:
 
760
            raise errors.BzrCommandError('Only one path may be specified to'
 
761
                                         ' --auto.')
 
762
        if after:
 
763
            raise errors.BzrCommandError('--after cannot be specified with'
 
764
                                         ' --auto.')
 
765
        work_tree, file_list = tree_files(names_list, default_branch='.')
 
766
        work_tree.lock_write()
 
767
        try:
 
768
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
 
769
        finally:
 
770
            work_tree.unlock()
 
771
 
 
772
    def _run(self, tree, names_list, rel_names, after):
 
773
        into_existing = osutils.isdir(names_list[-1])
 
774
        if into_existing and len(names_list) == 2:
 
775
            # special cases:
 
776
            # a. case-insensitive filesystem and change case of dir
 
777
            # b. move directory after the fact (if the source used to be
 
778
            #    a directory, but now doesn't exist in the working tree
 
779
            #    and the target is an existing directory, just rename it)
 
780
            if (not tree.case_sensitive
 
781
                and rel_names[0].lower() == rel_names[1].lower()):
 
782
                into_existing = False
 
783
            else:
 
784
                inv = tree.inventory
 
785
                # 'fix' the case of a potential 'from'
 
786
                from_id = tree.path2id(
 
787
                            tree.get_canonical_inventory_path(rel_names[0]))
 
788
                if (not osutils.lexists(names_list[0]) and
 
789
                    from_id and inv.get_file_kind(from_id) == "directory"):
 
790
                    into_existing = False
 
791
        # move/rename
 
792
        if into_existing:
538
793
            # move into existing directory
 
794
            # All entries reference existing inventory items, so fix them up
 
795
            # for cicp file-systems.
 
796
            rel_names = tree.get_canonical_inventory_paths(rel_names)
539
797
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
540
798
                self.outf.write("%s => %s\n" % pair)
541
799
        else:
543
801
                raise errors.BzrCommandError('to mv multiple files the'
544
802
                                             ' destination must be a versioned'
545
803
                                             ' directory')
546
 
            tree.rename_one(rel_names[0], rel_names[1], after=after)
547
 
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
548
 
            
549
 
    
 
804
 
 
805
            # for cicp file-systems: the src references an existing inventory
 
806
            # item:
 
807
            src = tree.get_canonical_inventory_path(rel_names[0])
 
808
            # Find the canonical version of the destination:  In all cases, the
 
809
            # parent of the target must be in the inventory, so we fetch the
 
810
            # canonical version from there (we do not always *use* the
 
811
            # canonicalized tail portion - we may be attempting to rename the
 
812
            # case of the tail)
 
813
            canon_dest = tree.get_canonical_inventory_path(rel_names[1])
 
814
            dest_parent = osutils.dirname(canon_dest)
 
815
            spec_tail = osutils.basename(rel_names[1])
 
816
            # For a CICP file-system, we need to avoid creating 2 inventory
 
817
            # entries that differ only by case.  So regardless of the case
 
818
            # we *want* to use (ie, specified by the user or the file-system),
 
819
            # we must always choose to use the case of any existing inventory
 
820
            # items.  The only exception to this is when we are attempting a
 
821
            # case-only rename (ie, canonical versions of src and dest are
 
822
            # the same)
 
823
            dest_id = tree.path2id(canon_dest)
 
824
            if dest_id is None or tree.path2id(src) == dest_id:
 
825
                # No existing item we care about, so work out what case we
 
826
                # are actually going to use.
 
827
                if after:
 
828
                    # If 'after' is specified, the tail must refer to a file on disk.
 
829
                    if dest_parent:
 
830
                        dest_parent_fq = osutils.pathjoin(tree.basedir, dest_parent)
 
831
                    else:
 
832
                        # pathjoin with an empty tail adds a slash, which breaks
 
833
                        # relpath :(
 
834
                        dest_parent_fq = tree.basedir
 
835
 
 
836
                    dest_tail = osutils.canonical_relpath(
 
837
                                    dest_parent_fq,
 
838
                                    osutils.pathjoin(dest_parent_fq, spec_tail))
 
839
                else:
 
840
                    # not 'after', so case as specified is used
 
841
                    dest_tail = spec_tail
 
842
            else:
 
843
                # Use the existing item so 'mv' fails with AlreadyVersioned.
 
844
                dest_tail = os.path.basename(canon_dest)
 
845
            dest = osutils.pathjoin(dest_parent, dest_tail)
 
846
            mutter("attempting to move %s => %s", src, dest)
 
847
            tree.rename_one(src, dest, after=after)
 
848
            self.outf.write("%s => %s\n" % (src, dest))
 
849
 
 
850
 
550
851
class cmd_pull(Command):
551
852
    """Turn this branch into a mirror of another branch.
552
853
 
565
866
    that, you can omit the location to use the default.  To change the
566
867
    default, use --remember. The value will only be saved if the remote
567
868
    location can be accessed.
 
869
 
 
870
    Note: The location can be specified either in the form of a branch,
 
871
    or in the form of a path to a file containing a merge directive generated
 
872
    with bzr send.
568
873
    """
569
874
 
570
 
    _see_also = ['push', 'update', 'status-flags']
571
 
    takes_options = ['remember', 'overwrite', 'revision', 'verbose',
 
875
    _see_also = ['push', 'update', 'status-flags', 'send']
 
876
    takes_options = ['remember', 'overwrite', 'revision',
 
877
        custom_help('verbose',
 
878
            help='Show logs of pulled revisions.'),
572
879
        Option('directory',
573
880
            help='Branch to pull into, '
574
881
                 'rather than the one containing the working directory.',
575
882
            short_name='d',
576
883
            type=unicode,
577
884
            ),
 
885
        Option('local',
 
886
            help="Perform a local pull in a bound "
 
887
                 "branch.  Local pulls are not applied to "
 
888
                 "the master branch."
 
889
            ),
578
890
        ]
579
891
    takes_args = ['location?']
580
892
    encoding_type = 'replace'
581
893
 
582
894
    def run(self, location=None, remember=False, overwrite=False,
583
895
            revision=None, verbose=False,
584
 
            directory=None):
 
896
            directory=None, local=False):
585
897
        # FIXME: too much stuff is in the command class
586
898
        revision_id = None
587
899
        mergeable = None
593
905
        except errors.NoWorkingTree:
594
906
            tree_to = None
595
907
            branch_to = Branch.open_containing(directory)[0]
 
908
        
 
909
        if local and not branch_to.get_bound_location():
 
910
            raise errors.LocalRequiresBoundBranch()
596
911
 
 
912
        possible_transports = []
597
913
        if location is not None:
598
 
            mergeable, location_transport = _get_mergeable_helper(location)
 
914
            try:
 
915
                mergeable = bundle.read_mergeable_from_url(location,
 
916
                    possible_transports=possible_transports)
 
917
            except errors.NotABundle:
 
918
                mergeable = None
599
919
 
600
920
        stored_loc = branch_to.get_parent()
601
921
        if location is None:
605
925
            else:
606
926
                display_url = urlutils.unescape_for_display(stored_loc,
607
927
                        self.outf.encoding)
608
 
                self.outf.write("Using saved location: %s\n" % display_url)
 
928
                if not is_quiet():
 
929
                    self.outf.write("Using saved parent location: %s\n" % display_url)
609
930
                location = stored_loc
610
 
                location_transport = transport.get_transport(location)
611
931
 
 
932
        revision = _get_one_revision('pull', revision)
612
933
        if mergeable is not None:
613
934
            if revision is not None:
614
935
                raise errors.BzrCommandError(
618
939
                mergeable.get_merge_request(branch_to.repository)
619
940
            branch_from = branch_to
620
941
        else:
621
 
            branch_from = Branch.open_from_transport(location_transport)
 
942
            branch_from = Branch.open(location,
 
943
                possible_transports=possible_transports)
622
944
 
623
945
            if branch_to.get_parent() is None or remember:
624
946
                branch_to.set_parent(branch_from.base)
625
947
 
626
948
        if revision is not None:
627
 
            if len(revision) == 1:
628
 
                revision_id = revision[0].in_history(branch_from).rev_id
 
949
            revision_id = revision.as_revision_id(branch_from)
 
950
 
 
951
        branch_to.lock_write()
 
952
        try:
 
953
            if tree_to is not None:
 
954
                view_info = _get_view_info_for_change_reporter(tree_to)
 
955
                change_reporter = delta._ChangeReporter(
 
956
                    unversioned_filter=tree_to.is_ignored, view_info=view_info)
 
957
                result = tree_to.pull(branch_from, overwrite, revision_id,
 
958
                                      change_reporter,
 
959
                                      possible_transports=possible_transports,
 
960
                                      local=local)
629
961
            else:
630
 
                raise errors.BzrCommandError(
631
 
                    'bzr pull --revision takes one value.')
632
 
 
633
 
        if verbose:
634
 
            old_rh = branch_to.revision_history()
635
 
        if tree_to is not None:
636
 
            result = tree_to.pull(branch_from, overwrite, revision_id,
637
 
                delta._ChangeReporter(unversioned_filter=tree_to.is_ignored))
638
 
        else:
639
 
            result = branch_to.pull(branch_from, overwrite, revision_id)
640
 
 
641
 
        result.report(self.outf)
642
 
        if verbose:
643
 
            from bzrlib.log import show_changed_revisions
644
 
            new_rh = branch_to.revision_history()
645
 
            show_changed_revisions(branch_to, old_rh, new_rh,
646
 
                                   to_file=self.outf)
 
962
                result = branch_to.pull(branch_from, overwrite, revision_id,
 
963
                                      local=local)
 
964
 
 
965
            result.report(self.outf)
 
966
            if verbose and result.old_revid != result.new_revid:
 
967
                log.show_branch_change(branch_to, self.outf, result.old_revno,
 
968
                                       result.old_revid)
 
969
        finally:
 
970
            branch_to.unlock()
647
971
 
648
972
 
649
973
class cmd_push(Command):
650
974
    """Update a mirror of this branch.
651
 
    
 
975
 
652
976
    The target branch will not have its working tree populated because this
653
977
    is both expensive, and is not supported on remote file systems.
654
 
    
 
978
 
655
979
    Some smart servers or protocols *may* put the working tree in place in
656
980
    the future.
657
981
 
661
985
 
662
986
    If branches have diverged, you can use 'bzr push --overwrite' to replace
663
987
    the other branch completely, discarding its unmerged changes.
664
 
    
 
988
 
665
989
    If you want to ensure you have the different changes in the other branch,
666
990
    do a merge (see bzr help merge) from the other branch, and commit that.
667
991
    After that you will be able to do a push without '--overwrite'.
673
997
    """
674
998
 
675
999
    _see_also = ['pull', 'update', 'working-trees']
676
 
    takes_options = ['remember', 'overwrite', 'verbose',
 
1000
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
677
1001
        Option('create-prefix',
678
1002
               help='Create the path leading up to the branch '
679
1003
                    'if it does not already exist.'),
688
1012
                    ' directory exists, but does not already'
689
1013
                    ' have a control directory.  This flag will'
690
1014
                    ' allow push to proceed.'),
 
1015
        Option('stacked',
 
1016
            help='Create a stacked branch that references the public location '
 
1017
                'of the parent branch.'),
 
1018
        Option('stacked-on',
 
1019
            help='Create a stacked branch that refers to another branch '
 
1020
                'for the commit history. Only the work not present in the '
 
1021
                'referenced branch is included in the branch created.',
 
1022
            type=unicode),
691
1023
        ]
692
1024
    takes_args = ['location?']
693
1025
    encoding_type = 'replace'
694
1026
 
695
1027
    def run(self, location=None, remember=False, overwrite=False,
696
 
            create_prefix=False, verbose=False,
697
 
            use_existing_dir=False,
698
 
            directory=None):
699
 
        # FIXME: Way too big!  Put this into a function called from the
700
 
        # command.
 
1028
        create_prefix=False, verbose=False, revision=None,
 
1029
        use_existing_dir=False, directory=None, stacked_on=None,
 
1030
        stacked=False):
 
1031
        from bzrlib.push import _show_push_branch
 
1032
 
 
1033
        # Get the source branch and revision_id
701
1034
        if directory is None:
702
1035
            directory = '.'
703
1036
        br_from = Branch.open_containing(directory)[0]
704
 
        stored_loc = br_from.get_push_location()
 
1037
        revision = _get_one_revision('push', revision)
 
1038
        if revision is not None:
 
1039
            revision_id = revision.in_history(br_from).rev_id
 
1040
        else:
 
1041
            revision_id = None
 
1042
 
 
1043
        # Get the stacked_on branch, if any
 
1044
        if stacked_on is not None:
 
1045
            stacked_on = urlutils.normalize_url(stacked_on)
 
1046
        elif stacked:
 
1047
            parent_url = br_from.get_parent()
 
1048
            if parent_url:
 
1049
                parent = Branch.open(parent_url)
 
1050
                stacked_on = parent.get_public_branch()
 
1051
                if not stacked_on:
 
1052
                    # I considered excluding non-http url's here, thus forcing
 
1053
                    # 'public' branches only, but that only works for some
 
1054
                    # users, so it's best to just depend on the user spotting an
 
1055
                    # error by the feedback given to them. RBC 20080227.
 
1056
                    stacked_on = parent_url
 
1057
            if not stacked_on:
 
1058
                raise errors.BzrCommandError(
 
1059
                    "Could not determine branch to refer to.")
 
1060
 
 
1061
        # Get the destination location
705
1062
        if location is None:
 
1063
            stored_loc = br_from.get_push_location()
706
1064
            if stored_loc is None:
707
 
                raise errors.BzrCommandError("No push location known or specified.")
 
1065
                raise errors.BzrCommandError(
 
1066
                    "No push location known or specified.")
708
1067
            else:
709
1068
                display_url = urlutils.unescape_for_display(stored_loc,
710
1069
                        self.outf.encoding)
711
 
                self.outf.write("Using saved location: %s\n" % display_url)
 
1070
                self.outf.write("Using saved push location: %s\n" % display_url)
712
1071
                location = stored_loc
713
1072
 
714
 
        to_transport = transport.get_transport(location)
715
 
 
716
 
        br_to = repository_to = dir_to = None
717
 
        try:
718
 
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
719
 
        except errors.NotBranchError:
720
 
            pass # Didn't find anything
721
 
        else:
722
 
            # If we can open a branch, use its direct repository, otherwise see
723
 
            # if there is a repository without a branch.
724
 
            try:
725
 
                br_to = dir_to.open_branch()
726
 
            except errors.NotBranchError:
727
 
                # Didn't find a branch, can we find a repository?
728
 
                try:
729
 
                    repository_to = dir_to.find_repository()
730
 
                except errors.NoRepositoryPresent:
731
 
                    pass
732
 
            else:
733
 
                # Found a branch, so we must have found a repository
734
 
                repository_to = br_to.repository
735
 
        push_result = None
736
 
        if verbose:
737
 
            old_rh = []
738
 
        if dir_to is None:
739
 
            # The destination doesn't exist; create it.
740
 
            # XXX: Refactor the create_prefix/no_create_prefix code into a
741
 
            #      common helper function
742
 
            try:
743
 
                to_transport.mkdir('.')
744
 
            except errors.FileExists:
745
 
                if not use_existing_dir:
746
 
                    raise errors.BzrCommandError("Target directory %s"
747
 
                         " already exists, but does not have a valid .bzr"
748
 
                         " directory. Supply --use-existing-dir to push"
749
 
                         " there anyway." % location)
750
 
            except errors.NoSuchFile:
751
 
                if not create_prefix:
752
 
                    raise errors.BzrCommandError("Parent directory of %s"
753
 
                        " does not exist."
754
 
                        "\nYou may supply --create-prefix to create all"
755
 
                        " leading parent directories."
756
 
                        % location)
757
 
                _create_prefix(to_transport)
758
 
 
759
 
            # Now the target directory exists, but doesn't have a .bzr
760
 
            # directory. So we need to create it, along with any work to create
761
 
            # all of the dependent branches, etc.
762
 
            dir_to = br_from.bzrdir.clone_on_transport(to_transport,
763
 
                revision_id=br_from.last_revision())
764
 
            br_to = dir_to.open_branch()
765
 
            # TODO: Some more useful message about what was copied
766
 
            note('Created new branch.')
767
 
            # We successfully created the target, remember it
768
 
            if br_from.get_push_location() is None or remember:
769
 
                br_from.set_push_location(br_to.base)
770
 
        elif repository_to is None:
771
 
            # we have a bzrdir but no branch or repository
772
 
            # XXX: Figure out what to do other than complain.
773
 
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
774
 
                " directory, but not a branch or repository. This is an"
775
 
                " unsupported configuration. Please move the target directory"
776
 
                " out of the way and try again."
777
 
                % location)
778
 
        elif br_to is None:
779
 
            # We have a repository but no branch, copy the revisions, and then
780
 
            # create a branch.
781
 
            last_revision_id = br_from.last_revision()
782
 
            repository_to.fetch(br_from.repository,
783
 
                                revision_id=last_revision_id)
784
 
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
785
 
            note('Created new branch.')
786
 
            if br_from.get_push_location() is None or remember:
787
 
                br_from.set_push_location(br_to.base)
788
 
        else: # We have a valid to branch
789
 
            # We were able to connect to the remote location, so remember it
790
 
            # we don't need to successfully push because of possible divergence.
791
 
            if br_from.get_push_location() is None or remember:
792
 
                br_from.set_push_location(br_to.base)
793
 
            if verbose:
794
 
                old_rh = br_to.revision_history()
795
 
            try:
796
 
                try:
797
 
                    tree_to = dir_to.open_workingtree()
798
 
                except errors.NotLocalUrl:
799
 
                    warning("This transport does not update the working " 
800
 
                            "tree of: %s. See 'bzr help working-trees' for "
801
 
                            "more information." % br_to.base)
802
 
                    push_result = br_from.push(br_to, overwrite)
803
 
                except errors.NoWorkingTree:
804
 
                    push_result = br_from.push(br_to, overwrite)
805
 
                else:
806
 
                    tree_to.lock_write()
807
 
                    try:
808
 
                        push_result = br_from.push(tree_to.branch, overwrite)
809
 
                        tree_to.update()
810
 
                    finally:
811
 
                        tree_to.unlock()
812
 
            except errors.DivergedBranches:
813
 
                raise errors.BzrCommandError('These branches have diverged.'
814
 
                                        '  Try using "merge" and then "push".')
815
 
        if push_result is not None:
816
 
            push_result.report(self.outf)
817
 
        elif verbose:
818
 
            new_rh = br_to.revision_history()
819
 
            if old_rh != new_rh:
820
 
                # Something changed
821
 
                from bzrlib.log import show_changed_revisions
822
 
                show_changed_revisions(br_to, old_rh, new_rh,
823
 
                                       to_file=self.outf)
824
 
        else:
825
 
            # we probably did a clone rather than a push, so a message was
826
 
            # emitted above
827
 
            pass
 
1073
        _show_push_branch(br_from, revision_id, location, self.outf,
 
1074
            verbose=verbose, overwrite=overwrite, remember=remember,
 
1075
            stacked_on=stacked_on, create_prefix=create_prefix,
 
1076
            use_existing_dir=use_existing_dir)
828
1077
 
829
1078
 
830
1079
class cmd_branch(Command):
843
1092
 
844
1093
    _see_also = ['checkout']
845
1094
    takes_args = ['from_location', 'to_location?']
846
 
    takes_options = ['revision']
 
1095
    takes_options = ['revision', Option('hardlink',
 
1096
        help='Hard-link working tree files where possible.'),
 
1097
        Option('no-tree',
 
1098
            help="Create a branch without a working-tree."),
 
1099
        Option('stacked',
 
1100
            help='Create a stacked branch referring to the source branch. '
 
1101
                'The new branch will depend on the availability of the source '
 
1102
                'branch for all operations.'),
 
1103
        Option('standalone',
 
1104
               help='Do not use a shared repository, even if available.'),
 
1105
        ]
847
1106
    aliases = ['get', 'clone']
848
1107
 
849
 
    def run(self, from_location, to_location=None, revision=None):
 
1108
    def run(self, from_location, to_location=None, revision=None,
 
1109
            hardlink=False, stacked=False, standalone=False, no_tree=False):
850
1110
        from bzrlib.tag import _merge_tags_if_possible
851
 
        if revision is None:
852
 
            revision = [None]
853
 
        elif len(revision) > 1:
854
 
            raise errors.BzrCommandError(
855
 
                'bzr branch --revision takes exactly 1 revision value')
856
1111
 
857
 
        br_from = Branch.open(from_location)
 
1112
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
 
1113
            from_location)
 
1114
        revision = _get_one_revision('branch', revision)
858
1115
        br_from.lock_read()
859
1116
        try:
860
 
            if len(revision) == 1 and revision[0] is not None:
861
 
                revision_id = revision[0].in_history(br_from)[1]
 
1117
            if revision is not None:
 
1118
                revision_id = revision.as_revision_id(br_from)
862
1119
            else:
863
1120
                # FIXME - wt.last_revision, fallback to branch, fall back to
864
1121
                # None or perhaps NULL_REVISION to mean copy nothing
866
1123
                revision_id = br_from.last_revision()
867
1124
            if to_location is None:
868
1125
                to_location = urlutils.derive_to_location(from_location)
869
 
                name = None
870
 
            else:
871
 
                name = os.path.basename(to_location) + '\n'
872
 
 
873
1126
            to_transport = transport.get_transport(to_location)
874
1127
            try:
875
1128
                to_transport.mkdir('.')
882
1135
            try:
883
1136
                # preserve whatever source format we have.
884
1137
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
885
 
                                            possible_transports=[to_transport])
 
1138
                                            possible_transports=[to_transport],
 
1139
                                            accelerator_tree=accelerator_tree,
 
1140
                                            hardlink=hardlink, stacked=stacked,
 
1141
                                            force_new_repo=standalone,
 
1142
                                            create_tree_if_local=not no_tree,
 
1143
                                            source_branch=br_from)
886
1144
                branch = dir.open_branch()
887
1145
            except errors.NoSuchRevision:
888
1146
                to_transport.delete_tree('.')
889
 
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
 
1147
                msg = "The branch %s has no revision %s." % (from_location,
 
1148
                    revision)
890
1149
                raise errors.BzrCommandError(msg)
891
 
            if name:
892
 
                branch.control_files.put_utf8('branch-name', name)
893
1150
            _merge_tags_if_possible(br_from, branch)
894
 
            note('Branched %d revision(s).' % branch.revno())
 
1151
            # If the source branch is stacked, the new branch may
 
1152
            # be stacked whether we asked for that explicitly or not.
 
1153
            # We therefore need a try/except here and not just 'if stacked:'
 
1154
            try:
 
1155
                note('Created new stacked branch referring to %s.' %
 
1156
                    branch.get_stacked_on_url())
 
1157
            except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1158
                errors.UnstackableRepositoryFormat), e:
 
1159
                note('Branched %d revision(s).' % branch.revno())
895
1160
        finally:
896
1161
            br_from.unlock()
897
1162
 
903
1168
    the branch found in '.'. This is useful if you have removed the working tree
904
1169
    or if it was never created - i.e. if you pushed the branch to its current
905
1170
    location using SFTP.
906
 
    
 
1171
 
907
1172
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
908
1173
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
909
1174
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
927
1192
                                 "common operations like diff and status without "
928
1193
                                 "such access, and also support local commits."
929
1194
                            ),
 
1195
                     Option('files-from', type=str,
 
1196
                            help="Get file contents from this tree."),
 
1197
                     Option('hardlink',
 
1198
                            help='Hard-link working tree files where possible.'
 
1199
                            ),
930
1200
                     ]
931
1201
    aliases = ['co']
932
1202
 
933
1203
    def run(self, branch_location=None, to_location=None, revision=None,
934
 
            lightweight=False):
935
 
        if revision is None:
936
 
            revision = [None]
937
 
        elif len(revision) > 1:
938
 
            raise errors.BzrCommandError(
939
 
                'bzr checkout --revision takes exactly 1 revision value')
 
1204
            lightweight=False, files_from=None, hardlink=False):
940
1205
        if branch_location is None:
941
1206
            branch_location = osutils.getcwd()
942
1207
            to_location = branch_location
943
 
        source = Branch.open(branch_location)
944
 
        if len(revision) == 1 and revision[0] is not None:
945
 
            revision_id = _mod_revision.ensure_null(
946
 
                revision[0].in_history(source)[1])
 
1208
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
 
1209
            branch_location)
 
1210
        revision = _get_one_revision('checkout', revision)
 
1211
        if files_from is not None:
 
1212
            accelerator_tree = WorkingTree.open(files_from)
 
1213
        if revision is not None:
 
1214
            revision_id = revision.as_revision_id(source)
947
1215
        else:
948
1216
            revision_id = None
949
1217
        if to_location is None:
950
1218
            to_location = urlutils.derive_to_location(branch_location)
951
 
        # if the source and to_location are the same, 
 
1219
        # if the source and to_location are the same,
952
1220
        # and there is no working tree,
953
1221
        # then reconstitute a branch
954
1222
        if (osutils.abspath(to_location) ==
958
1226
            except errors.NoWorkingTree:
959
1227
                source.bzrdir.create_workingtree(revision_id)
960
1228
                return
961
 
        try:
962
 
            os.mkdir(to_location)
963
 
        except OSError, e:
964
 
            if e.errno == errno.EEXIST:
965
 
                raise errors.BzrCommandError('Target directory "%s" already'
966
 
                                             ' exists.' % to_location)
967
 
            if e.errno == errno.ENOENT:
968
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
969
 
                                             % to_location)
970
 
            else:
971
 
                raise
972
 
        source.create_checkout(to_location, revision_id, lightweight)
 
1229
        source.create_checkout(to_location, revision_id, lightweight,
 
1230
                               accelerator_tree, hardlink)
973
1231
 
974
1232
 
975
1233
class cmd_renames(Command):
991
1249
            old_tree.lock_read()
992
1250
            try:
993
1251
                old_inv = old_tree.inventory
994
 
                renames = list(_mod_tree.find_renames(old_inv, new_inv))
 
1252
                renames = []
 
1253
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1254
                for f, paths, c, v, p, n, k, e in iterator:
 
1255
                    if paths[0] == paths[1]:
 
1256
                        continue
 
1257
                    if None in (paths):
 
1258
                        continue
 
1259
                    renames.append(paths)
995
1260
                renames.sort()
996
1261
                for old_name, new_name in renames:
997
1262
                    self.outf.write("%s => %s\n" % (old_name, new_name))
1003
1268
 
1004
1269
class cmd_update(Command):
1005
1270
    """Update a tree to have the latest code committed to its branch.
1006
 
    
 
1271
 
1007
1272
    This will perform a merge into the working tree, and may generate
1008
 
    conflicts. If you have any local changes, you will still 
 
1273
    conflicts. If you have any local changes, you will still
1009
1274
    need to commit them after the update for the update to be complete.
1010
 
    
1011
 
    If you want to discard your local changes, you can just do a 
 
1275
 
 
1276
    If you want to discard your local changes, you can just do a
1012
1277
    'bzr revert' instead of 'bzr commit' after the update.
1013
1278
    """
1014
1279
 
1018
1283
 
1019
1284
    def run(self, dir='.'):
1020
1285
        tree = WorkingTree.open_containing(dir)[0]
1021
 
        master = tree.branch.get_master_branch()
 
1286
        possible_transports = []
 
1287
        master = tree.branch.get_master_branch(
 
1288
            possible_transports=possible_transports)
1022
1289
        if master is not None:
1023
1290
            tree.lock_write()
1024
1291
        else:
1034
1301
                    revno = tree.branch.revision_id_to_revno(last_rev)
1035
1302
                    note("Tree is up to date at revision %d." % (revno,))
1036
1303
                    return 0
1037
 
            conflicts = tree.update(delta._ChangeReporter(
1038
 
                                        unversioned_filter=tree.is_ignored))
 
1304
            view_info = _get_view_info_for_change_reporter(tree)
 
1305
            conflicts = tree.update(
 
1306
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
 
1307
                view_info=view_info), possible_transports=possible_transports)
1039
1308
            revno = tree.branch.revision_id_to_revno(
1040
1309
                _mod_revision.ensure_null(tree.last_revision()))
1041
1310
            note('Updated to revision %d.' % (revno,))
1054
1323
    """Show information about a working tree, branch or repository.
1055
1324
 
1056
1325
    This command will show all known locations and formats associated to the
1057
 
    tree, branch or repository.  Statistical information is included with
1058
 
    each report.
 
1326
    tree, branch or repository.
 
1327
 
 
1328
    In verbose mode, statistical information is included with each report.
 
1329
    To see extended statistic information, use a verbosity level of 2 or
 
1330
    higher by specifying the verbose option multiple times, e.g. -vv.
1059
1331
 
1060
1332
    Branches and working trees will also report any missing revisions.
 
1333
 
 
1334
    :Examples:
 
1335
 
 
1336
      Display information on the format and related locations:
 
1337
 
 
1338
        bzr info
 
1339
 
 
1340
      Display the above together with extended format information and
 
1341
      basic statistics (like the number of files in the working tree and
 
1342
      number of revisions in the branch and repository):
 
1343
 
 
1344
        bzr info -v
 
1345
 
 
1346
      Display the above together with number of committers to the branch:
 
1347
 
 
1348
        bzr info -vv
1061
1349
    """
1062
1350
    _see_also = ['revno', 'working-trees', 'repositories']
1063
1351
    takes_args = ['location?']
1064
1352
    takes_options = ['verbose']
 
1353
    encoding_type = 'replace'
1065
1354
 
1066
1355
    @display_command
1067
 
    def run(self, location=None, verbose=0):
 
1356
    def run(self, location=None, verbose=False):
 
1357
        if verbose:
 
1358
            noise_level = get_verbosity_level()
 
1359
        else:
 
1360
            noise_level = 0
1068
1361
        from bzrlib.info import show_bzrdir_info
1069
1362
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1070
 
                         verbose=verbose)
 
1363
                         verbose=noise_level, outfile=self.outf)
1071
1364
 
1072
1365
 
1073
1366
class cmd_remove(Command):
1074
1367
    """Remove files or directories.
1075
1368
 
1076
 
    This makes bzr stop tracking changes to the specified files and
1077
 
    delete them if they can easily be recovered using revert.
1078
 
 
1079
 
    You can specify one or more files, and/or --new.  If you specify --new,
1080
 
    only 'added' files will be removed.  If you specify both, then new files
1081
 
    in the specified directories will be removed.  If the directories are
1082
 
    also new, they will also be removed.
 
1369
    This makes bzr stop tracking changes to the specified files. bzr will delete
 
1370
    them if they can easily be recovered using revert. If no options or
 
1371
    parameters are given bzr will scan for files that are being tracked by bzr
 
1372
    but missing in your tree and stop tracking them for you.
1083
1373
    """
1084
1374
    takes_args = ['file*']
1085
1375
    takes_options = ['verbose',
1086
 
        Option('new', help='Remove newly-added files.'),
 
1376
        Option('new', help='Only remove files that have never been committed.'),
1087
1377
        RegistryOption.from_kwargs('file-deletion-strategy',
1088
1378
            'The file deletion mode to be used.',
1089
1379
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1092
1382
            keep="Don't delete any files.",
1093
1383
            force='Delete all the specified files, even if they can not be '
1094
1384
                'recovered and even if they are non-empty directories.')]
1095
 
    aliases = ['rm']
 
1385
    aliases = ['rm', 'del']
1096
1386
    encoding_type = 'replace'
1097
1387
 
1098
1388
    def run(self, file_list, verbose=False, new=False,
1100
1390
        tree, file_list = tree_files(file_list)
1101
1391
 
1102
1392
        if file_list is not None:
1103
 
            file_list = [f for f in file_list if f != '']
1104
 
        elif not new:
1105
 
            raise errors.BzrCommandError('Specify one or more files to'
1106
 
            ' remove, or use --new.')
 
1393
            file_list = [f for f in file_list]
1107
1394
 
1108
 
        if new:
1109
 
            added = tree.changes_from(tree.basis_tree(),
1110
 
                specific_files=file_list).added
1111
 
            file_list = sorted([f[0] for f in added], reverse=True)
1112
 
            if len(file_list) == 0:
1113
 
                raise errors.BzrCommandError('No matching files.')
1114
 
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1115
 
            keep_files=file_deletion_strategy=='keep',
1116
 
            force=file_deletion_strategy=='force')
 
1395
        tree.lock_write()
 
1396
        try:
 
1397
            # Heuristics should probably all move into tree.remove_smart or
 
1398
            # some such?
 
1399
            if new:
 
1400
                added = tree.changes_from(tree.basis_tree(),
 
1401
                    specific_files=file_list).added
 
1402
                file_list = sorted([f[0] for f in added], reverse=True)
 
1403
                if len(file_list) == 0:
 
1404
                    raise errors.BzrCommandError('No matching files.')
 
1405
            elif file_list is None:
 
1406
                # missing files show up in iter_changes(basis) as
 
1407
                # versioned-with-no-kind.
 
1408
                missing = []
 
1409
                for change in tree.iter_changes(tree.basis_tree()):
 
1410
                    # Find paths in the working tree that have no kind:
 
1411
                    if change[1][1] is not None and change[6][1] is None:
 
1412
                        missing.append(change[1][1])
 
1413
                file_list = sorted(missing, reverse=True)
 
1414
                file_deletion_strategy = 'keep'
 
1415
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1416
                keep_files=file_deletion_strategy=='keep',
 
1417
                force=file_deletion_strategy=='force')
 
1418
        finally:
 
1419
            tree.unlock()
1117
1420
 
1118
1421
 
1119
1422
class cmd_file_id(Command):
1165
1468
 
1166
1469
    This can correct data mismatches that may have been caused by
1167
1470
    previous ghost operations or bzr upgrades. You should only
1168
 
    need to run this command if 'bzr check' or a bzr developer 
 
1471
    need to run this command if 'bzr check' or a bzr developer
1169
1472
    advises you to run it.
1170
1473
 
1171
1474
    If a second branch is provided, cross-branch reconciliation is
1173
1476
    id which was not present in very early bzr versions is represented
1174
1477
    correctly in both branches.
1175
1478
 
1176
 
    At the same time it is run it may recompress data resulting in 
 
1479
    At the same time it is run it may recompress data resulting in
1177
1480
    a potential saving in disk space or performance gain.
1178
1481
 
1179
1482
    The branch *MUST* be on a listable system such as local disk or sftp.
1224
1527
            last_revision = wt.last_revision()
1225
1528
 
1226
1529
        revision_ids = b.repository.get_ancestry(last_revision)
1227
 
        assert revision_ids[0] is None
1228
1530
        revision_ids.pop(0)
1229
1531
        for revision_id in revision_ids:
1230
1532
            self.outf.write(revision_id + '\n')
1236
1538
    Use this to create an empty branch, or before importing an
1237
1539
    existing project.
1238
1540
 
1239
 
    If there is a repository in a parent directory of the location, then 
 
1541
    If there is a repository in a parent directory of the location, then
1240
1542
    the history of the branch will be stored in the repository.  Otherwise
1241
1543
    init creates a standalone branch which carries its own history
1242
1544
    in the .bzr directory.
1250
1552
        bzr init
1251
1553
        bzr add .
1252
1554
        bzr status
1253
 
        bzr commit -m 'imported project'
 
1555
        bzr commit -m "imported project"
1254
1556
    """
1255
1557
 
1256
1558
    _see_also = ['init-repository', 'branch', 'checkout']
1262
1564
         RegistryOption('format',
1263
1565
                help='Specify a format for this branch. '
1264
1566
                'See "help formats".',
1265
 
                registry=bzrdir.format_registry,
1266
 
                converter=bzrdir.format_registry.make_bzrdir,
 
1567
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
1568
                converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1267
1569
                value_switches=True,
1268
1570
                title="Branch Format",
1269
1571
                ),
1294
1596
                    "\nYou may supply --create-prefix to create all"
1295
1597
                    " leading parent directories."
1296
1598
                    % location)
1297
 
            _create_prefix(to_transport)
 
1599
            to_transport.create_prefix()
1298
1600
 
1299
1601
        try:
1300
 
            existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
 
1602
            a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1301
1603
        except errors.NotBranchError:
1302
1604
            # really a NotBzrDir error...
1303
1605
            create_branch = bzrdir.BzrDir.create_branch_convenience
1304
1606
            branch = create_branch(to_transport.base, format=format,
1305
1607
                                   possible_transports=[to_transport])
 
1608
            a_bzrdir = branch.bzrdir
1306
1609
        else:
1307
1610
            from bzrlib.transport.local import LocalTransport
1308
 
            if existing_bzrdir.has_branch():
 
1611
            if a_bzrdir.has_branch():
1309
1612
                if (isinstance(to_transport, LocalTransport)
1310
 
                    and not existing_bzrdir.has_workingtree()):
 
1613
                    and not a_bzrdir.has_workingtree()):
1311
1614
                        raise errors.BranchExistsWithoutWorkingTree(location)
1312
1615
                raise errors.AlreadyBranchError(location)
1313
 
            else:
1314
 
                branch = existing_bzrdir.create_branch()
1315
 
                existing_bzrdir.create_workingtree()
 
1616
            branch = a_bzrdir.create_branch()
 
1617
            a_bzrdir.create_workingtree()
1316
1618
        if append_revisions_only:
1317
1619
            try:
1318
1620
                branch.set_append_revisions_only(True)
1319
1621
            except errors.UpgradeRequired:
1320
1622
                raise errors.BzrCommandError('This branch format cannot be set'
1321
1623
                    ' to append-revisions-only.  Try --experimental-branch6')
 
1624
        if not is_quiet():
 
1625
            from bzrlib.info import describe_layout, describe_format
 
1626
            try:
 
1627
                tree = a_bzrdir.open_workingtree(recommend_upgrade=False)
 
1628
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
1629
                tree = None
 
1630
            repository = branch.repository
 
1631
            layout = describe_layout(repository, branch, tree).lower()
 
1632
            format = describe_format(a_bzrdir, repository, branch, tree)
 
1633
            self.outf.write("Created a %s (format: %s)\n" % (layout, format))
 
1634
            if repository.is_shared():
 
1635
                #XXX: maybe this can be refactored into transport.path_or_url()
 
1636
                url = repository.bzrdir.root_transport.external_url()
 
1637
                try:
 
1638
                    url = urlutils.local_path_from_url(url)
 
1639
                except errors.InvalidURL:
 
1640
                    pass
 
1641
                self.outf.write("Using shared repository: %s\n" % url)
1322
1642
 
1323
1643
 
1324
1644
class cmd_init_repository(Command):
1348
1668
    takes_options = [RegistryOption('format',
1349
1669
                            help='Specify a format for this repository. See'
1350
1670
                                 ' "bzr help formats" for details.',
1351
 
                            registry=bzrdir.format_registry,
1352
 
                            converter=bzrdir.format_registry.make_bzrdir,
 
1671
                            lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
1672
                            converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1353
1673
                            value_switches=True, title='Repository format'),
1354
1674
                     Option('no-trees',
1355
1675
                             help='Branches in the repository will default to'
1370
1690
        newdir = format.initialize_on_transport(to_transport)
1371
1691
        repo = newdir.create_repository(shared=True)
1372
1692
        repo.set_make_working_trees(not no_trees)
 
1693
        if not is_quiet():
 
1694
            from bzrlib.info import show_bzrdir_info
 
1695
            show_bzrdir_info(repo.bzrdir, verbose=0, outfile=self.outf)
1373
1696
 
1374
1697
 
1375
1698
class cmd_diff(Command):
1376
 
    """Show differences in the working tree or between revisions.
1377
 
    
1378
 
    If files are listed, only the changes in those files are listed.
1379
 
    Otherwise, all changes for the tree are listed.
 
1699
    """Show differences in the working tree, between revisions or branches.
 
1700
 
 
1701
    If no arguments are given, all changes for the current tree are listed.
 
1702
    If files are given, only the changes in those files are listed.
 
1703
    Remote and multiple branches can be compared by using the --old and
 
1704
    --new options. If not provided, the default for both is derived from
 
1705
    the first argument, if any, or the current tree if no arguments are
 
1706
    given.
1380
1707
 
1381
1708
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1382
1709
    produces patches suitable for "patch -p1".
1383
1710
 
 
1711
    :Exit values:
 
1712
        1 - changed
 
1713
        2 - unrepresentable changes
 
1714
        3 - error
 
1715
        0 - no change
 
1716
 
1384
1717
    :Examples:
1385
1718
        Shows the difference in the working tree versus the last commit::
1386
1719
 
1394
1727
 
1395
1728
            bzr diff -r1..2
1396
1729
 
 
1730
        Difference between revision 2 and revision 1 for branch xxx::
 
1731
 
 
1732
            bzr diff -r1..2 xxx
 
1733
 
 
1734
        Show just the differences for file NEWS::
 
1735
 
 
1736
            bzr diff NEWS
 
1737
 
 
1738
        Show the differences in working tree xxx for file NEWS::
 
1739
 
 
1740
            bzr diff xxx/NEWS
 
1741
 
 
1742
        Show the differences from branch xxx to this working tree:
 
1743
 
 
1744
            bzr diff --old xxx
 
1745
 
 
1746
        Show the differences between two branches for file NEWS::
 
1747
 
 
1748
            bzr diff --old xxx --new yyy NEWS
 
1749
 
1397
1750
        Same as 'bzr diff' but prefix paths with old/ and new/::
1398
1751
 
1399
1752
            bzr diff --prefix old/:new/
1400
 
 
1401
 
        Show the differences between the two working trees::
1402
 
 
1403
 
            bzr diff bzr.mine bzr.dev
1404
 
 
1405
 
        Show just the differences for 'foo.c'::
1406
 
 
1407
 
            bzr diff foo.c
1408
1753
    """
1409
 
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
1410
 
    #       or a graphical diff.
1411
 
 
1412
 
    # TODO: Python difflib is not exactly the same as unidiff; should
1413
 
    #       either fix it up or prefer to use an external diff.
1414
 
 
1415
 
    # TODO: Selected-file diff is inefficient and doesn't show you
1416
 
    #       deleted files.
1417
 
 
1418
 
    # TODO: This probably handles non-Unix newlines poorly.
1419
 
 
1420
1754
    _see_also = ['status']
1421
1755
    takes_args = ['file*']
1422
1756
    takes_options = [
1424
1758
               help='Pass these options to the external diff program.'),
1425
1759
        Option('prefix', type=str,
1426
1760
               short_name='p',
1427
 
               help='Set prefixes to added to old and new filenames, as '
 
1761
               help='Set prefixes added to old and new filenames, as '
1428
1762
                    'two values separated by a colon. (eg "old/:new/").'),
 
1763
        Option('old',
 
1764
            help='Branch/tree to compare from.',
 
1765
            type=unicode,
 
1766
            ),
 
1767
        Option('new',
 
1768
            help='Branch/tree to compare to.',
 
1769
            type=unicode,
 
1770
            ),
1429
1771
        'revision',
 
1772
        'change',
 
1773
        Option('using',
 
1774
            help='Use this command to compare files.',
 
1775
            type=unicode,
 
1776
            ),
1430
1777
        ]
1431
1778
    aliases = ['di', 'dif']
1432
1779
    encoding_type = 'exact'
1433
1780
 
1434
1781
    @display_command
1435
1782
    def run(self, revision=None, file_list=None, diff_options=None,
1436
 
            prefix=None):
1437
 
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
 
1783
            prefix=None, old=None, new=None, using=None):
 
1784
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
1438
1785
 
1439
1786
        if (prefix is None) or (prefix == '0'):
1440
1787
            # diff -p0 format
1454
1801
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1455
1802
                                         ' one or two revision specifiers')
1456
1803
 
1457
 
        try:
1458
 
            tree1, file_list = internal_tree_files(file_list)
1459
 
            tree2 = None
1460
 
            b = None
1461
 
            b2 = None
1462
 
        except errors.FileInWrongBranch:
1463
 
            if len(file_list) != 2:
1464
 
                raise errors.BzrCommandError("Files are in different branches")
1465
 
 
1466
 
            tree1, file1 = WorkingTree.open_containing(file_list[0])
1467
 
            tree2, file2 = WorkingTree.open_containing(file_list[1])
1468
 
            if file1 != "" or file2 != "":
1469
 
                # FIXME diff those two files. rbc 20051123
1470
 
                raise errors.BzrCommandError("Files are in different branches")
1471
 
            file_list = None
1472
 
        except errors.NotBranchError:
1473
 
            if (revision is not None and len(revision) == 2
1474
 
                and not revision[0].needs_branch()
1475
 
                and not revision[1].needs_branch()):
1476
 
                # If both revision specs include a branch, we can
1477
 
                # diff them without needing a local working tree
1478
 
                tree1, tree2 = None, None
1479
 
            else:
1480
 
                raise
1481
 
 
1482
 
        if tree2 is not None:
1483
 
            if revision is not None:
1484
 
                # FIXME: but there should be a clean way to diff between
1485
 
                # non-default versions of two trees, it's not hard to do
1486
 
                # internally...
1487
 
                raise errors.BzrCommandError(
1488
 
                        "Sorry, diffing arbitrary revisions across branches "
1489
 
                        "is not implemented yet")
1490
 
            return show_diff_trees(tree1, tree2, sys.stdout, 
1491
 
                                   specific_files=file_list,
1492
 
                                   external_diff_options=diff_options,
1493
 
                                   old_label=old_label, new_label=new_label)
1494
 
 
1495
 
        return diff_cmd_helper(tree1, file_list, diff_options,
1496
 
                               revision_specs=revision,
1497
 
                               old_label=old_label, new_label=new_label)
 
1804
        old_tree, new_tree, specific_files, extra_trees = \
 
1805
                _get_trees_to_diff(file_list, revision, old, new,
 
1806
                apply_view=True)
 
1807
        return show_diff_trees(old_tree, new_tree, sys.stdout,
 
1808
                               specific_files=specific_files,
 
1809
                               external_diff_options=diff_options,
 
1810
                               old_label=old_label, new_label=new_label,
 
1811
                               extra_trees=extra_trees, using=using)
1498
1812
 
1499
1813
 
1500
1814
class cmd_deleted(Command):
1536
1850
 
1537
1851
    hidden = True
1538
1852
    _see_also = ['status', 'ls']
 
1853
    takes_options = [
 
1854
            Option('null',
 
1855
                   help='Write an ascii NUL (\\0) separator '
 
1856
                   'between files rather than a newline.')
 
1857
            ]
1539
1858
 
1540
1859
    @display_command
1541
 
    def run(self):
 
1860
    def run(self, null=False):
1542
1861
        tree = WorkingTree.open_containing(u'.')[0]
1543
1862
        td = tree.changes_from(tree.basis_tree())
1544
1863
        for path, id, kind, text_modified, meta_modified in td.modified:
1545
 
            self.outf.write(path + '\n')
 
1864
            if null:
 
1865
                self.outf.write(path + '\0')
 
1866
            else:
 
1867
                self.outf.write(osutils.quotefn(path) + '\n')
1546
1868
 
1547
1869
 
1548
1870
class cmd_added(Command):
1551
1873
 
1552
1874
    hidden = True
1553
1875
    _see_also = ['status', 'ls']
 
1876
    takes_options = [
 
1877
            Option('null',
 
1878
                   help='Write an ascii NUL (\\0) separator '
 
1879
                   'between files rather than a newline.')
 
1880
            ]
1554
1881
 
1555
1882
    @display_command
1556
 
    def run(self):
 
1883
    def run(self, null=False):
1557
1884
        wt = WorkingTree.open_containing(u'.')[0]
1558
1885
        wt.lock_read()
1559
1886
        try:
1570
1897
                    path = inv.id2path(file_id)
1571
1898
                    if not os.access(osutils.abspath(path), os.F_OK):
1572
1899
                        continue
1573
 
                    self.outf.write(path + '\n')
 
1900
                    if null:
 
1901
                        self.outf.write(path + '\0')
 
1902
                    else:
 
1903
                        self.outf.write(osutils.quotefn(path) + '\n')
1574
1904
            finally:
1575
1905
                basis.unlock()
1576
1906
        finally:
1599
1929
        raise errors.BzrCommandError(msg)
1600
1930
 
1601
1931
 
 
1932
def _parse_levels(s):
 
1933
    try:
 
1934
        return int(s)
 
1935
    except ValueError:
 
1936
        msg = "The levels argument must be an integer."
 
1937
        raise errors.BzrCommandError(msg)
 
1938
 
 
1939
 
1602
1940
class cmd_log(Command):
1603
 
    """Show log of a branch, file, or directory.
1604
 
 
1605
 
    By default show the log of the branch containing the working directory.
1606
 
 
1607
 
    To request a range of logs, you can use the command -r begin..end
1608
 
    -r revision requests a specific revision, -r ..end or -r begin.. are
1609
 
    also valid.
1610
 
 
1611
 
    :Examples:
1612
 
        Log the current branch::
1613
 
 
1614
 
            bzr log
1615
 
 
1616
 
        Log a file::
1617
 
 
1618
 
            bzr log foo.c
1619
 
 
1620
 
        Log the last 10 revisions of a branch::
1621
 
 
1622
 
            bzr log -r -10.. http://server/branch
 
1941
    """Show historical log for a branch or subset of a branch.
 
1942
 
 
1943
    log is bzr's default tool for exploring the history of a branch.
 
1944
    The branch to use is taken from the first parameter. If no parameters
 
1945
    are given, the branch containing the working directory is logged.
 
1946
    Here are some simple examples::
 
1947
 
 
1948
      bzr log                       log the current branch
 
1949
      bzr log foo.py                log a file in its branch
 
1950
      bzr log http://server/branch  log a branch on a server
 
1951
 
 
1952
    The filtering, ordering and information shown for each revision can
 
1953
    be controlled as explained below. By default, all revisions are
 
1954
    shown sorted (topologically) so that newer revisions appear before
 
1955
    older ones and descendants always appear before ancestors. If displayed,
 
1956
    merged revisions are shown indented under the revision in which they
 
1957
    were merged.
 
1958
 
 
1959
    :Output control:
 
1960
 
 
1961
      The log format controls how information about each revision is
 
1962
      displayed. The standard log formats are called ``long``, ``short``
 
1963
      and ``line``. The default is long. See ``bzr help log-formats``
 
1964
      for more details on log formats.
 
1965
 
 
1966
      The following options can be used to control what information is
 
1967
      displayed::
 
1968
 
 
1969
        -l N        display a maximum of N revisions
 
1970
        -n N        display N levels of revisions (0 for all, 1 for collapsed)
 
1971
        -v          display a status summary (delta) for each revision
 
1972
        -p          display a diff (patch) for each revision
 
1973
        --show-ids  display revision-ids (and file-ids), not just revnos
 
1974
 
 
1975
      Note that the default number of levels to display is a function of the
 
1976
      log format. If the -n option is not used, the standard log formats show
 
1977
      just the top level (mainline).
 
1978
 
 
1979
      Status summaries are shown using status flags like A, M, etc. To see
 
1980
      the changes explained using words like ``added`` and ``modified``
 
1981
      instead, use the -vv option.
 
1982
 
 
1983
    :Ordering control:
 
1984
 
 
1985
      To display revisions from oldest to newest, use the --forward option.
 
1986
      In most cases, using this option will have little impact on the total
 
1987
      time taken to produce a log, though --forward does not incrementally
 
1988
      display revisions like --reverse does when it can.
 
1989
 
 
1990
    :Revision filtering:
 
1991
 
 
1992
      The -r option can be used to specify what revision or range of revisions
 
1993
      to filter against. The various forms are shown below::
 
1994
 
 
1995
        -rX      display revision X
 
1996
        -rX..    display revision X and later
 
1997
        -r..Y    display up to and including revision Y
 
1998
        -rX..Y   display from X to Y inclusive
 
1999
 
 
2000
      See ``bzr help revisionspec`` for details on how to specify X and Y.
 
2001
      Some common examples are given below::
 
2002
 
 
2003
        -r-1                show just the tip
 
2004
        -r-10..             show the last 10 mainline revisions
 
2005
        -rsubmit:..         show what's new on this branch
 
2006
        -rancestor:path..   show changes since the common ancestor of this
 
2007
                            branch and the one at location path
 
2008
        -rdate:yesterday..  show changes since yesterday
 
2009
 
 
2010
      When logging a range of revisions using -rX..Y, log starts at
 
2011
      revision Y and searches back in history through the primary
 
2012
      ("left-hand") parents until it finds X. When logging just the
 
2013
      top level (using -n1), an error is reported if X is not found
 
2014
      along the way. If multi-level logging is used (-n0), X may be
 
2015
      a nested merge revision and the log will be truncated accordingly.
 
2016
 
 
2017
    :Path filtering:
 
2018
 
 
2019
      If parameters are given and the first one is not a branch, the log
 
2020
      will be filtered to show only those revisions that changed the
 
2021
      nominated files or directories.
 
2022
 
 
2023
      Filenames are interpreted within their historical context. To log a
 
2024
      deleted file, specify a revision range so that the file existed at
 
2025
      the end or start of the range.
 
2026
 
 
2027
      Historical context is also important when interpreting pathnames of
 
2028
      renamed files/directories. Consider the following example:
 
2029
 
 
2030
      * revision 1: add tutorial.txt
 
2031
      * revision 2: modify tutorial.txt
 
2032
      * revision 3: rename tutorial.txt to guide.txt; add tutorial.txt
 
2033
 
 
2034
      In this case:
 
2035
 
 
2036
      * ``bzr log guide.txt`` will log the file added in revision 1
 
2037
 
 
2038
      * ``bzr log tutorial.txt`` will log the new file added in revision 3
 
2039
 
 
2040
      * ``bzr log -r2 -p tutorial.txt`` will show the changes made to
 
2041
        the original file in revision 2.
 
2042
 
 
2043
      * ``bzr log -r2 -p guide.txt`` will display an error message as there
 
2044
        was no file called guide.txt in revision 2.
 
2045
 
 
2046
      Renames are always followed by log. By design, there is no need to
 
2047
      explicitly ask for this (and no way to stop logging a file back
 
2048
      until it was last renamed).
 
2049
 
 
2050
    :Other filtering:
 
2051
 
 
2052
      The --message option can be used for finding revisions that match a
 
2053
      regular expression in a commit message.
 
2054
 
 
2055
    :Tips & tricks:
 
2056
 
 
2057
      GUI tools and IDEs are often better at exploring history than command
 
2058
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
 
2059
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
 
2060
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
 
2061
 
 
2062
      Web interfaces are often better at exploring history than command line
 
2063
      tools, particularly for branches on servers. You may prefer Loggerhead
 
2064
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
 
2065
 
 
2066
      You may find it useful to add the aliases below to ``bazaar.conf``::
 
2067
 
 
2068
        [ALIASES]
 
2069
        tip = log -r-1
 
2070
        top = log -l10 --line
 
2071
        show = log -v -p
 
2072
 
 
2073
      ``bzr tip`` will then show the latest revision while ``bzr top``
 
2074
      will show the last 10 mainline revisions. To see the details of a
 
2075
      particular revision X,  ``bzr show -rX``.
 
2076
 
 
2077
      If you are interested in looking deeper into a particular merge X,
 
2078
      use ``bzr log -n0 -rX``.
 
2079
 
 
2080
      ``bzr log -v`` on a branch with lots of history is currently
 
2081
      very slow. A fix for this issue is currently under development.
 
2082
      With or without that fix, it is recommended that a revision range
 
2083
      be given when using the -v option.
 
2084
 
 
2085
      bzr has a generic full-text matching plugin, bzr-search, that can be
 
2086
      used to find revisions matching user names, commit messages, etc.
 
2087
      Among other features, this plugin can find all revisions containing
 
2088
      a list of words but not others.
 
2089
 
 
2090
      When exploring non-mainline history on large projects with deep
 
2091
      history, the performance of log can be greatly improved by installing
 
2092
      the historycache plugin. This plugin buffers historical information
 
2093
      trading disk space for faster speed.
1623
2094
    """
1624
 
 
1625
 
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1626
 
 
1627
 
    takes_args = ['location?']
 
2095
    takes_args = ['file*']
 
2096
    _see_also = ['log-formats', 'revisionspec']
1628
2097
    takes_options = [
1629
2098
            Option('forward',
1630
2099
                   help='Show from oldest to newest.'),
1631
 
            Option('timezone',
1632
 
                   type=str,
1633
 
                   help='Display timezone as local, original, or utc.'),
1634
 
            Option('verbose',
1635
 
                   short_name='v',
 
2100
            'timezone',
 
2101
            custom_help('verbose',
1636
2102
                   help='Show files changed in each revision.'),
1637
2103
            'show-ids',
1638
2104
            'revision',
 
2105
            Option('change',
 
2106
                   type=bzrlib.option._parse_revision_str,
 
2107
                   short_name='c',
 
2108
                   help='Show just the specified revision.'
 
2109
                   ' See also "help revisionspec".'),
1639
2110
            'log-format',
 
2111
            Option('levels',
 
2112
                   short_name='n',
 
2113
                   help='Number of levels to display - 0 for all, 1 for flat.',
 
2114
                   argname='N',
 
2115
                   type=_parse_levels),
1640
2116
            Option('message',
1641
2117
                   short_name='m',
1642
2118
                   help='Show revisions whose message matches this '
1643
2119
                        'regular expression.',
1644
2120
                   type=str),
1645
2121
            Option('limit',
 
2122
                   short_name='l',
1646
2123
                   help='Limit the output to the first N revisions.',
1647
2124
                   argname='N',
1648
2125
                   type=_parse_limit),
 
2126
            Option('show-diff',
 
2127
                   short_name='p',
 
2128
                   help='Show changes made in each revision as a patch.'),
 
2129
            Option('include-merges',
 
2130
                   help='Show merged revisions like --levels 0 does.'),
1649
2131
            ]
1650
2132
    encoding_type = 'replace'
1651
2133
 
1652
2134
    @display_command
1653
 
    def run(self, location=None, timezone='original',
 
2135
    def run(self, file_list=None, timezone='original',
1654
2136
            verbose=False,
1655
2137
            show_ids=False,
1656
2138
            forward=False,
1657
2139
            revision=None,
 
2140
            change=None,
1658
2141
            log_format=None,
 
2142
            levels=None,
1659
2143
            message=None,
1660
 
            limit=None):
1661
 
        from bzrlib.log import show_log
1662
 
        assert message is None or isinstance(message, basestring), \
1663
 
            "invalid message argument %r" % message
 
2144
            limit=None,
 
2145
            show_diff=False,
 
2146
            include_merges=False):
 
2147
        from bzrlib.log import (
 
2148
            Logger,
 
2149
            make_log_request_dict,
 
2150
            _get_info_for_log_files,
 
2151
            )
1664
2152
        direction = (forward and 'forward') or 'reverse'
1665
 
        
1666
 
        # log everything
1667
 
        file_id = None
1668
 
        if location:
1669
 
            # find the file id to log:
1670
 
 
1671
 
            tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1672
 
                location)
1673
 
            if fp != '':
1674
 
                if tree is None:
1675
 
                    tree = b.basis_tree()
1676
 
                file_id = tree.path2id(fp)
 
2153
        if include_merges:
 
2154
            if levels is None:
 
2155
                levels = 0
 
2156
            else:
 
2157
                raise errors.BzrCommandError(
 
2158
                    '--levels and --include-merges are mutually exclusive')
 
2159
 
 
2160
        if change is not None:
 
2161
            if len(change) > 1:
 
2162
                raise errors.RangeInChangeOption()
 
2163
            if revision is not None:
 
2164
                raise errors.BzrCommandError(
 
2165
                    '--revision and --change are mutually exclusive')
 
2166
            else:
 
2167
                revision = change
 
2168
 
 
2169
        file_ids = []
 
2170
        filter_by_dir = False
 
2171
        if file_list:
 
2172
            # find the file ids to log and check for directory filtering
 
2173
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
 
2174
                file_list)
 
2175
            for relpath, file_id, kind in file_info_list:
1677
2176
                if file_id is None:
1678
2177
                    raise errors.BzrCommandError(
1679
 
                        "Path does not have any revision history: %s" %
1680
 
                        location)
 
2178
                        "Path unknown at end or start of revision range: %s" %
 
2179
                        relpath)
 
2180
                # If the relpath is the top of the tree, we log everything
 
2181
                if relpath == '':
 
2182
                    file_ids = []
 
2183
                    break
 
2184
                else:
 
2185
                    file_ids.append(file_id)
 
2186
                filter_by_dir = filter_by_dir or (
 
2187
                    kind in ['directory', 'tree-reference'])
1681
2188
        else:
1682
 
            # local dir only
1683
 
            # FIXME ? log the current subdir only RBC 20060203 
 
2189
            # log everything
 
2190
            # FIXME ? log the current subdir only RBC 20060203
1684
2191
            if revision is not None \
1685
2192
                    and len(revision) > 0 and revision[0].get_branch():
1686
2193
                location = revision[0].get_branch()
1688
2195
                location = '.'
1689
2196
            dir, relpath = bzrdir.BzrDir.open_containing(location)
1690
2197
            b = dir.open_branch()
 
2198
            rev1, rev2 = _get_revision_range(revision, b, self.name())
 
2199
 
 
2200
        # Decide on the type of delta & diff filtering to use
 
2201
        # TODO: add an --all-files option to make this configurable & consistent
 
2202
        if not verbose:
 
2203
            delta_type = None
 
2204
        else:
 
2205
            delta_type = 'full'
 
2206
        if not show_diff:
 
2207
            diff_type = None
 
2208
        elif file_ids:
 
2209
            diff_type = 'partial'
 
2210
        else:
 
2211
            diff_type = 'full'
1691
2212
 
1692
2213
        b.lock_read()
1693
2214
        try:
1694
 
            if revision is None:
1695
 
                rev1 = None
1696
 
                rev2 = None
1697
 
            elif len(revision) == 1:
1698
 
                rev1 = rev2 = revision[0].in_history(b)
1699
 
            elif len(revision) == 2:
1700
 
                if revision[1].get_branch() != revision[0].get_branch():
1701
 
                    # b is taken from revision[0].get_branch(), and
1702
 
                    # show_log will use its revision_history. Having
1703
 
                    # different branches will lead to weird behaviors.
1704
 
                    raise errors.BzrCommandError(
1705
 
                        "Log doesn't accept two revisions in different"
1706
 
                        " branches.")
1707
 
                rev1 = revision[0].in_history(b)
1708
 
                rev2 = revision[1].in_history(b)
1709
 
            else:
1710
 
                raise errors.BzrCommandError(
1711
 
                    'bzr log --revision takes one or two values.')
1712
 
 
 
2215
            # Build the log formatter
1713
2216
            if log_format is None:
1714
2217
                log_format = log.log_formatter_registry.get_default(b)
1715
 
 
1716
2218
            lf = log_format(show_ids=show_ids, to_file=self.outf,
1717
 
                            show_timezone=timezone)
1718
 
 
1719
 
            show_log(b,
1720
 
                     lf,
1721
 
                     file_id,
1722
 
                     verbose=verbose,
1723
 
                     direction=direction,
1724
 
                     start_revision=rev1,
1725
 
                     end_revision=rev2,
1726
 
                     search=message,
1727
 
                     limit=limit)
 
2219
                            show_timezone=timezone,
 
2220
                            delta_format=get_verbosity_level(),
 
2221
                            levels=levels,
 
2222
                            show_advice=levels is None)
 
2223
 
 
2224
            # Choose the algorithm for doing the logging. It's annoying
 
2225
            # having multiple code paths like this but necessary until
 
2226
            # the underlying repository format is faster at generating
 
2227
            # deltas or can provide everything we need from the indices.
 
2228
            # The default algorithm - match-using-deltas - works for
 
2229
            # multiple files and directories and is faster for small
 
2230
            # amounts of history (200 revisions say). However, it's too
 
2231
            # slow for logging a single file in a repository with deep
 
2232
            # history, i.e. > 10K revisions. In the spirit of "do no
 
2233
            # evil when adding features", we continue to use the
 
2234
            # original algorithm - per-file-graph - for the "single
 
2235
            # file that isn't a directory without showing a delta" case.
 
2236
            partial_history = revision and b.repository._format.supports_chks
 
2237
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2238
                or delta_type or partial_history)
 
2239
 
 
2240
            # Build the LogRequest and execute it
 
2241
            if len(file_ids) == 0:
 
2242
                file_ids = None
 
2243
            rqst = make_log_request_dict(
 
2244
                direction=direction, specific_fileids=file_ids,
 
2245
                start_revision=rev1, end_revision=rev2, limit=limit,
 
2246
                message_search=message, delta_type=delta_type,
 
2247
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2248
            Logger(b, rqst).show(lf)
1728
2249
        finally:
1729
2250
            b.unlock()
1730
2251
 
1731
2252
 
 
2253
def _get_revision_range(revisionspec_list, branch, command_name):
 
2254
    """Take the input of a revision option and turn it into a revision range.
 
2255
 
 
2256
    It returns RevisionInfo objects which can be used to obtain the rev_id's
 
2257
    of the desired revisions. It does some user input validations.
 
2258
    """
 
2259
    if revisionspec_list is None:
 
2260
        rev1 = None
 
2261
        rev2 = None
 
2262
    elif len(revisionspec_list) == 1:
 
2263
        rev1 = rev2 = revisionspec_list[0].in_history(branch)
 
2264
    elif len(revisionspec_list) == 2:
 
2265
        start_spec = revisionspec_list[0]
 
2266
        end_spec = revisionspec_list[1]
 
2267
        if end_spec.get_branch() != start_spec.get_branch():
 
2268
            # b is taken from revision[0].get_branch(), and
 
2269
            # show_log will use its revision_history. Having
 
2270
            # different branches will lead to weird behaviors.
 
2271
            raise errors.BzrCommandError(
 
2272
                "bzr %s doesn't accept two revisions in different"
 
2273
                " branches." % command_name)
 
2274
        rev1 = start_spec.in_history(branch)
 
2275
        # Avoid loading all of history when we know a missing
 
2276
        # end of range means the last revision ...
 
2277
        if end_spec.spec is None:
 
2278
            last_revno, last_revision_id = branch.last_revision_info()
 
2279
            rev2 = RevisionInfo(branch, last_revno, last_revision_id)
 
2280
        else:
 
2281
            rev2 = end_spec.in_history(branch)
 
2282
    else:
 
2283
        raise errors.BzrCommandError(
 
2284
            'bzr %s --revision takes one or two values.' % command_name)
 
2285
    return rev1, rev2
 
2286
 
 
2287
 
 
2288
def _revision_range_to_revid_range(revision_range):
 
2289
    rev_id1 = None
 
2290
    rev_id2 = None
 
2291
    if revision_range[0] is not None:
 
2292
        rev_id1 = revision_range[0].rev_id
 
2293
    if revision_range[1] is not None:
 
2294
        rev_id2 = revision_range[1].rev_id
 
2295
    return rev_id1, rev_id2
 
2296
 
1732
2297
def get_log_format(long=False, short=False, line=False, default='long'):
1733
2298
    log_format = default
1734
2299
    if long:
1764
2329
 
1765
2330
    _see_also = ['status', 'cat']
1766
2331
    takes_args = ['path?']
1767
 
    # TODO: Take a revision or remote path and list that tree instead.
1768
2332
    takes_options = [
1769
2333
            'verbose',
1770
2334
            'revision',
1771
 
            Option('non-recursive',
1772
 
                   help='Don\'t recurse into subdirectories.'),
 
2335
            Option('recursive', short_name='R',
 
2336
                   help='Recurse into subdirectories.'),
1773
2337
            Option('from-root',
1774
2338
                   help='Print paths relative to the root of the branch.'),
1775
2339
            Option('unknown', help='Print unknown files.'),
1776
 
            Option('versioned', help='Print versioned files.'),
 
2340
            Option('versioned', help='Print versioned files.',
 
2341
                   short_name='V'),
1777
2342
            Option('ignored', help='Print ignored files.'),
1778
2343
            Option('null',
1779
2344
                   help='Write an ascii NUL (\\0) separator '
1785
2350
            ]
1786
2351
    @display_command
1787
2352
    def run(self, revision=None, verbose=False,
1788
 
            non_recursive=False, from_root=False,
 
2353
            recursive=False, from_root=False,
1789
2354
            unknown=False, versioned=False, ignored=False,
1790
2355
            null=False, kind=None, show_ids=False, path=None):
1791
2356
 
1813
2378
            relpath = u''
1814
2379
        elif relpath:
1815
2380
            relpath += '/'
1816
 
        if revision is not None:
1817
 
            tree = branch.repository.revision_tree(
1818
 
                revision[0].in_history(branch).rev_id)
1819
 
        elif tree is None:
1820
 
            tree = branch.basis_tree()
 
2381
        if revision is not None or tree is None:
 
2382
            tree = _get_one_revision_tree('ls', revision, branch=branch)
 
2383
 
 
2384
        apply_view = False
 
2385
        if isinstance(tree, WorkingTree) and tree.supports_views():
 
2386
            view_files = tree.views.lookup_view()
 
2387
            if view_files:
 
2388
                apply_view = True
 
2389
                view_str = views.view_display_str(view_files)
 
2390
                note("Ignoring files outside view. View is %s" % view_str)
1821
2391
 
1822
2392
        tree.lock_read()
1823
2393
        try:
1824
2394
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
1825
2395
                if fp.startswith(relpath):
1826
 
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
1827
 
                    if non_recursive and '/' in fp:
 
2396
                    rp = fp[len(relpath):]
 
2397
                    fp = osutils.pathjoin(prefix, rp)
 
2398
                    if not recursive and '/' in rp:
1828
2399
                        continue
1829
2400
                    if not all and not selection[fc]:
1830
2401
                        continue
1831
2402
                    if kind is not None and fkind != kind:
1832
2403
                        continue
 
2404
                    if apply_view:
 
2405
                        try:
 
2406
                            views.check_path_in_view(tree, fp)
 
2407
                        except errors.FileOutsideView:
 
2408
                            continue
 
2409
                    kindch = entry.kind_character()
 
2410
                    outstring = fp + kindch
1833
2411
                    if verbose:
1834
 
                        kindch = entry.kind_character()
1835
 
                        outstring = '%-8s %s%s' % (fc, fp, kindch)
 
2412
                        outstring = '%-8s %s' % (fc, outstring)
1836
2413
                        if show_ids and fid is not None:
1837
2414
                            outstring = "%-50s %s" % (outstring, fid)
1838
2415
                        self.outf.write(outstring + '\n')
1849
2426
                        else:
1850
2427
                            my_id = ''
1851
2428
                        if show_ids:
1852
 
                            self.outf.write('%-50s %s\n' % (fp, my_id))
 
2429
                            self.outf.write('%-50s %s\n' % (outstring, my_id))
1853
2430
                        else:
1854
 
                            self.outf.write(fp + '\n')
 
2431
                            self.outf.write(outstring + '\n')
1855
2432
        finally:
1856
2433
            tree.unlock()
1857
2434
 
1872
2449
class cmd_ignore(Command):
1873
2450
    """Ignore specified files or patterns.
1874
2451
 
 
2452
    See ``bzr help patterns`` for details on the syntax of patterns.
 
2453
 
1875
2454
    To remove patterns from the ignore list, edit the .bzrignore file.
1876
 
 
1877
 
    Trailing slashes on patterns are ignored. 
1878
 
    If the pattern contains a slash or is a regular expression, it is compared 
1879
 
    to the whole path from the branch root.  Otherwise, it is compared to only
1880
 
    the last component of the path.  To match a file only in the root 
1881
 
    directory, prepend './'.
1882
 
 
1883
 
    Ignore patterns specifying absolute paths are not allowed.
1884
 
 
1885
 
    Ignore patterns may include globbing wildcards such as::
1886
 
 
1887
 
      ? - Matches any single character except '/'
1888
 
      * - Matches 0 or more characters except '/'
1889
 
      /**/ - Matches 0 or more directories in a path
1890
 
      [a-z] - Matches a single character from within a group of characters
1891
 
 
1892
 
    Ignore patterns may also be Python regular expressions.  
1893
 
    Regular expression ignore patterns are identified by a 'RE:' prefix 
1894
 
    followed by the regular expression.  Regular expression ignore patterns
1895
 
    may not include named or numbered groups.
1896
 
 
1897
 
    Note: ignore patterns containing shell wildcards must be quoted from 
 
2455
    After adding, editing or deleting that file either indirectly by
 
2456
    using this command or directly by using an editor, be sure to commit
 
2457
    it.
 
2458
 
 
2459
    Note: ignore patterns containing shell wildcards must be quoted from
1898
2460
    the shell on Unix.
1899
2461
 
1900
2462
    :Examples:
1904
2466
 
1905
2467
        Ignore class files in all directories::
1906
2468
 
1907
 
            bzr ignore '*.class'
1908
 
 
1909
 
        Ignore .o files under the lib directory::
1910
 
 
1911
 
            bzr ignore 'lib/**/*.o'
1912
 
 
1913
 
        Ignore .o files under the lib directory::
1914
 
 
1915
 
            bzr ignore 'RE:lib/.*\.o'
 
2469
            bzr ignore "*.class"
 
2470
 
 
2471
        Ignore .o files under the lib directory::
 
2472
 
 
2473
            bzr ignore "lib/**/*.o"
 
2474
 
 
2475
        Ignore .o files under the lib directory::
 
2476
 
 
2477
            bzr ignore "RE:lib/.*\.o"
 
2478
 
 
2479
        Ignore everything but the "debian" toplevel directory::
 
2480
 
 
2481
            bzr ignore "RE:(?!debian/).*"
1916
2482
    """
1917
2483
 
1918
 
    _see_also = ['status', 'ignored']
 
2484
    _see_also = ['status', 'ignored', 'patterns']
1919
2485
    takes_args = ['name_pattern*']
1920
2486
    takes_options = [
1921
2487
        Option('old-default-rules',
1922
2488
               help='Write out the ignore rules bzr < 0.9 always used.')
1923
2489
        ]
1924
 
    
 
2490
 
1925
2491
    def run(self, name_pattern_list=None, old_default_rules=None):
1926
 
        from bzrlib.atomicfile import AtomicFile
 
2492
        from bzrlib import ignores
1927
2493
        if old_default_rules is not None:
1928
2494
            # dump the rules and exit
1929
2495
            for pattern in ignores.OLD_DEFAULTS:
1932
2498
        if not name_pattern_list:
1933
2499
            raise errors.BzrCommandError("ignore requires at least one "
1934
2500
                                  "NAME_PATTERN or --old-default-rules")
1935
 
        name_pattern_list = [globbing.normalize_pattern(p) 
 
2501
        name_pattern_list = [globbing.normalize_pattern(p)
1936
2502
                             for p in name_pattern_list]
1937
2503
        for name_pattern in name_pattern_list:
1938
 
            if (name_pattern[0] == '/' or 
 
2504
            if (name_pattern[0] == '/' or
1939
2505
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
1940
2506
                raise errors.BzrCommandError(
1941
2507
                    "NAME_PATTERN should not be an absolute path")
1942
2508
        tree, relpath = WorkingTree.open_containing(u'.')
1943
 
        ifn = tree.abspath('.bzrignore')
1944
 
        if os.path.exists(ifn):
1945
 
            f = open(ifn, 'rt')
1946
 
            try:
1947
 
                igns = f.read().decode('utf-8')
1948
 
            finally:
1949
 
                f.close()
1950
 
        else:
1951
 
            igns = ''
1952
 
 
1953
 
        # TODO: If the file already uses crlf-style termination, maybe
1954
 
        # we should use that for the newly added lines?
1955
 
 
1956
 
        if igns and igns[-1] != '\n':
1957
 
            igns += '\n'
1958
 
        for name_pattern in name_pattern_list:
1959
 
            igns += name_pattern + '\n'
1960
 
 
1961
 
        f = AtomicFile(ifn, 'wb')
1962
 
        try:
1963
 
            f.write(igns.encode('utf-8'))
1964
 
            f.commit()
1965
 
        finally:
1966
 
            f.close()
1967
 
 
1968
 
        if not tree.path2id('.bzrignore'):
1969
 
            tree.add(['.bzrignore'])
 
2509
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
 
2510
        ignored = globbing.Globster(name_pattern_list)
 
2511
        matches = []
 
2512
        tree.lock_read()
 
2513
        for entry in tree.list_files():
 
2514
            id = entry[3]
 
2515
            if id is not None:
 
2516
                filename = entry[0]
 
2517
                if ignored.match(filename):
 
2518
                    matches.append(filename.encode('utf-8'))
 
2519
        tree.unlock()
 
2520
        if len(matches) > 0:
 
2521
            print "Warning: the following files are version controlled and" \
 
2522
                  " match your ignore pattern:\n%s" \
 
2523
                  "\nThese files will continue to be version controlled" \
 
2524
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
1970
2525
 
1971
2526
 
1972
2527
class cmd_ignored(Command):
1973
2528
    """List ignored files and the patterns that matched them.
 
2529
 
 
2530
    List all the ignored files and the ignore pattern that caused the file to
 
2531
    be ignored.
 
2532
 
 
2533
    Alternatively, to list just the files::
 
2534
 
 
2535
        bzr ls --ignored
1974
2536
    """
1975
2537
 
1976
 
    _see_also = ['ignore']
 
2538
    encoding_type = 'replace'
 
2539
    _see_also = ['ignore', 'ls']
 
2540
 
1977
2541
    @display_command
1978
2542
    def run(self):
1979
2543
        tree = WorkingTree.open_containing(u'.')[0]
1984
2548
                    continue
1985
2549
                ## XXX: Slightly inefficient since this was already calculated
1986
2550
                pat = tree.is_ignored(path)
1987
 
                print '%-50s %s' % (path, pat)
 
2551
                self.outf.write('%-50s %s\n' % (path, pat))
1988
2552
        finally:
1989
2553
            tree.unlock()
1990
2554
 
1997
2561
    """
1998
2562
    hidden = True
1999
2563
    takes_args = ['revno']
2000
 
    
 
2564
 
2001
2565
    @display_command
2002
2566
    def run(self, revno):
2003
2567
        try:
2036
2600
         zip                          .zip
2037
2601
      =================       =========================
2038
2602
    """
2039
 
    takes_args = ['dest', 'branch?']
 
2603
    takes_args = ['dest', 'branch_or_subdir?']
2040
2604
    takes_options = [
2041
2605
        Option('format',
2042
2606
               help="Type of file to export to.",
2043
2607
               type=unicode),
2044
2608
        'revision',
 
2609
        Option('filters', help='Apply content filters to export the '
 
2610
                'convenient form.'),
2045
2611
        Option('root',
2046
2612
               type=str,
2047
2613
               help="Name of the root directory inside the exported file."),
2048
2614
        ]
2049
 
    def run(self, dest, branch=None, revision=None, format=None, root=None):
 
2615
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
 
2616
        root=None, filters=False):
2050
2617
        from bzrlib.export import export
2051
2618
 
2052
 
        if branch is None:
 
2619
        if branch_or_subdir is None:
2053
2620
            tree = WorkingTree.open_containing(u'.')[0]
2054
2621
            b = tree.branch
2055
 
        else:
2056
 
            b = Branch.open(branch)
2057
 
            
2058
 
        if revision is None:
2059
 
            # should be tree.last_revision  FIXME
2060
 
            rev_id = b.last_revision()
2061
 
        else:
2062
 
            if len(revision) != 1:
2063
 
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2064
 
            rev_id = revision[0].in_history(b).rev_id
2065
 
        t = b.repository.revision_tree(rev_id)
 
2622
            subdir = None
 
2623
        else:
 
2624
            b, subdir = Branch.open_containing(branch_or_subdir)
 
2625
            tree = None
 
2626
 
 
2627
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2066
2628
        try:
2067
 
            export(t, dest, format, root)
 
2629
            export(rev_tree, dest, format, root, subdir, filtered=filters)
2068
2630
        except errors.NoSuchExportFormat, e:
2069
2631
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2070
2632
 
2075
2637
    If no revision is nominated, the last revision is used.
2076
2638
 
2077
2639
    Note: Take care to redirect standard output when using this command on a
2078
 
    binary file. 
 
2640
    binary file.
2079
2641
    """
2080
2642
 
2081
2643
    _see_also = ['ls']
2082
2644
    takes_options = [
2083
2645
        Option('name-from-revision', help='The path name in the old tree.'),
 
2646
        Option('filters', help='Apply content filters to display the '
 
2647
                'convenience form.'),
2084
2648
        'revision',
2085
2649
        ]
2086
2650
    takes_args = ['filename']
2087
2651
    encoding_type = 'exact'
2088
2652
 
2089
2653
    @display_command
2090
 
    def run(self, filename, revision=None, name_from_revision=False):
 
2654
    def run(self, filename, revision=None, name_from_revision=False,
 
2655
            filters=False):
2091
2656
        if revision is not None and len(revision) != 1:
2092
2657
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2093
 
                                        " one number")
2094
 
 
2095
 
        tree = None
 
2658
                                         " one revision specifier")
 
2659
        tree, branch, relpath = \
 
2660
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
2661
        branch.lock_read()
2096
2662
        try:
2097
 
            tree, b, relpath = \
2098
 
                    bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2099
 
        except errors.NotBranchError:
2100
 
            pass
 
2663
            return self._run(tree, branch, relpath, filename, revision,
 
2664
                             name_from_revision, filters)
 
2665
        finally:
 
2666
            branch.unlock()
2101
2667
 
2102
 
        if revision is not None and revision[0].get_branch() is not None:
2103
 
            b = Branch.open(revision[0].get_branch())
 
2668
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
 
2669
        filtered):
2104
2670
        if tree is None:
2105
2671
            tree = b.basis_tree()
2106
 
        if revision is None:
2107
 
            revision_id = b.last_revision()
2108
 
        else:
2109
 
            revision_id = revision[0].in_history(b).rev_id
 
2672
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2110
2673
 
2111
 
        cur_file_id = tree.path2id(relpath)
2112
 
        rev_tree = b.repository.revision_tree(revision_id)
2113
2674
        old_file_id = rev_tree.path2id(relpath)
2114
 
        
 
2675
 
2115
2676
        if name_from_revision:
 
2677
            # Try in revision if requested
2116
2678
            if old_file_id is None:
2117
 
                raise errors.BzrCommandError("%r is not present in revision %s"
2118
 
                                                % (filename, revision_id))
 
2679
                raise errors.BzrCommandError(
 
2680
                    "%r is not present in revision %s" % (
 
2681
                        filename, rev_tree.get_revision_id()))
2119
2682
            else:
2120
 
                rev_tree.print_file(old_file_id)
2121
 
        elif cur_file_id is not None:
2122
 
            rev_tree.print_file(cur_file_id)
2123
 
        elif old_file_id is not None:
2124
 
            rev_tree.print_file(old_file_id)
2125
 
        else:
2126
 
            raise errors.BzrCommandError("%r is not present in revision %s" %
2127
 
                                         (filename, revision_id))
 
2683
                content = rev_tree.get_file_text(old_file_id)
 
2684
        else:
 
2685
            cur_file_id = tree.path2id(relpath)
 
2686
            found = False
 
2687
            if cur_file_id is not None:
 
2688
                # Then try with the actual file id
 
2689
                try:
 
2690
                    content = rev_tree.get_file_text(cur_file_id)
 
2691
                    found = True
 
2692
                except errors.NoSuchId:
 
2693
                    # The actual file id didn't exist at that time
 
2694
                    pass
 
2695
            if not found and old_file_id is not None:
 
2696
                # Finally try with the old file id
 
2697
                content = rev_tree.get_file_text(old_file_id)
 
2698
                found = True
 
2699
            if not found:
 
2700
                # Can't be found anywhere
 
2701
                raise errors.BzrCommandError(
 
2702
                    "%r is not present in revision %s" % (
 
2703
                        filename, rev_tree.get_revision_id()))
 
2704
        if filtered:
 
2705
            from bzrlib.filters import (
 
2706
                ContentFilterContext,
 
2707
                filtered_output_bytes,
 
2708
                )
 
2709
            filters = rev_tree._content_filter_stack(relpath)
 
2710
            chunks = content.splitlines(True)
 
2711
            content = filtered_output_bytes(chunks, filters,
 
2712
                ContentFilterContext(relpath, rev_tree))
 
2713
            self.outf.writelines(content)
 
2714
        else:
 
2715
            self.outf.write(content)
2128
2716
 
2129
2717
 
2130
2718
class cmd_local_time_offset(Command):
2131
2719
    """Show the offset in seconds from GMT to local time."""
2132
 
    hidden = True    
 
2720
    hidden = True
2133
2721
    @display_command
2134
2722
    def run(self):
2135
2723
        print osutils.local_time_offset()
2138
2726
 
2139
2727
class cmd_commit(Command):
2140
2728
    """Commit changes into a new revision.
2141
 
    
2142
 
    If no arguments are given, the entire tree is committed.
2143
 
 
2144
 
    If selected files are specified, only changes to those files are
2145
 
    committed.  If a directory is specified then the directory and everything 
2146
 
    within it is committed.
2147
 
 
2148
 
    A selected-file commit may fail in some cases where the committed
2149
 
    tree would be invalid. Consider::
2150
 
 
2151
 
      bzr init foo
2152
 
      mkdir foo/bar
2153
 
      bzr add foo/bar
2154
 
      bzr commit foo -m "committing foo"
2155
 
      bzr mv foo/bar foo/baz
2156
 
      mkdir foo/bar
2157
 
      bzr add foo/bar
2158
 
      bzr commit foo/bar -m "committing bar but not baz"
2159
 
 
2160
 
    In the example above, the last commit will fail by design. This gives
2161
 
    the user the opportunity to decide whether they want to commit the
2162
 
    rename at the same time, separately first, or not at all. (As a general
2163
 
    rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2164
 
 
2165
 
    Note: A selected-file commit after a merge is not yet supported.
 
2729
 
 
2730
    An explanatory message needs to be given for each commit. This is
 
2731
    often done by using the --message option (getting the message from the
 
2732
    command line) or by using the --file option (getting the message from
 
2733
    a file). If neither of these options is given, an editor is opened for
 
2734
    the user to enter the message. To see the changed files in the
 
2735
    boilerplate text loaded into the editor, use the --show-diff option.
 
2736
 
 
2737
    By default, the entire tree is committed and the person doing the
 
2738
    commit is assumed to be the author. These defaults can be overridden
 
2739
    as explained below.
 
2740
 
 
2741
    :Selective commits:
 
2742
 
 
2743
      If selected files are specified, only changes to those files are
 
2744
      committed.  If a directory is specified then the directory and
 
2745
      everything within it is committed.
 
2746
  
 
2747
      When excludes are given, they take precedence over selected files.
 
2748
      For example, to commit only changes within foo, but not changes
 
2749
      within foo/bar::
 
2750
  
 
2751
        bzr commit foo -x foo/bar
 
2752
  
 
2753
      A selective commit after a merge is not yet supported.
 
2754
 
 
2755
    :Custom authors:
 
2756
 
 
2757
      If the author of the change is not the same person as the committer,
 
2758
      you can specify the author's name using the --author option. The
 
2759
      name should be in the same format as a committer-id, e.g.
 
2760
      "John Doe <jdoe@example.com>". If there is more than one author of
 
2761
      the change you can specify the option multiple times, once for each
 
2762
      author.
 
2763
  
 
2764
    :Checks:
 
2765
 
 
2766
      A common mistake is to forget to add a new file or directory before
 
2767
      running the commit command. The --strict option checks for unknown
 
2768
      files and aborts the commit if any are found. More advanced pre-commit
 
2769
      checks can be implemented by defining hooks. See ``bzr help hooks``
 
2770
      for details.
 
2771
 
 
2772
    :Things to note:
 
2773
 
 
2774
      If you accidentially commit the wrong changes or make a spelling
 
2775
      mistake in the commit message say, you can use the uncommit command
 
2776
      to undo it. See ``bzr help uncommit`` for details.
 
2777
 
 
2778
      Hooks can also be configured to run after a commit. This allows you
 
2779
      to trigger updates to external systems like bug trackers. The --fixes
 
2780
      option can be used to record the association between a revision and
 
2781
      one or more bugs. See ``bzr help bugs`` for details.
 
2782
 
 
2783
      A selective commit may fail in some cases where the committed
 
2784
      tree would be invalid. Consider::
 
2785
  
 
2786
        bzr init foo
 
2787
        mkdir foo/bar
 
2788
        bzr add foo/bar
 
2789
        bzr commit foo -m "committing foo"
 
2790
        bzr mv foo/bar foo/baz
 
2791
        mkdir foo/bar
 
2792
        bzr add foo/bar
 
2793
        bzr commit foo/bar -m "committing bar but not baz"
 
2794
  
 
2795
      In the example above, the last commit will fail by design. This gives
 
2796
      the user the opportunity to decide whether they want to commit the
 
2797
      rename at the same time, separately first, or not at all. (As a general
 
2798
      rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2166
2799
    """
2167
2800
    # TODO: Run hooks on tree to-be-committed, and after commit.
2168
2801
 
2173
2806
 
2174
2807
    # XXX: verbose currently does nothing
2175
2808
 
2176
 
    _see_also = ['bugs', 'uncommit']
 
2809
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
2177
2810
    takes_args = ['selected*']
2178
2811
    takes_options = [
 
2812
            ListOption('exclude', type=str, short_name='x',
 
2813
                help="Do not consider changes made to a given path."),
2179
2814
            Option('message', type=unicode,
2180
2815
                   short_name='m',
2181
2816
                   help="Description of the new revision."),
2190
2825
                    help="Refuse to commit if there are unknown "
2191
2826
                    "files in the working tree."),
2192
2827
             ListOption('fixes', type=str,
2193
 
                    help="Mark a bug as being fixed by this revision."),
 
2828
                    help="Mark a bug as being fixed by this revision "
 
2829
                         "(see \"bzr help bugs\")."),
 
2830
             ListOption('author', type=unicode,
 
2831
                    help="Set the author's name, if it's different "
 
2832
                         "from the committer."),
2194
2833
             Option('local',
2195
2834
                    help="Perform a local commit in a bound "
2196
2835
                         "branch.  Local commits are not pushed to "
2197
2836
                         "the master branch until a normal commit "
2198
2837
                         "is performed."
2199
2838
                    ),
 
2839
              Option('show-diff',
 
2840
                     help='When no message is supplied, show the diff along'
 
2841
                     ' with the status summary in the message editor.'),
2200
2842
             ]
2201
2843
    aliases = ['ci', 'checkin']
2202
2844
 
2203
 
    def _get_bug_fix_properties(self, fixes, branch):
2204
 
        properties = []
 
2845
    def _iter_bug_fix_urls(self, fixes, branch):
2205
2846
        # Configure the properties for bug fixing attributes.
2206
2847
        for fixed_bug in fixes:
2207
2848
            tokens = fixed_bug.split(':')
2208
2849
            if len(tokens) != 2:
2209
2850
                raise errors.BzrCommandError(
2210
 
                    "Invalid bug %s. Must be in the form of 'tag:id'. "
2211
 
                    "Commit refused." % fixed_bug)
 
2851
                    "Invalid bug %s. Must be in the form of 'tracker:id'. "
 
2852
                    "See \"bzr help bugs\" for more information on this "
 
2853
                    "feature.\nCommit refused." % fixed_bug)
2212
2854
            tag, bug_id = tokens
2213
2855
            try:
2214
 
                bug_url = bugtracker.get_bug_url(tag, branch, bug_id)
 
2856
                yield bugtracker.get_bug_url(tag, branch, bug_id)
2215
2857
            except errors.UnknownBugTrackerAbbreviation:
2216
2858
                raise errors.BzrCommandError(
2217
2859
                    'Unrecognized bug %s. Commit refused.' % fixed_bug)
2218
 
            except errors.MalformedBugIdentifier:
 
2860
            except errors.MalformedBugIdentifier, e:
2219
2861
                raise errors.BzrCommandError(
2220
 
                    "Invalid bug identifier for %s. Commit refused."
2221
 
                    % fixed_bug)
2222
 
            properties.append('%s fixed' % bug_url)
2223
 
        return '\n'.join(properties)
 
2862
                    "%s\nCommit refused." % (str(e),))
2224
2863
 
2225
 
    def run(self, message=None, file=None, verbose=True, selected_list=None,
2226
 
            unchanged=False, strict=False, local=False, fixes=None):
2227
 
        from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
2228
 
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
2229
 
                StrictCommitFailed)
2230
 
        from bzrlib.msgeditor import edit_commit_message, \
2231
 
                make_commit_message_template
 
2864
    def run(self, message=None, file=None, verbose=False, selected_list=None,
 
2865
            unchanged=False, strict=False, local=False, fixes=None,
 
2866
            author=None, show_diff=False, exclude=None):
 
2867
        from bzrlib.errors import (
 
2868
            PointlessCommit,
 
2869
            ConflictsInTree,
 
2870
            StrictCommitFailed
 
2871
        )
 
2872
        from bzrlib.msgeditor import (
 
2873
            edit_commit_message_encoded,
 
2874
            generate_commit_message_template,
 
2875
            make_commit_message_template_encoded
 
2876
        )
2232
2877
 
2233
2878
        # TODO: Need a blackbox test for invoking the external editor; may be
2234
2879
        # slightly problematic to run this cross-platform.
2235
2880
 
2236
 
        # TODO: do more checks that the commit will succeed before 
 
2881
        # TODO: do more checks that the commit will succeed before
2237
2882
        # spending the user's valuable time typing a commit message.
2238
2883
 
2239
2884
        properties = {}
2245
2890
            # selected-file merge commit is not done yet
2246
2891
            selected_list = []
2247
2892
 
2248
 
        bug_property = self._get_bug_fix_properties(fixes, tree.branch)
 
2893
        if fixes is None:
 
2894
            fixes = []
 
2895
        bug_property = bugtracker.encode_fixes_bug_urls(
 
2896
            self._iter_bug_fix_urls(fixes, tree.branch))
2249
2897
        if bug_property:
2250
2898
            properties['bugs'] = bug_property
2251
2899
 
2256
2904
            """Callback to get commit message"""
2257
2905
            my_message = message
2258
2906
            if my_message is None and not file:
2259
 
                template = make_commit_message_template(tree, selected_list)
2260
 
                my_message = edit_commit_message(template)
 
2907
                t = make_commit_message_template_encoded(tree,
 
2908
                        selected_list, diff=show_diff,
 
2909
                        output_encoding=osutils.get_user_encoding())
 
2910
                start_message = generate_commit_message_template(commit_obj)
 
2911
                my_message = edit_commit_message_encoded(t,
 
2912
                    start_message=start_message)
2261
2913
                if my_message is None:
2262
2914
                    raise errors.BzrCommandError("please specify a commit"
2263
2915
                        " message with either --message or --file")
2265
2917
                raise errors.BzrCommandError(
2266
2918
                    "please specify either --message or --file")
2267
2919
            if file:
2268
 
                my_message = codecs.open(file, 'rt', 
2269
 
                                         bzrlib.user_encoding).read()
 
2920
                my_message = codecs.open(file, 'rt',
 
2921
                                         osutils.get_user_encoding()).read()
2270
2922
            if my_message == "":
2271
2923
                raise errors.BzrCommandError("empty commit message specified")
2272
2924
            return my_message
2273
2925
 
2274
 
        if verbose:
2275
 
            reporter = ReportCommitToLog()
2276
 
        else:
2277
 
            reporter = NullCommitReporter()
2278
 
 
2279
2926
        try:
2280
2927
            tree.commit(message_callback=get_message,
2281
2928
                        specific_files=selected_list,
2282
2929
                        allow_pointless=unchanged, strict=strict, local=local,
2283
 
                        reporter=reporter, revprops=properties)
 
2930
                        reporter=None, verbose=verbose, revprops=properties,
 
2931
                        authors=author,
 
2932
                        exclude=safe_relpath_files(tree, exclude))
2284
2933
        except PointlessCommit:
2285
2934
            # FIXME: This should really happen before the file is read in;
2286
2935
            # perhaps prepare the commit; get the message; then actually commit
2287
 
            raise errors.BzrCommandError("no changes to commit."
2288
 
                              " use --unchanged to commit anyhow")
 
2936
            raise errors.BzrCommandError("No changes to commit."
 
2937
                              " Use --unchanged to commit anyhow.")
2289
2938
        except ConflictsInTree:
2290
2939
            raise errors.BzrCommandError('Conflicts detected in working '
2291
2940
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
2301
2950
 
2302
2951
 
2303
2952
class cmd_check(Command):
2304
 
    """Validate consistency of branch history.
2305
 
 
2306
 
    This command checks various invariants about the branch storage to
2307
 
    detect data corruption or bzr bugs.
 
2953
    """Validate working tree structure, branch consistency and repository history.
 
2954
 
 
2955
    This command checks various invariants about branch and repository storage
 
2956
    to detect data corruption or bzr bugs.
 
2957
 
 
2958
    The working tree and branch checks will only give output if a problem is
 
2959
    detected. The output fields of the repository check are:
 
2960
 
 
2961
        revisions: This is just the number of revisions checked.  It doesn't
 
2962
            indicate a problem.
 
2963
        versionedfiles: This is just the number of versionedfiles checked.  It
 
2964
            doesn't indicate a problem.
 
2965
        unreferenced ancestors: Texts that are ancestors of other texts, but
 
2966
            are not properly referenced by the revision ancestry.  This is a
 
2967
            subtle problem that Bazaar can work around.
 
2968
        unique file texts: This is the total number of unique file contents
 
2969
            seen in the checked revisions.  It does not indicate a problem.
 
2970
        repeated file texts: This is the total number of repeated texts seen
 
2971
            in the checked revisions.  Texts can be repeated when their file
 
2972
            entries are modified, but the file contents are not.  It does not
 
2973
            indicate a problem.
 
2974
 
 
2975
    If no restrictions are specified, all Bazaar data that is found at the given
 
2976
    location will be checked.
 
2977
 
 
2978
    :Examples:
 
2979
 
 
2980
        Check the tree and branch at 'foo'::
 
2981
 
 
2982
            bzr check --tree --branch foo
 
2983
 
 
2984
        Check only the repository at 'bar'::
 
2985
 
 
2986
            bzr check --repo bar
 
2987
 
 
2988
        Check everything at 'baz'::
 
2989
 
 
2990
            bzr check baz
2308
2991
    """
2309
2992
 
2310
2993
    _see_also = ['reconcile']
2311
 
    takes_args = ['branch?']
2312
 
    takes_options = ['verbose']
 
2994
    takes_args = ['path?']
 
2995
    takes_options = ['verbose',
 
2996
                     Option('branch', help="Check the branch related to the"
 
2997
                                           " current directory."),
 
2998
                     Option('repo', help="Check the repository related to the"
 
2999
                                         " current directory."),
 
3000
                     Option('tree', help="Check the working tree related to"
 
3001
                                         " the current directory.")]
2313
3002
 
2314
 
    def run(self, branch=None, verbose=False):
2315
 
        from bzrlib.check import check
2316
 
        if branch is None:
2317
 
            tree = WorkingTree.open_containing()[0]
2318
 
            branch = tree.branch
2319
 
        else:
2320
 
            branch = Branch.open(branch)
2321
 
        check(branch, verbose)
 
3003
    def run(self, path=None, verbose=False, branch=False, repo=False,
 
3004
            tree=False):
 
3005
        from bzrlib.check import check_dwim
 
3006
        if path is None:
 
3007
            path = '.'
 
3008
        if not branch and not repo and not tree:
 
3009
            branch = repo = tree = True
 
3010
        check_dwim(path, verbose, do_branch=branch, do_repo=repo, do_tree=tree)
2322
3011
 
2323
3012
 
2324
3013
class cmd_upgrade(Command):
2335
3024
                    RegistryOption('format',
2336
3025
                        help='Upgrade to a specific format.  See "bzr help'
2337
3026
                             ' formats" for details.',
2338
 
                        registry=bzrdir.format_registry,
2339
 
                        converter=bzrdir.format_registry.make_bzrdir,
 
3027
                        lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
3028
                        converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
2340
3029
                        value_switches=True, title='Branch format'),
2341
3030
                    ]
2342
3031
 
2343
3032
    def run(self, url='.', format=None):
2344
3033
        from bzrlib.upgrade import upgrade
2345
 
        if format is None:
2346
 
            format = bzrdir.format_registry.make_bzrdir('default')
2347
3034
        upgrade(url, format)
2348
3035
 
2349
3036
 
2350
3037
class cmd_whoami(Command):
2351
3038
    """Show or set bzr user id.
2352
 
    
 
3039
 
2353
3040
    :Examples:
2354
3041
        Show the email of the current user::
2355
3042
 
2357
3044
 
2358
3045
        Set the current user::
2359
3046
 
2360
 
            bzr whoami 'Frank Chu <fchu@example.com>'
 
3047
            bzr whoami "Frank Chu <fchu@example.com>"
2361
3048
    """
2362
3049
    takes_options = [ Option('email',
2363
3050
                             help='Display email address only.'),
2367
3054
                    ]
2368
3055
    takes_args = ['name?']
2369
3056
    encoding_type = 'replace'
2370
 
    
 
3057
 
2371
3058
    @display_command
2372
3059
    def run(self, email=False, branch=False, name=None):
2373
3060
        if name is None:
2388
3075
        except errors.NoEmailInUsername, e:
2389
3076
            warning('"%s" does not seem to contain an email address.  '
2390
3077
                    'This is allowed, but not recommended.', name)
2391
 
        
 
3078
 
2392
3079
        # use global config unless --branch given
2393
3080
        if branch:
2394
3081
            c = Branch.open_containing('.')[0].get_config()
2398
3085
 
2399
3086
 
2400
3087
class cmd_nick(Command):
2401
 
    """Print or set the branch nickname.  
2402
 
 
2403
 
    If unset, the tree root directory name is used as the nickname
2404
 
    To print the current nickname, execute with no argument.  
 
3088
    """Print or set the branch nickname.
 
3089
 
 
3090
    If unset, the tree root directory name is used as the nickname.
 
3091
    To print the current nickname, execute with no argument.
 
3092
 
 
3093
    Bound branches use the nickname of its master branch unless it is set
 
3094
    locally.
2405
3095
    """
2406
3096
 
2407
3097
    _see_also = ['info']
2418
3108
        print branch.nick
2419
3109
 
2420
3110
 
 
3111
class cmd_alias(Command):
 
3112
    """Set/unset and display aliases.
 
3113
 
 
3114
    :Examples:
 
3115
        Show the current aliases::
 
3116
 
 
3117
            bzr alias
 
3118
 
 
3119
        Show the alias specified for 'll'::
 
3120
 
 
3121
            bzr alias ll
 
3122
 
 
3123
        Set an alias for 'll'::
 
3124
 
 
3125
            bzr alias ll="log --line -r-10..-1"
 
3126
 
 
3127
        To remove an alias for 'll'::
 
3128
 
 
3129
            bzr alias --remove ll
 
3130
 
 
3131
    """
 
3132
    takes_args = ['name?']
 
3133
    takes_options = [
 
3134
        Option('remove', help='Remove the alias.'),
 
3135
        ]
 
3136
 
 
3137
    def run(self, name=None, remove=False):
 
3138
        if remove:
 
3139
            self.remove_alias(name)
 
3140
        elif name is None:
 
3141
            self.print_aliases()
 
3142
        else:
 
3143
            equal_pos = name.find('=')
 
3144
            if equal_pos == -1:
 
3145
                self.print_alias(name)
 
3146
            else:
 
3147
                self.set_alias(name[:equal_pos], name[equal_pos+1:])
 
3148
 
 
3149
    def remove_alias(self, alias_name):
 
3150
        if alias_name is None:
 
3151
            raise errors.BzrCommandError(
 
3152
                'bzr alias --remove expects an alias to remove.')
 
3153
        # If alias is not found, print something like:
 
3154
        # unalias: foo: not found
 
3155
        c = config.GlobalConfig()
 
3156
        c.unset_alias(alias_name)
 
3157
 
 
3158
    @display_command
 
3159
    def print_aliases(self):
 
3160
        """Print out the defined aliases in a similar format to bash."""
 
3161
        aliases = config.GlobalConfig().get_aliases()
 
3162
        for key, value in sorted(aliases.iteritems()):
 
3163
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
 
3164
 
 
3165
    @display_command
 
3166
    def print_alias(self, alias_name):
 
3167
        from bzrlib.commands import get_alias
 
3168
        alias = get_alias(alias_name)
 
3169
        if alias is None:
 
3170
            self.outf.write("bzr alias: %s: not found\n" % alias_name)
 
3171
        else:
 
3172
            self.outf.write(
 
3173
                'bzr alias %s="%s"\n' % (alias_name, ' '.join(alias)))
 
3174
 
 
3175
    def set_alias(self, alias_name, alias_command):
 
3176
        """Save the alias in the global config."""
 
3177
        c = config.GlobalConfig()
 
3178
        c.set_alias(alias_name, alias_command)
 
3179
 
 
3180
 
2421
3181
class cmd_selftest(Command):
2422
3182
    """Run internal test suite.
2423
 
    
 
3183
 
2424
3184
    If arguments are given, they are regular expressions that say which tests
2425
3185
    should run.  Tests matching any expression are run, and other tests are
2426
3186
    not run.
2449
3209
    modified by plugins will not be tested, and tests provided by plugins will
2450
3210
    not be run.
2451
3211
 
2452
 
    Tests that need working space on disk use a common temporary directory, 
 
3212
    Tests that need working space on disk use a common temporary directory,
2453
3213
    typically inside $TMPDIR or /tmp.
2454
3214
 
2455
3215
    :Examples:
2503
3263
                            ),
2504
3264
                     Option('list-only',
2505
3265
                            help='List the tests instead of running them.'),
 
3266
                     RegistryOption('parallel',
 
3267
                        help="Run the test suite in parallel.",
 
3268
                        lazy_registry=('bzrlib.tests', 'parallel_registry'),
 
3269
                        value_switches=False,
 
3270
                        ),
2506
3271
                     Option('randomize', type=str, argname="SEED",
2507
3272
                            help='Randomize the order of tests using the given'
2508
3273
                                 ' seed or "now" for the current time.'),
2510
3275
                            short_name='x',
2511
3276
                            help='Exclude tests that match this regular'
2512
3277
                                 ' expression.'),
 
3278
                     Option('subunit',
 
3279
                        help='Output test progress via subunit.'),
2513
3280
                     Option('strict', help='Fail on missing dependencies or '
2514
3281
                            'known failures.'),
 
3282
                     Option('load-list', type=str, argname='TESTLISTFILE',
 
3283
                            help='Load a test id list from a text file.'),
 
3284
                     ListOption('debugflag', type=str, short_name='E',
 
3285
                                help='Turn on a selftest debug flag.'),
 
3286
                     ListOption('starting-with', type=str, argname='TESTID',
 
3287
                                param_name='starting_with', short_name='s',
 
3288
                                help=
 
3289
                                'Load only the tests starting with TESTID.'),
2515
3290
                     ]
2516
3291
    encoding_type = 'replace'
2517
3292
 
2518
 
    def run(self, testspecs_list=None, verbose=None, one=False,
 
3293
    def __init__(self):
 
3294
        Command.__init__(self)
 
3295
        self.additional_selftest_args = {}
 
3296
 
 
3297
    def run(self, testspecs_list=None, verbose=False, one=False,
2519
3298
            transport=None, benchmark=None,
2520
3299
            lsprof_timed=None, cache_dir=None,
2521
3300
            first=False, list_only=False,
2522
 
            randomize=None, exclude=None, strict=False):
2523
 
        import bzrlib.ui
 
3301
            randomize=None, exclude=None, strict=False,
 
3302
            load_list=None, debugflag=None, starting_with=None, subunit=False,
 
3303
            parallel=None):
2524
3304
        from bzrlib.tests import selftest
2525
3305
        import bzrlib.benchmarks as benchmarks
2526
3306
        from bzrlib.benchmarks import tree_creator
2527
 
        from bzrlib.version import show_version
 
3307
 
 
3308
        # Make deprecation warnings visible, unless -Werror is set
 
3309
        symbol_versioning.activate_deprecation_warnings(override=False)
2528
3310
 
2529
3311
        if cache_dir is not None:
2530
3312
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2531
 
        if not list_only:
2532
 
            show_version(show_config=False, show_copyright=False)
2533
 
        print
2534
3313
        if testspecs_list is not None:
2535
3314
            pattern = '|'.join(testspecs_list)
2536
3315
        else:
2537
3316
            pattern = ".*"
 
3317
        if subunit:
 
3318
            try:
 
3319
                from bzrlib.tests import SubUnitBzrRunner
 
3320
            except ImportError:
 
3321
                raise errors.BzrCommandError("subunit not available. subunit "
 
3322
                    "needs to be installed to use --subunit.")
 
3323
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
 
3324
        if parallel:
 
3325
            self.additional_selftest_args.setdefault(
 
3326
                'suite_decorators', []).append(parallel)
2538
3327
        if benchmark:
2539
3328
            test_suite_factory = benchmarks.test_suite
2540
 
            if verbose is None:
2541
 
                verbose = True
 
3329
            # Unless user explicitly asks for quiet, be verbose in benchmarks
 
3330
            verbose = not is_quiet()
2542
3331
            # TODO: should possibly lock the history file...
2543
3332
            benchfile = open(".perf_history", "at", buffering=1)
2544
3333
        else:
2545
3334
            test_suite_factory = None
2546
 
            if verbose is None:
2547
 
                verbose = False
2548
3335
            benchfile = None
2549
3336
        try:
2550
 
            result = selftest(verbose=verbose,
2551
 
                              pattern=pattern,
2552
 
                              stop_on_failure=one,
2553
 
                              transport=transport,
2554
 
                              test_suite_factory=test_suite_factory,
2555
 
                              lsprof_timed=lsprof_timed,
2556
 
                              bench_history=benchfile,
2557
 
                              matching_tests_first=first,
2558
 
                              list_only=list_only,
2559
 
                              random_seed=randomize,
2560
 
                              exclude_pattern=exclude,
2561
 
                              strict=strict,
2562
 
                              )
 
3337
            selftest_kwargs = {"verbose": verbose,
 
3338
                              "pattern": pattern,
 
3339
                              "stop_on_failure": one,
 
3340
                              "transport": transport,
 
3341
                              "test_suite_factory": test_suite_factory,
 
3342
                              "lsprof_timed": lsprof_timed,
 
3343
                              "bench_history": benchfile,
 
3344
                              "matching_tests_first": first,
 
3345
                              "list_only": list_only,
 
3346
                              "random_seed": randomize,
 
3347
                              "exclude_pattern": exclude,
 
3348
                              "strict": strict,
 
3349
                              "load_list": load_list,
 
3350
                              "debug_flags": debugflag,
 
3351
                              "starting_with": starting_with
 
3352
                              }
 
3353
            selftest_kwargs.update(self.additional_selftest_args)
 
3354
            result = selftest(**selftest_kwargs)
2563
3355
        finally:
2564
3356
            if benchfile is not None:
2565
3357
                benchfile.close()
2566
 
        if result:
2567
 
            info('tests passed')
2568
 
        else:
2569
 
            info('tests failed')
2570
3358
        return int(not result)
2571
3359
 
2572
3360
 
2573
3361
class cmd_version(Command):
2574
3362
    """Show version of bzr."""
2575
3363
 
 
3364
    encoding_type = 'replace'
 
3365
    takes_options = [
 
3366
        Option("short", help="Print just the version number."),
 
3367
        ]
 
3368
 
2576
3369
    @display_command
2577
 
    def run(self):
 
3370
    def run(self, short=False):
2578
3371
        from bzrlib.version import show_version
2579
 
        show_version()
 
3372
        if short:
 
3373
            self.outf.write(bzrlib.version_string + '\n')
 
3374
        else:
 
3375
            show_version(to_file=self.outf)
2580
3376
 
2581
3377
 
2582
3378
class cmd_rocks(Command):
2595
3391
    #       merging only part of the history.
2596
3392
    takes_args = ['branch', 'other']
2597
3393
    hidden = True
2598
 
    
 
3394
 
2599
3395
    @display_command
2600
3396
    def run(self, branch, other):
2601
 
        from bzrlib.revision import ensure_null, MultipleRevisionSources
2602
 
        
 
3397
        from bzrlib.revision import ensure_null
 
3398
 
2603
3399
        branch1 = Branch.open_containing(branch)[0]
2604
3400
        branch2 = Branch.open_containing(other)[0]
2605
 
 
2606
 
        last1 = ensure_null(branch1.last_revision())
2607
 
        last2 = ensure_null(branch2.last_revision())
2608
 
 
2609
 
        graph = branch1.repository.get_graph(branch2.repository)
2610
 
        base_rev_id = graph.find_unique_lca(last1, last2)
2611
 
 
2612
 
        print 'merge base is revision %s' % base_rev_id
 
3401
        branch1.lock_read()
 
3402
        try:
 
3403
            branch2.lock_read()
 
3404
            try:
 
3405
                last1 = ensure_null(branch1.last_revision())
 
3406
                last2 = ensure_null(branch2.last_revision())
 
3407
 
 
3408
                graph = branch1.repository.get_graph(branch2.repository)
 
3409
                base_rev_id = graph.find_unique_lca(last1, last2)
 
3410
 
 
3411
                print 'merge base is revision %s' % base_rev_id
 
3412
            finally:
 
3413
                branch2.unlock()
 
3414
        finally:
 
3415
            branch1.unlock()
2613
3416
 
2614
3417
 
2615
3418
class cmd_merge(Command):
2616
3419
    """Perform a three-way merge.
2617
 
    
2618
 
    The branch is the branch you will merge from.  By default, it will merge
2619
 
    the latest revision.  If you specify a revision, that revision will be
2620
 
    merged.  If you specify two revisions, the first will be used as a BASE,
2621
 
    and the second one as OTHER.  Revision numbers are always relative to the
2622
 
    specified branch.
 
3420
 
 
3421
    The source of the merge can be specified either in the form of a branch,
 
3422
    or in the form of a path to a file containing a merge directive generated
 
3423
    with bzr send. If neither is specified, the default is the upstream branch
 
3424
    or the branch most recently merged using --remember.
 
3425
 
 
3426
    When merging a branch, by default the tip will be merged. To pick a different
 
3427
    revision, pass --revision. If you specify two values, the first will be used as
 
3428
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
 
3429
    available revisions, like this is commonly referred to as "cherrypicking".
 
3430
 
 
3431
    Revision numbers are always relative to the branch being merged.
2623
3432
 
2624
3433
    By default, bzr will try to merge in all new work from the other
2625
3434
    branch, automatically determining an appropriate base.  If this
2626
3435
    fails, you may need to give an explicit base.
2627
 
    
 
3436
 
2628
3437
    Merge will do its best to combine the changes in two branches, but there
2629
3438
    are some kinds of problems only a human can fix.  When it encounters those,
2630
3439
    it will mark a conflict.  A conflict means that you need to fix something,
2640
3449
    The results of the merge are placed into the destination working
2641
3450
    directory, where they can be reviewed (with bzr diff), tested, and then
2642
3451
    committed to record the result of the merge.
2643
 
    
 
3452
 
2644
3453
    merge refuses to run if there are any uncommitted changes, unless
2645
3454
    --force is given.
2646
3455
 
2656
3465
        To merge the changes introduced by 82, without previous changes::
2657
3466
 
2658
3467
            bzr merge -r 81..82 ../bzr.dev
 
3468
 
 
3469
        To apply a merge directive contained in /tmp/merge:
 
3470
 
 
3471
            bzr merge /tmp/merge
2659
3472
    """
2660
3473
 
2661
 
    _see_also = ['update', 'remerge', 'status-flags']
2662
 
    takes_args = ['branch?']
 
3474
    encoding_type = 'exact'
 
3475
    _see_also = ['update', 'remerge', 'status-flags', 'send']
 
3476
    takes_args = ['location?']
2663
3477
    takes_options = [
 
3478
        'change',
2664
3479
        'revision',
2665
3480
        Option('force',
2666
3481
               help='Merge even if the destination tree has uncommitted changes.'),
2681
3496
               short_name='d',
2682
3497
               type=unicode,
2683
3498
               ),
 
3499
        Option('preview', help='Instead of merging, show a diff of the merge.')
2684
3500
    ]
2685
3501
 
2686
 
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2687
 
            show_base=False, reprocess=False, remember=False,
 
3502
    def run(self, location=None, revision=None, force=False,
 
3503
            merge_type=None, show_base=False, reprocess=None, remember=False,
2688
3504
            uncommitted=False, pull=False,
2689
3505
            directory=None,
 
3506
            preview=False,
2690
3507
            ):
2691
 
        from bzrlib.tag import _merge_tags_if_possible
2692
 
        # This is actually a branch (or merge-directive) *location*.
2693
 
        location = branch
2694
 
        del branch
2695
 
 
2696
3508
        if merge_type is None:
2697
3509
            merge_type = _mod_merge.Merge3Merger
2698
3510
 
2702
3514
        allow_pending = True
2703
3515
        verified = 'inapplicable'
2704
3516
        tree = WorkingTree.open_containing(directory)[0]
 
3517
 
 
3518
        # die as quickly as possible if there are uncommitted changes
 
3519
        try:
 
3520
            basis_tree = tree.revision_tree(tree.last_revision())
 
3521
        except errors.NoSuchRevision:
 
3522
            basis_tree = tree.basis_tree()
 
3523
        if not force:
 
3524
            changes = tree.changes_from(basis_tree)
 
3525
            if changes.has_changed():
 
3526
                raise errors.UncommittedChanges(tree)
 
3527
 
 
3528
        view_info = _get_view_info_for_change_reporter(tree)
2705
3529
        change_reporter = delta._ChangeReporter(
2706
 
            unversioned_filter=tree.is_ignored)
 
3530
            unversioned_filter=tree.is_ignored, view_info=view_info)
2707
3531
        cleanups = []
2708
3532
        try:
2709
3533
            pb = ui.ui_factory.nested_progress_bar()
2711
3535
            tree.lock_write()
2712
3536
            cleanups.append(tree.unlock)
2713
3537
            if location is not None:
2714
 
                mergeable, other_transport = _get_mergeable_helper(location)
2715
 
                if mergeable:
 
3538
                try:
 
3539
                    mergeable = bundle.read_mergeable_from_url(location,
 
3540
                        possible_transports=possible_transports)
 
3541
                except errors.NotABundle:
 
3542
                    mergeable = None
 
3543
                else:
2716
3544
                    if uncommitted:
2717
3545
                        raise errors.BzrCommandError('Cannot use --uncommitted'
2718
3546
                            ' with bundles or merge directives.')
2722
3550
                            'Cannot use -r with merge directives or bundles')
2723
3551
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
2724
3552
                       mergeable, pb)
2725
 
                possible_transports.append(other_transport)
2726
3553
 
2727
3554
            if merger is None and uncommitted:
2728
3555
                if revision is not None and len(revision) > 0:
2733
3560
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
2734
3561
                    pb)
2735
3562
                allow_pending = False
 
3563
                if other_path != '':
 
3564
                    merger.interesting_files = [other_path]
2736
3565
 
2737
3566
            if merger is None:
2738
3567
                merger, allow_pending = self._get_merger_from_branch(tree,
2741
3570
            merger.merge_type = merge_type
2742
3571
            merger.reprocess = reprocess
2743
3572
            merger.show_base = show_base
2744
 
            merger.change_reporter = change_reporter
2745
3573
            self.sanity_check_merger(merger)
2746
3574
            if (merger.base_rev_id == merger.other_rev_id and
2747
 
                merger.other_rev_id != None):
 
3575
                merger.other_rev_id is not None):
2748
3576
                note('Nothing to do.')
2749
3577
                return 0
2750
3578
            if pull:
2751
3579
                if merger.interesting_files is not None:
2752
 
                    raise BzrCommandError('Cannot pull individual files')
 
3580
                    raise errors.BzrCommandError('Cannot pull individual files')
2753
3581
                if (merger.base_rev_id == tree.last_revision()):
2754
3582
                    result = tree.pull(merger.other_branch, False,
2755
3583
                                       merger.other_rev_id)
2756
3584
                    result.report(self.outf)
2757
3585
                    return 0
2758
 
            merger.check_basis(not force)
2759
 
            conflict_count = merger.do_merge()
2760
 
            if allow_pending:
2761
 
                merger.set_pending()
2762
 
            if verified == 'failed':
2763
 
                warning('Preview patch does not match changes')
2764
 
            if conflict_count != 0:
2765
 
                return 1
 
3586
            merger.check_basis(False)
 
3587
            if preview:
 
3588
                return self._do_preview(merger)
2766
3589
            else:
2767
 
                return 0
 
3590
                return self._do_merge(merger, change_reporter, allow_pending,
 
3591
                                      verified)
2768
3592
        finally:
2769
3593
            for cleanup in reversed(cleanups):
2770
3594
                cleanup()
2771
3595
 
 
3596
    def _do_preview(self, merger):
 
3597
        from bzrlib.diff import show_diff_trees
 
3598
        tree_merger = merger.make_merger()
 
3599
        tt = tree_merger.make_preview_transform()
 
3600
        try:
 
3601
            result_tree = tt.get_preview_tree()
 
3602
            show_diff_trees(merger.this_tree, result_tree, self.outf,
 
3603
                            old_label='', new_label='')
 
3604
        finally:
 
3605
            tt.finalize()
 
3606
 
 
3607
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
 
3608
        merger.change_reporter = change_reporter
 
3609
        conflict_count = merger.do_merge()
 
3610
        if allow_pending:
 
3611
            merger.set_pending()
 
3612
        if verified == 'failed':
 
3613
            warning('Preview patch does not match changes')
 
3614
        if conflict_count != 0:
 
3615
            return 1
 
3616
        else:
 
3617
            return 0
 
3618
 
2772
3619
    def sanity_check_merger(self, merger):
2773
3620
        if (merger.show_base and
2774
3621
            not merger.merge_type is _mod_merge.Merge3Merger):
2775
3622
            raise errors.BzrCommandError("Show-base is not supported for this"
2776
3623
                                         " merge type. %s" % merger.merge_type)
 
3624
        if merger.reprocess is None:
 
3625
            if merger.show_base:
 
3626
                merger.reprocess = False
 
3627
            else:
 
3628
                # Use reprocess if the merger supports it
 
3629
                merger.reprocess = merger.merge_type.supports_reprocess
2777
3630
        if merger.reprocess and not merger.merge_type.supports_reprocess:
2778
3631
            raise errors.BzrCommandError("Conflict reduction is not supported"
2779
3632
                                         " for merge type %s." %
2786
3639
                                possible_transports, pb):
2787
3640
        """Produce a merger from a location, assuming it refers to a branch."""
2788
3641
        from bzrlib.tag import _merge_tags_if_possible
2789
 
        assert revision is None or len(revision) < 3
2790
3642
        # find the branch locations
2791
 
        other_loc, location = self._select_branch_location(tree, location,
 
3643
        other_loc, user_location = self._select_branch_location(tree, location,
2792
3644
            revision, -1)
2793
3645
        if revision is not None and len(revision) == 2:
2794
 
            base_loc, location = self._select_branch_location(tree, location,
2795
 
                                                              revision, 0)
 
3646
            base_loc, _unused = self._select_branch_location(tree,
 
3647
                location, revision, 0)
2796
3648
        else:
2797
3649
            base_loc = other_loc
2798
3650
        # Open the branches
2808
3660
            other_revision_id = _mod_revision.ensure_null(
2809
3661
                other_branch.last_revision())
2810
3662
        else:
2811
 
            other_revision_id = \
2812
 
                _mod_revision.ensure_null(
2813
 
                    revision[-1].in_history(other_branch).rev_id)
 
3663
            other_revision_id = revision[-1].as_revision_id(other_branch)
2814
3664
        if (revision is not None and len(revision) == 2
2815
3665
            and revision[0] is not None):
2816
 
            base_revision_id = \
2817
 
                _mod_revision.ensure_null(
2818
 
                    revision[0].in_history(base_branch).rev_id)
 
3666
            base_revision_id = revision[0].as_revision_id(base_branch)
2819
3667
        else:
2820
3668
            base_revision_id = None
2821
3669
        # Remember where we merge from
2822
 
        if ((tree.branch.get_parent() is None or remember) and
2823
 
            other_branch is not None):
2824
 
            tree.branch.set_parent(other_branch.base)
 
3670
        if ((remember or tree.branch.get_submit_branch() is None) and
 
3671
             user_location is not None):
 
3672
            tree.branch.set_submit_branch(other_branch.base)
2825
3673
        _merge_tags_if_possible(other_branch, tree.branch)
2826
3674
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
2827
3675
            other_revision_id, base_revision_id, other_branch, base_branch)
2832
3680
            allow_pending = True
2833
3681
        return merger, allow_pending
2834
3682
 
2835
 
    def _select_branch_location(self, tree, location, revision=None,
 
3683
    def _select_branch_location(self, tree, user_location, revision=None,
2836
3684
                                index=None):
2837
3685
        """Select a branch location, according to possible inputs.
2838
3686
 
2840
3688
        ``revision`` and ``index`` must be supplied.)
2841
3689
 
2842
3690
        Otherwise, the ``location`` parameter is used.  If it is None, then the
2843
 
        ``parent`` location is used, and a note is printed.
 
3691
        ``submit`` or ``parent`` location is used, and a note is printed.
2844
3692
 
2845
3693
        :param tree: The working tree to select a branch for merging into
2846
3694
        :param location: The location entered by the user
2847
3695
        :param revision: The revision parameter to the command
2848
3696
        :param index: The index to use for the revision parameter.  Negative
2849
3697
            indices are permitted.
2850
 
        :return: (selected_location, default_location).  The default location
2851
 
            will be the user-entered location, if any, or else the remembered
2852
 
            location.
 
3698
        :return: (selected_location, user_location).  The default location
 
3699
            will be the user-entered location.
2853
3700
        """
2854
3701
        if (revision is not None and index is not None
2855
3702
            and revision[index] is not None):
2856
3703
            branch = revision[index].get_branch()
2857
3704
            if branch is not None:
2858
 
                return branch, location
2859
 
        location = self._get_remembered_parent(tree, location, 'Merging from')
2860
 
        return location, location
 
3705
                return branch, branch
 
3706
        if user_location is None:
 
3707
            location = self._get_remembered(tree, 'Merging from')
 
3708
        else:
 
3709
            location = user_location
 
3710
        return location, user_location
2861
3711
 
2862
 
    # TODO: move up to common parent; this isn't merge-specific anymore. 
2863
 
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
 
3712
    def _get_remembered(self, tree, verb_string):
2864
3713
        """Use tree.branch's parent if none was supplied.
2865
3714
 
2866
3715
        Report if the remembered location was used.
2867
3716
        """
2868
 
        if supplied_location is not None:
2869
 
            return supplied_location
2870
 
        stored_location = tree.branch.get_parent()
 
3717
        stored_location = tree.branch.get_submit_branch()
 
3718
        stored_location_type = "submit"
 
3719
        if stored_location is None:
 
3720
            stored_location = tree.branch.get_parent()
 
3721
            stored_location_type = "parent"
2871
3722
        mutter("%s", stored_location)
2872
3723
        if stored_location is None:
2873
3724
            raise errors.BzrCommandError("No location specified or remembered")
2874
 
        display_url = urlutils.unescape_for_display(stored_location,
2875
 
            self.outf.encoding)
2876
 
        self.outf.write("%s remembered location %s\n" % (verb_string,
2877
 
            display_url))
 
3725
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
 
3726
        note(u"%s remembered %s location %s", verb_string,
 
3727
                stored_location_type, display_url)
2878
3728
        return stored_location
2879
3729
 
2880
3730
 
2882
3732
    """Redo a merge.
2883
3733
 
2884
3734
    Use this if you want to try a different merge technique while resolving
2885
 
    conflicts.  Some merge techniques are better than others, and remerge 
 
3735
    conflicts.  Some merge techniques are better than others, and remerge
2886
3736
    lets you try different ones on different files.
2887
3737
 
2888
3738
    The options for remerge have the same meaning and defaults as the ones for
2892
3742
    :Examples:
2893
3743
        Re-do the merge of all conflicted files, and show the base text in
2894
3744
        conflict regions, in addition to the usual THIS and OTHER texts::
2895
 
      
 
3745
 
2896
3746
            bzr remerge --show-base
2897
3747
 
2898
3748
        Re-do the merge of "foobar", using the weave merge algorithm, with
2899
3749
        additional processing to reduce the size of conflict regions::
2900
 
      
 
3750
 
2901
3751
            bzr remerge --merge-type weave --reprocess foobar
2902
3752
    """
2903
3753
    takes_args = ['file*']
2921
3771
                                             " merges.  Not cherrypicking or"
2922
3772
                                             " multi-merges.")
2923
3773
            repository = tree.branch.repository
2924
 
            graph = repository.get_graph()
2925
 
            base_revision = graph.find_unique_lca(parents[0], parents[1])
2926
 
            base_tree = repository.revision_tree(base_revision)
2927
 
            other_tree = repository.revision_tree(parents[1])
2928
3774
            interesting_ids = None
2929
3775
            new_conflicts = []
2930
3776
            conflicts = tree.conflicts()
2937
3783
                    interesting_ids.add(file_id)
2938
3784
                    if tree.kind(file_id) != "directory":
2939
3785
                        continue
2940
 
                    
 
3786
 
2941
3787
                    for name, ie in tree.inventory.iter_entries(file_id):
2942
3788
                        interesting_ids.add(ie.file_id)
2943
3789
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2960
3806
            # list, we imply that the working tree text has seen and rejected
2961
3807
            # all the changes from the other tree, when in fact those changes
2962
3808
            # have not yet been seen.
 
3809
            pb = ui.ui_factory.nested_progress_bar()
2963
3810
            tree.set_parent_ids(parents[:1])
2964
3811
            try:
2965
 
                conflicts = _mod_merge.merge_inner(
2966
 
                                          tree.branch, other_tree, base_tree,
2967
 
                                          this_tree=tree,
2968
 
                                          interesting_ids=interesting_ids,
2969
 
                                          other_rev_id=parents[1],
2970
 
                                          merge_type=merge_type,
2971
 
                                          show_base=show_base,
2972
 
                                          reprocess=reprocess)
 
3812
                merger = _mod_merge.Merger.from_revision_ids(pb,
 
3813
                                                             tree, parents[1])
 
3814
                merger.interesting_ids = interesting_ids
 
3815
                merger.merge_type = merge_type
 
3816
                merger.show_base = show_base
 
3817
                merger.reprocess = reprocess
 
3818
                conflicts = merger.do_merge()
2973
3819
            finally:
2974
3820
                tree.set_parent_ids(parents)
 
3821
                pb.finished()
2975
3822
        finally:
2976
3823
            tree.unlock()
2977
3824
        if conflicts > 0:
2988
3835
    last committed revision is used.
2989
3836
 
2990
3837
    To remove only some changes, without reverting to a prior version, use
2991
 
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
2992
 
    introduced by -2, without affecting the changes introduced by -1.  Or
2993
 
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
2994
 
    
 
3838
    merge instead.  For example, "merge . --revision -2..-3" will remove the
 
3839
    changes introduced by -2, without affecting the changes introduced by -1.
 
3840
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
3841
 
2995
3842
    By default, any files that have been manually changed will be backed up
2996
3843
    first.  (Files changed only by merge are not backed up.)  Backup files have
2997
3844
    '.~#~' appended to their name, where # is a number.
3000
3847
    from the target revision.  So you can use revert to "undelete" a file by
3001
3848
    name.  If you name a directory, all the contents of that directory will be
3002
3849
    reverted.
 
3850
 
 
3851
    Any files that have been newly added since that revision will be deleted,
 
3852
    with a backup kept if appropriate.  Directories containing unknown files
 
3853
    will not be deleted.
 
3854
 
 
3855
    The working tree contains a list of pending merged revisions, which will
 
3856
    be included as parents in the next commit.  Normally, revert clears that
 
3857
    list as well as reverting the files.  If any files are specified, revert
 
3858
    leaves the pending merge list alone and reverts only the files.  Use "bzr
 
3859
    revert ." in the tree root to revert all files but keep the merge record,
 
3860
    and "bzr revert --forget-merges" to clear the pending merge list without
 
3861
    reverting any files.
3003
3862
    """
3004
3863
 
3005
3864
    _see_also = ['cat', 'export']
3006
3865
    takes_options = [
3007
 
            'revision',
3008
 
            Option('no-backup', "Do not save backups of reverted files."),
3009
 
            ]
 
3866
        'revision',
 
3867
        Option('no-backup', "Do not save backups of reverted files."),
 
3868
        Option('forget-merges',
 
3869
               'Remove pending merge marker, without changing any files.'),
 
3870
        ]
3010
3871
    takes_args = ['file*']
3011
3872
 
3012
 
    def run(self, revision=None, no_backup=False, file_list=None):
3013
 
        if file_list is not None:
3014
 
            if len(file_list) == 0:
3015
 
                raise errors.BzrCommandError("No files specified")
3016
 
        else:
3017
 
            file_list = []
3018
 
        
 
3873
    def run(self, revision=None, no_backup=False, file_list=None,
 
3874
            forget_merges=None):
3019
3875
        tree, file_list = tree_files(file_list)
3020
 
        if revision is None:
3021
 
            # FIXME should be tree.last_revision
3022
 
            rev_id = tree.last_revision()
3023
 
        elif len(revision) != 1:
3024
 
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3025
 
        else:
3026
 
            rev_id = revision[0].in_history(tree.branch).rev_id
 
3876
        tree.lock_write()
 
3877
        try:
 
3878
            if forget_merges:
 
3879
                tree.set_parent_ids(tree.get_parent_ids()[:1])
 
3880
            else:
 
3881
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
3882
        finally:
 
3883
            tree.unlock()
 
3884
 
 
3885
    @staticmethod
 
3886
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
 
3887
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
3027
3888
        pb = ui.ui_factory.nested_progress_bar()
3028
3889
        try:
3029
 
            tree.revert(file_list, 
3030
 
                        tree.branch.repository.revision_tree(rev_id),
3031
 
                        not no_backup, pb, report_changes=True)
 
3890
            tree.revert(file_list, rev_tree, not no_backup, pb,
 
3891
                report_changes=True)
3032
3892
        finally:
3033
3893
            pb.finished()
3034
3894
 
3053
3913
            ]
3054
3914
    takes_args = ['topic?']
3055
3915
    aliases = ['?', '--help', '-?', '-h']
3056
 
    
 
3916
 
3057
3917
    @display_command
3058
3918
    def run(self, topic=None, long=False):
3059
3919
        import bzrlib.help
3070
3930
    takes_args = ['context?']
3071
3931
    aliases = ['s-c']
3072
3932
    hidden = True
3073
 
    
 
3933
 
3074
3934
    @display_command
3075
3935
    def run(self, context=None):
3076
3936
        import shellcomplete
3077
3937
        shellcomplete.shellcomplete(context)
3078
3938
 
3079
3939
 
3080
 
class cmd_fetch(Command):
3081
 
    """Copy in history from another branch but don't merge it.
3082
 
 
3083
 
    This is an internal method used for pull and merge.
3084
 
    """
3085
 
    hidden = True
3086
 
    takes_args = ['from_branch', 'to_branch']
3087
 
    def run(self, from_branch, to_branch):
3088
 
        from bzrlib.fetch import Fetcher
3089
 
        from_b = Branch.open(from_branch)
3090
 
        to_b = Branch.open(to_branch)
3091
 
        Fetcher(to_b, from_b)
3092
 
 
3093
 
 
3094
3940
class cmd_missing(Command):
3095
3941
    """Show unmerged/unpulled revisions between two branches.
3096
 
    
 
3942
 
3097
3943
    OTHER_BRANCH may be local or remote.
 
3944
 
 
3945
    To filter on a range of revisions, you can use the command -r begin..end
 
3946
    -r revision requests a specific revision, -r ..end or -r begin.. are
 
3947
    also valid.
 
3948
 
 
3949
    :Examples:
 
3950
 
 
3951
        Determine the missing revisions between this and the branch at the
 
3952
        remembered pull location::
 
3953
 
 
3954
            bzr missing
 
3955
 
 
3956
        Determine the missing revisions between this and another branch::
 
3957
 
 
3958
            bzr missing http://server/branch
 
3959
 
 
3960
        Determine the missing revisions up to a specific revision on the other
 
3961
        branch::
 
3962
 
 
3963
            bzr missing -r ..-10
 
3964
 
 
3965
        Determine the missing revisions up to a specific revision on this
 
3966
        branch::
 
3967
 
 
3968
            bzr missing --my-revision ..-10
3098
3969
    """
3099
3970
 
3100
3971
    _see_also = ['merge', 'pull']
3101
3972
    takes_args = ['other_branch?']
3102
3973
    takes_options = [
3103
 
            Option('reverse', 'Reverse the order of revisions.'),
3104
 
            Option('mine-only',
3105
 
                   'Display changes in the local branch only.'),
3106
 
            Option('this' , 'Same as --mine-only.'),
3107
 
            Option('theirs-only',
3108
 
                   'Display changes in the remote branch only.'),
3109
 
            Option('other', 'Same as --theirs-only.'),
3110
 
            'log-format',
3111
 
            'show-ids',
3112
 
            'verbose'
3113
 
            ]
 
3974
        Option('reverse', 'Reverse the order of revisions.'),
 
3975
        Option('mine-only',
 
3976
               'Display changes in the local branch only.'),
 
3977
        Option('this' , 'Same as --mine-only.'),
 
3978
        Option('theirs-only',
 
3979
               'Display changes in the remote branch only.'),
 
3980
        Option('other', 'Same as --theirs-only.'),
 
3981
        'log-format',
 
3982
        'show-ids',
 
3983
        'verbose',
 
3984
        custom_help('revision',
 
3985
             help='Filter on other branch revisions (inclusive). '
 
3986
                'See "help revisionspec" for details.'),
 
3987
        Option('my-revision',
 
3988
            type=_parse_revision_str,
 
3989
            help='Filter on local branch revisions (inclusive). '
 
3990
                'See "help revisionspec" for details.'),
 
3991
        Option('include-merges',
 
3992
               'Show all revisions in addition to the mainline ones.'),
 
3993
        ]
3114
3994
    encoding_type = 'replace'
3115
3995
 
3116
3996
    @display_command
3117
3997
    def run(self, other_branch=None, reverse=False, mine_only=False,
3118
 
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
3119
 
            show_ids=False, verbose=False, this=False, other=False):
 
3998
            theirs_only=False,
 
3999
            log_format=None, long=False, short=False, line=False,
 
4000
            show_ids=False, verbose=False, this=False, other=False,
 
4001
            include_merges=False, revision=None, my_revision=None):
3120
4002
        from bzrlib.missing import find_unmerged, iter_log_revisions
3121
 
        from bzrlib.log import log_formatter
 
4003
        def message(s):
 
4004
            if not is_quiet():
 
4005
                self.outf.write(s)
3122
4006
 
3123
4007
        if this:
3124
 
          mine_only = this
 
4008
            mine_only = this
3125
4009
        if other:
3126
 
          theirs_only = other
 
4010
            theirs_only = other
 
4011
        # TODO: We should probably check that we don't have mine-only and
 
4012
        #       theirs-only set, but it gets complicated because we also have
 
4013
        #       this and other which could be used.
 
4014
        restrict = 'all'
 
4015
        if mine_only:
 
4016
            restrict = 'local'
 
4017
        elif theirs_only:
 
4018
            restrict = 'remote'
3127
4019
 
3128
4020
        local_branch = Branch.open_containing(u".")[0]
3129
4021
        parent = local_branch.get_parent()
3134
4026
                                             " or specified.")
3135
4027
            display_url = urlutils.unescape_for_display(parent,
3136
4028
                                                        self.outf.encoding)
3137
 
            self.outf.write("Using last location: " + display_url + "\n")
 
4029
            message("Using saved parent location: "
 
4030
                    + display_url + "\n")
3138
4031
 
3139
4032
        remote_branch = Branch.open(other_branch)
3140
4033
        if remote_branch.base == local_branch.base:
3141
4034
            remote_branch = local_branch
 
4035
 
 
4036
        local_revid_range = _revision_range_to_revid_range(
 
4037
            _get_revision_range(my_revision, local_branch,
 
4038
                self.name()))
 
4039
 
 
4040
        remote_revid_range = _revision_range_to_revid_range(
 
4041
            _get_revision_range(revision,
 
4042
                remote_branch, self.name()))
 
4043
 
3142
4044
        local_branch.lock_read()
3143
4045
        try:
3144
4046
            remote_branch.lock_read()
3145
4047
            try:
3146
 
                local_extra, remote_extra = find_unmerged(local_branch,
3147
 
                                                          remote_branch)
 
4048
                local_extra, remote_extra = find_unmerged(
 
4049
                    local_branch, remote_branch, restrict,
 
4050
                    backward=not reverse,
 
4051
                    include_merges=include_merges,
 
4052
                    local_revid_range=local_revid_range,
 
4053
                    remote_revid_range=remote_revid_range)
 
4054
 
3148
4055
                if log_format is None:
3149
4056
                    registry = log.log_formatter_registry
3150
4057
                    log_format = registry.get_default(local_branch)
3151
4058
                lf = log_format(to_file=self.outf,
3152
4059
                                show_ids=show_ids,
3153
4060
                                show_timezone='original')
3154
 
                if reverse is False:
3155
 
                    local_extra.reverse()
3156
 
                    remote_extra.reverse()
 
4061
 
 
4062
                status_code = 0
3157
4063
                if local_extra and not theirs_only:
3158
 
                    self.outf.write("You have %d extra revision(s):\n" %
3159
 
                                    len(local_extra))
 
4064
                    message("You have %d extra revision(s):\n" %
 
4065
                        len(local_extra))
3160
4066
                    for revision in iter_log_revisions(local_extra,
3161
4067
                                        local_branch.repository,
3162
4068
                                        verbose):
3163
4069
                        lf.log_revision(revision)
3164
4070
                    printed_local = True
 
4071
                    status_code = 1
3165
4072
                else:
3166
4073
                    printed_local = False
 
4074
 
3167
4075
                if remote_extra and not mine_only:
3168
4076
                    if printed_local is True:
3169
 
                        self.outf.write("\n\n\n")
3170
 
                    self.outf.write("You are missing %d revision(s):\n" %
3171
 
                                    len(remote_extra))
 
4077
                        message("\n\n\n")
 
4078
                    message("You are missing %d revision(s):\n" %
 
4079
                        len(remote_extra))
3172
4080
                    for revision in iter_log_revisions(remote_extra,
3173
4081
                                        remote_branch.repository,
3174
4082
                                        verbose):
3175
4083
                        lf.log_revision(revision)
3176
 
                if not remote_extra and not local_extra:
3177
 
                    status_code = 0
3178
 
                    self.outf.write("Branches are up to date.\n")
3179
 
                else:
3180
4084
                    status_code = 1
 
4085
 
 
4086
                if mine_only and not local_extra:
 
4087
                    # We checked local, and found nothing extra
 
4088
                    message('This branch is up to date.\n')
 
4089
                elif theirs_only and not remote_extra:
 
4090
                    # We checked remote, and found nothing extra
 
4091
                    message('Other branch is up to date.\n')
 
4092
                elif not (mine_only or theirs_only or local_extra or
 
4093
                          remote_extra):
 
4094
                    # We checked both branches, and neither one had extra
 
4095
                    # revisions
 
4096
                    message("Branches are up to date.\n")
3181
4097
            finally:
3182
4098
                remote_branch.unlock()
3183
4099
        finally:
3211
4127
 
3212
4128
class cmd_plugins(Command):
3213
4129
    """List the installed plugins.
3214
 
    
3215
 
    This command displays the list of installed plugins including the
3216
 
    path where each one is located and a short description of each.
 
4130
 
 
4131
    This command displays the list of installed plugins including
 
4132
    version of plugin and a short description of each.
 
4133
 
 
4134
    --verbose shows the path where each plugin is located.
3217
4135
 
3218
4136
    A plugin is an external component for Bazaar that extends the
3219
4137
    revision control system, by adding or replacing code in Bazaar.
3226
4144
    install them. Instructions are also provided there on how to
3227
4145
    write new plugins using the Python programming language.
3228
4146
    """
 
4147
    takes_options = ['verbose']
3229
4148
 
3230
4149
    @display_command
3231
 
    def run(self):
 
4150
    def run(self, verbose=False):
3232
4151
        import bzrlib.plugin
3233
4152
        from inspect import getdoc
3234
 
        for name, plugin in bzrlib.plugin.all_plugins().items():
3235
 
            if getattr(plugin, '__path__', None) is not None:
3236
 
                print plugin.__path__[0]
3237
 
            elif getattr(plugin, '__file__', None) is not None:
3238
 
                print plugin.__file__
3239
 
            else:
3240
 
                print repr(plugin)
3241
 
                
3242
 
            d = getdoc(plugin)
 
4153
        result = []
 
4154
        for name, plugin in bzrlib.plugin.plugins().items():
 
4155
            version = plugin.__version__
 
4156
            if version == 'unknown':
 
4157
                version = ''
 
4158
            name_ver = '%s %s' % (name, version)
 
4159
            d = getdoc(plugin.module)
3243
4160
            if d:
3244
 
                print '\t', d.split('\n')[0]
 
4161
                doc = d.split('\n')[0]
 
4162
            else:
 
4163
                doc = '(no description)'
 
4164
            result.append((name_ver, doc, plugin.path()))
 
4165
        for name_ver, doc, path in sorted(result):
 
4166
            print name_ver
 
4167
            print '   ', doc
 
4168
            if verbose:
 
4169
                print '   ', path
 
4170
            print
3245
4171
 
3246
4172
 
3247
4173
class cmd_testament(Command):
3259
4185
            testament_class = StrictTestament
3260
4186
        else:
3261
4187
            testament_class = Testament
3262
 
        b = WorkingTree.open_containing(branch)[0].branch
 
4188
        if branch == '.':
 
4189
            b = Branch.open_containing(branch)[0]
 
4190
        else:
 
4191
            b = Branch.open(branch)
3263
4192
        b.lock_read()
3264
4193
        try:
3265
4194
            if revision is None:
3266
4195
                rev_id = b.last_revision()
3267
4196
            else:
3268
 
                rev_id = revision[0].in_history(b).rev_id
 
4197
                rev_id = revision[0].as_revision_id(b)
3269
4198
            t = testament_class.from_revision(b.repository, rev_id)
3270
4199
            if long:
3271
4200
                sys.stdout.writelines(t.as_text_lines())
3281
4210
    This prints out the given file with an annotation on the left side
3282
4211
    indicating which revision, author and date introduced the change.
3283
4212
 
3284
 
    If the origin is the same for a run of consecutive lines, it is 
 
4213
    If the origin is the same for a run of consecutive lines, it is
3285
4214
    shown only at the top, unless the --all option is given.
3286
4215
    """
3287
4216
    # TODO: annotate directories; showing when each file was last changed
3288
 
    # TODO: if the working copy is modified, show annotations on that 
 
4217
    # TODO: if the working copy is modified, show annotations on that
3289
4218
    #       with new uncommitted lines marked
3290
4219
    aliases = ['ann', 'blame', 'praise']
3291
4220
    takes_args = ['filename']
3299
4228
    @display_command
3300
4229
    def run(self, filename, all=False, long=False, revision=None,
3301
4230
            show_ids=False):
3302
 
        from bzrlib.annotate import annotate_file
3303
 
        tree, relpath = WorkingTree.open_containing(filename)
3304
 
        branch = tree.branch
3305
 
        branch.lock_read()
 
4231
        from bzrlib.annotate import annotate_file, annotate_file_tree
 
4232
        wt, branch, relpath = \
 
4233
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
4234
        if wt is not None:
 
4235
            wt.lock_read()
 
4236
        else:
 
4237
            branch.lock_read()
3306
4238
        try:
3307
 
            if revision is None:
3308
 
                revision_id = branch.last_revision()
3309
 
            elif len(revision) != 1:
3310
 
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
 
4239
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4240
            if wt is not None:
 
4241
                file_id = wt.path2id(relpath)
3311
4242
            else:
3312
 
                revision_id = revision[0].in_history(branch).rev_id
3313
 
            file_id = tree.path2id(relpath)
 
4243
                file_id = tree.path2id(relpath)
3314
4244
            if file_id is None:
3315
4245
                raise errors.NotVersionedError(filename)
3316
 
            tree = branch.repository.revision_tree(revision_id)
3317
4246
            file_version = tree.inventory[file_id].revision
3318
 
            annotate_file(branch, file_version, file_id, long, all, self.outf,
3319
 
                          show_ids=show_ids)
 
4247
            if wt is not None and revision is None:
 
4248
                # If there is a tree and we're not annotating historical
 
4249
                # versions, annotate the working tree's content.
 
4250
                annotate_file_tree(wt, file_id, self.outf, long, all,
 
4251
                    show_ids=show_ids)
 
4252
            else:
 
4253
                annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4254
                              show_ids=show_ids)
3320
4255
        finally:
3321
 
            branch.unlock()
 
4256
            if wt is not None:
 
4257
                wt.unlock()
 
4258
            else:
 
4259
                branch.unlock()
3322
4260
 
3323
4261
 
3324
4262
class cmd_re_sign(Command):
3328
4266
    hidden = True # is this right ?
3329
4267
    takes_args = ['revision_id*']
3330
4268
    takes_options = ['revision']
3331
 
    
 
4269
 
3332
4270
    def run(self, revision_id_list=None, revision=None):
3333
 
        import bzrlib.gpg as gpg
3334
4271
        if revision_id_list is not None and revision is not None:
3335
4272
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3336
4273
        if revision_id_list is None and revision is None:
3337
4274
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3338
4275
        b = WorkingTree.open_containing(u'.')[0].branch
 
4276
        b.lock_write()
 
4277
        try:
 
4278
            return self._run(b, revision_id_list, revision)
 
4279
        finally:
 
4280
            b.unlock()
 
4281
 
 
4282
    def _run(self, b, revision_id_list, revision):
 
4283
        import bzrlib.gpg as gpg
3339
4284
        gpg_strategy = gpg.GPGStrategy(b.get_config())
3340
4285
        if revision_id_list is not None:
3341
 
            for revision_id in revision_id_list:
3342
 
                b.repository.sign_revision(revision_id, gpg_strategy)
 
4286
            b.repository.start_write_group()
 
4287
            try:
 
4288
                for revision_id in revision_id_list:
 
4289
                    b.repository.sign_revision(revision_id, gpg_strategy)
 
4290
            except:
 
4291
                b.repository.abort_write_group()
 
4292
                raise
 
4293
            else:
 
4294
                b.repository.commit_write_group()
3343
4295
        elif revision is not None:
3344
4296
            if len(revision) == 1:
3345
4297
                revno, rev_id = revision[0].in_history(b)
3346
 
                b.repository.sign_revision(rev_id, gpg_strategy)
 
4298
                b.repository.start_write_group()
 
4299
                try:
 
4300
                    b.repository.sign_revision(rev_id, gpg_strategy)
 
4301
                except:
 
4302
                    b.repository.abort_write_group()
 
4303
                    raise
 
4304
                else:
 
4305
                    b.repository.commit_write_group()
3347
4306
            elif len(revision) == 2:
3348
4307
                # are they both on rh- if so we can walk between them
3349
4308
                # might be nice to have a range helper for arbitrary
3354
4313
                    to_revno = b.revno()
3355
4314
                if from_revno is None or to_revno is None:
3356
4315
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
3357
 
                for revno in range(from_revno, to_revno + 1):
3358
 
                    b.repository.sign_revision(b.get_rev_id(revno), 
3359
 
                                               gpg_strategy)
 
4316
                b.repository.start_write_group()
 
4317
                try:
 
4318
                    for revno in range(from_revno, to_revno + 1):
 
4319
                        b.repository.sign_revision(b.get_rev_id(revno),
 
4320
                                                   gpg_strategy)
 
4321
                except:
 
4322
                    b.repository.abort_write_group()
 
4323
                    raise
 
4324
                else:
 
4325
                    b.repository.commit_write_group()
3360
4326
            else:
3361
4327
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
3362
4328
 
3366
4332
 
3367
4333
    Once converted into a checkout, commits must succeed on the master branch
3368
4334
    before they will be applied to the local branch.
 
4335
 
 
4336
    Bound branches use the nickname of its master branch unless it is set
 
4337
    locally, in which case binding will update the the local nickname to be
 
4338
    that of the master.
3369
4339
    """
3370
4340
 
3371
4341
    _see_also = ['checkouts', 'unbind']
3390
4360
        except errors.DivergedBranches:
3391
4361
            raise errors.BzrCommandError('These branches have diverged.'
3392
4362
                                         ' Try merging, and then bind again.')
 
4363
        if b.get_config().has_explicit_nickname():
 
4364
            b.nick = b_other.nick
3393
4365
 
3394
4366
 
3395
4367
class cmd_unbind(Command):
3415
4387
    --verbose will print out what is being removed.
3416
4388
    --dry-run will go through all the motions, but not actually
3417
4389
    remove anything.
3418
 
    
3419
 
    In the future, uncommit will create a revision bundle, which can then
3420
 
    be re-applied.
 
4390
 
 
4391
    If --revision is specified, uncommit revisions to leave the branch at the
 
4392
    specified revision.  For example, "bzr uncommit -r 15" will leave the
 
4393
    branch at revision 15.
 
4394
 
 
4395
    Uncommit leaves the working tree ready for a new commit.  The only change
 
4396
    it may make is to restore any pending merges that were present before
 
4397
    the commit.
3421
4398
    """
3422
4399
 
3423
4400
    # TODO: jam 20060108 Add an option to allow uncommit to remove
3427
4404
    _see_also = ['commit']
3428
4405
    takes_options = ['verbose', 'revision',
3429
4406
                    Option('dry-run', help='Don\'t actually make changes.'),
3430
 
                    Option('force', help='Say yes to all questions.')]
 
4407
                    Option('force', help='Say yes to all questions.'),
 
4408
                    Option('local',
 
4409
                           help="Only remove the commits from the local branch"
 
4410
                                " when in a checkout."
 
4411
                           ),
 
4412
                    ]
3431
4413
    takes_args = ['location?']
3432
4414
    aliases = []
 
4415
    encoding_type = 'replace'
3433
4416
 
3434
4417
    def run(self, location=None,
3435
4418
            dry_run=False, verbose=False,
3436
 
            revision=None, force=False):
3437
 
        from bzrlib.log import log_formatter, show_log
3438
 
        import sys
3439
 
        from bzrlib.uncommit import uncommit
3440
 
 
 
4419
            revision=None, force=False, local=False):
3441
4420
        if location is None:
3442
4421
            location = u'.'
3443
4422
        control, relpath = bzrdir.BzrDir.open_containing(location)
3448
4427
            tree = None
3449
4428
            b = control.open_branch()
3450
4429
 
 
4430
        if tree is not None:
 
4431
            tree.lock_write()
 
4432
        else:
 
4433
            b.lock_write()
 
4434
        try:
 
4435
            return self._run(b, tree, dry_run, verbose, revision, force,
 
4436
                             local=local)
 
4437
        finally:
 
4438
            if tree is not None:
 
4439
                tree.unlock()
 
4440
            else:
 
4441
                b.unlock()
 
4442
 
 
4443
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
 
4444
        from bzrlib.log import log_formatter, show_log
 
4445
        from bzrlib.uncommit import uncommit
 
4446
 
 
4447
        last_revno, last_rev_id = b.last_revision_info()
 
4448
 
3451
4449
        rev_id = None
3452
4450
        if revision is None:
3453
 
            revno = b.revno()
 
4451
            revno = last_revno
 
4452
            rev_id = last_rev_id
3454
4453
        else:
3455
4454
            # 'bzr uncommit -r 10' actually means uncommit
3456
4455
            # so that the final tree is at revno 10.
3457
4456
            # but bzrlib.uncommit.uncommit() actually uncommits
3458
4457
            # the revisions that are supplied.
3459
4458
            # So we need to offset it by one
3460
 
            revno = revision[0].in_history(b).revno+1
 
4459
            revno = revision[0].in_history(b).revno + 1
 
4460
            if revno <= last_revno:
 
4461
                rev_id = b.get_rev_id(revno)
3461
4462
 
3462
 
        if revno <= b.revno():
3463
 
            rev_id = b.get_rev_id(revno)
3464
 
        if rev_id is None:
 
4463
        if rev_id is None or _mod_revision.is_null(rev_id):
3465
4464
            self.outf.write('No revisions to uncommit.\n')
3466
4465
            return 1
3467
4466
 
3474
4473
                 verbose=False,
3475
4474
                 direction='forward',
3476
4475
                 start_revision=revno,
3477
 
                 end_revision=b.revno())
 
4476
                 end_revision=last_revno)
3478
4477
 
3479
4478
        if dry_run:
3480
4479
            print 'Dry-run, pretending to remove the above revisions.'
3488
4487
                    print 'Canceled'
3489
4488
                    return 0
3490
4489
 
 
4490
        mutter('Uncommitting from {%s} to {%s}',
 
4491
               last_rev_id, rev_id)
3491
4492
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3492
 
                revno=revno)
 
4493
                 revno=revno, local=local)
 
4494
        note('You can restore the old tip by running:\n'
 
4495
             '  bzr pull . -r revid:%s', last_rev_id)
3493
4496
 
3494
4497
 
3495
4498
class cmd_break_lock(Command):
3499
4502
    holding the lock has been stopped.
3500
4503
 
3501
4504
    You can get information on what locks are open via the 'bzr info' command.
3502
 
    
 
4505
 
3503
4506
    :Examples:
3504
4507
        bzr break-lock
3505
4508
    """
3513
4516
            control.break_lock()
3514
4517
        except NotImplementedError:
3515
4518
            pass
3516
 
        
 
4519
 
3517
4520
 
3518
4521
class cmd_wait_until_signalled(Command):
3519
4522
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
3553
4556
                ),
3554
4557
        ]
3555
4558
 
 
4559
    def run_smart_server(self, smart_server):
 
4560
        """Run 'smart_server' forever, with no UI output at all."""
 
4561
        # For the duration of this server, no UI output is permitted. note
 
4562
        # that this may cause problems with blackbox tests. This should be
 
4563
        # changed with care though, as we dont want to use bandwidth sending
 
4564
        # progress over stderr to smart server clients!
 
4565
        from bzrlib import lockdir
 
4566
        old_factory = ui.ui_factory
 
4567
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
 
4568
        try:
 
4569
            ui.ui_factory = ui.SilentUIFactory()
 
4570
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
 
4571
            smart_server.serve()
 
4572
        finally:
 
4573
            ui.ui_factory = old_factory
 
4574
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
 
4575
 
 
4576
    def get_host_and_port(self, port):
 
4577
        """Return the host and port to run the smart server on.
 
4578
 
 
4579
        If 'port' is None, the default host (`medium.BZR_DEFAULT_INTERFACE`)
 
4580
        and port (`medium.BZR_DEFAULT_PORT`) will be used.
 
4581
 
 
4582
        If 'port' has a colon in it, the string before the colon will be
 
4583
        interpreted as the host.
 
4584
 
 
4585
        :param port: A string of the port to run the server on.
 
4586
        :return: A tuple of (host, port), where 'host' is a host name or IP,
 
4587
            and port is an integer TCP/IP port.
 
4588
        """
 
4589
        from bzrlib.smart import medium
 
4590
        host = medium.BZR_DEFAULT_INTERFACE
 
4591
        if port is None:
 
4592
            port = medium.BZR_DEFAULT_PORT
 
4593
        else:
 
4594
            if ':' in port:
 
4595
                host, port = port.split(':')
 
4596
            port = int(port)
 
4597
        return host, port
 
4598
 
 
4599
    def get_smart_server(self, transport, inet, port):
 
4600
        """Construct a smart server.
 
4601
 
 
4602
        :param transport: The base transport from which branches will be
 
4603
            served.
 
4604
        :param inet: If True, serve over stdin and stdout. Used for running
 
4605
            from inet.
 
4606
        :param port: The port to listen on. By default, it's `
 
4607
            medium.BZR_DEFAULT_PORT`. See `get_host_and_port` for more
 
4608
            information.
 
4609
        :return: A smart server.
 
4610
        """
 
4611
        from bzrlib.smart import medium, server
 
4612
        if inet:
 
4613
            smart_server = medium.SmartServerPipeStreamMedium(
 
4614
                sys.stdin, sys.stdout, transport)
 
4615
        else:
 
4616
            host, port = self.get_host_and_port(port)
 
4617
            smart_server = server.SmartTCPServer(
 
4618
                transport, host=host, port=port)
 
4619
            note('listening on port: %s' % smart_server.port)
 
4620
        return smart_server
 
4621
 
3556
4622
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
3557
 
        from bzrlib.smart import medium, server
3558
4623
        from bzrlib.transport import get_transport
3559
4624
        from bzrlib.transport.chroot import ChrootServer
3560
 
        from bzrlib.transport.remote import BZR_DEFAULT_PORT, BZR_DEFAULT_INTERFACE
3561
4625
        if directory is None:
3562
4626
            directory = os.getcwd()
3563
4627
        url = urlutils.local_path_to_url(directory)
3566
4630
        chroot_server = ChrootServer(get_transport(url))
3567
4631
        chroot_server.setUp()
3568
4632
        t = get_transport(chroot_server.get_url())
3569
 
        if inet:
3570
 
            smart_server = medium.SmartServerPipeStreamMedium(
3571
 
                sys.stdin, sys.stdout, t)
3572
 
        else:
3573
 
            host = BZR_DEFAULT_INTERFACE
3574
 
            if port is None:
3575
 
                port = BZR_DEFAULT_PORT
3576
 
            else:
3577
 
                if ':' in port:
3578
 
                    host, port = port.split(':')
3579
 
                port = int(port)
3580
 
            smart_server = server.SmartTCPServer(t, host=host, port=port)
3581
 
            print 'listening on port: ', smart_server.port
3582
 
            sys.stdout.flush()
3583
 
        # for the duration of this server, no UI output is permitted.
3584
 
        # note that this may cause problems with blackbox tests. This should
3585
 
        # be changed with care though, as we dont want to use bandwidth sending
3586
 
        # progress over stderr to smart server clients!
3587
 
        old_factory = ui.ui_factory
3588
 
        try:
3589
 
            ui.ui_factory = ui.SilentUIFactory()
3590
 
            smart_server.serve()
3591
 
        finally:
3592
 
            ui.ui_factory = old_factory
 
4633
        smart_server = self.get_smart_server(t, inet, port)
 
4634
        self.run_smart_server(smart_server)
3593
4635
 
3594
4636
 
3595
4637
class cmd_join(Command):
3596
 
    """Combine a subtree into its containing tree.
3597
 
    
3598
 
    This command is for experimental use only.  It requires the target tree
3599
 
    to be in dirstate-with-subtree format, which cannot be converted into
3600
 
    earlier formats.
 
4638
    """Combine a tree into its containing tree.
 
4639
 
 
4640
    This command requires the target tree to be in a rich-root format.
3601
4641
 
3602
4642
    The TREE argument should be an independent tree, inside another tree, but
3603
4643
    not part of it.  (Such trees can be produced by "bzr split", but also by
3606
4646
    The result is a combined tree, with the subtree no longer an independant
3607
4647
    part.  This is marked as a merge of the subtree into the containing tree,
3608
4648
    and all history is preserved.
3609
 
 
3610
 
    If --reference is specified, the subtree retains its independence.  It can
3611
 
    be branched by itself, and can be part of multiple projects at the same
3612
 
    time.  But operations performed in the containing tree, such as commit
3613
 
    and merge, will recurse into the subtree.
3614
4649
    """
3615
4650
 
3616
4651
    _see_also = ['split']
3617
4652
    takes_args = ['tree']
3618
4653
    takes_options = [
3619
 
            Option('reference', help='Join by reference.'),
 
4654
            Option('reference', help='Join by reference.', hidden=True),
3620
4655
            ]
3621
 
    hidden = True
3622
4656
 
3623
4657
    def run(self, tree, reference=False):
3624
4658
        sub_tree = WorkingTree.open(tree)
3642
4676
            try:
3643
4677
                containing_tree.subsume(sub_tree)
3644
4678
            except errors.BadSubsumeSource, e:
3645
 
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
 
4679
                raise errors.BzrCommandError("Cannot join %s.  %s" %
3646
4680
                                             (tree, e.reason))
3647
4681
 
3648
4682
 
3649
4683
class cmd_split(Command):
3650
 
    """Split a tree into two trees.
 
4684
    """Split a subdirectory of a tree into a separate tree.
3651
4685
 
3652
 
    This command is for experimental use only.  It requires the target tree
3653
 
    to be in dirstate-with-subtree format, which cannot be converted into
3654
 
    earlier formats.
 
4686
    This command will produce a target tree in a format that supports
 
4687
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
 
4688
    converted into earlier formats like 'dirstate-tags'.
3655
4689
 
3656
4690
    The TREE argument should be a subdirectory of a working tree.  That
3657
4691
    subdirectory will be converted into an independent tree, with its own
3658
4692
    branch.  Commits in the top-level tree will not apply to the new subtree.
3659
 
    If you want that behavior, do "bzr join --reference TREE".
3660
4693
    """
3661
4694
 
3662
4695
    _see_also = ['join']
3663
4696
    takes_args = ['tree']
3664
4697
 
3665
 
    hidden = True
3666
 
 
3667
4698
    def run(self, tree):
3668
4699
        containing_tree, subdir = WorkingTree.open_containing(tree)
3669
4700
        sub_id = containing_tree.path2id(subdir)
3675
4706
            raise errors.UpgradeRequired(containing_tree.branch.base)
3676
4707
 
3677
4708
 
3678
 
 
3679
4709
class cmd_merge_directive(Command):
3680
4710
    """Generate a merge directive for auto-merge tools.
3681
4711
 
3750
4780
            if len(revision) > 2:
3751
4781
                raise errors.BzrCommandError('bzr merge-directive takes '
3752
4782
                    'at most two one revision identifiers')
3753
 
            revision_id = revision[-1].in_history(branch).rev_id
 
4783
            revision_id = revision[-1].as_revision_id(branch)
3754
4784
            if len(revision) == 2:
3755
 
                base_revision_id = revision[0].in_history(branch).rev_id
3756
 
                base_revision_id = ensure_null(base_revision_id)
 
4785
                base_revision_id = revision[0].as_revision_id(branch)
3757
4786
        else:
3758
4787
            revision_id = branch.last_revision()
3759
4788
        revision_id = ensure_null(revision_id)
3777
4806
 
3778
4807
 
3779
4808
class cmd_send(Command):
3780
 
    """Create a merge-directive for submiting changes.
 
4809
    """Mail or create a merge-directive for submitting changes.
3781
4810
 
3782
4811
    A merge directive provides many things needed for requesting merges:
3783
4812
 
3802
4831
    can be used as your actual submit branch, once you have set public_branch
3803
4832
    for that mirror.
3804
4833
 
 
4834
    Mail is sent using your preferred mail program.  This should be transparent
 
4835
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
 
4836
    If the preferred client can't be found (or used), your editor will be used.
 
4837
 
 
4838
    To use a specific mail program, set the mail_client configuration option.
 
4839
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
 
4840
    specific clients are "claws", "evolution", "kmail", "mutt", and
 
4841
    "thunderbird"; generic options are "default", "editor", "emacsclient",
 
4842
    "mapi", and "xdg-email".  Plugins may also add supported clients.
 
4843
 
 
4844
    If mail is being sent, a to address is required.  This can be supplied
 
4845
    either on the commandline, by setting the submit_to configuration
 
4846
    option in the branch itself or the child_submit_to configuration option
 
4847
    in the submit branch.
 
4848
 
3805
4849
    Two formats are currently supported: "4" uses revision bundle format 4 and
3806
4850
    merge directive format 2.  It is significantly faster and smaller than
3807
4851
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
3808
4852
    default.  "0.9" uses revision bundle format 0.9 and merge directive
3809
4853
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
 
4854
 
 
4855
    The merge directives created by bzr send may be applied using bzr merge or
 
4856
    bzr pull by specifying a file containing a merge directive as the location.
3810
4857
    """
3811
4858
 
3812
4859
    encoding_type = 'exact'
3813
4860
 
3814
 
    _see_also = ['merge']
 
4861
    _see_also = ['merge', 'pull']
3815
4862
 
3816
4863
    takes_args = ['submit_branch?', 'public_branch?']
3817
4864
 
3827
4874
               'rather than the one containing the working directory.',
3828
4875
               short_name='f',
3829
4876
               type=unicode),
3830
 
        Option('output', short_name='o', help='Write directive to this file.',
 
4877
        Option('output', short_name='o',
 
4878
               help='Write merge directive to this file; '
 
4879
                    'use - for stdout.',
 
4880
               type=unicode),
 
4881
        Option('mail-to', help='Mail the request to this address.',
3831
4882
               type=unicode),
3832
4883
        'revision',
 
4884
        'message',
 
4885
        Option('body', help='Body for the email.', type=unicode),
3833
4886
        RegistryOption.from_kwargs('format',
3834
4887
        'Use the specified output format.',
3835
4888
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
3838
4891
 
3839
4892
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
3840
4893
            no_patch=False, revision=None, remember=False, output=None,
3841
 
            format='4', **kwargs):
3842
 
        if output is None:
3843
 
            raise errors.BzrCommandError('File must be specified with'
3844
 
                                         ' --output')
 
4894
            format=None, mail_to=None, message=None, body=None, **kwargs):
3845
4895
        return self._run(submit_branch, revision, public_branch, remember,
3846
4896
                         format, no_bundle, no_patch, output,
3847
 
                         kwargs.get('from', '.'))
 
4897
                         kwargs.get('from', '.'), mail_to, message, body)
3848
4898
 
3849
4899
    def _run(self, submit_branch, revision, public_branch, remember, format,
3850
 
             no_bundle, no_patch, output, from_,):
3851
 
        from bzrlib.revision import ensure_null, NULL_REVISION
3852
 
        if output == '-':
3853
 
            outfile = self.outf
3854
 
        else:
3855
 
            outfile = open(output, 'wb')
 
4900
             no_bundle, no_patch, output, from_, mail_to, message, body):
 
4901
        from bzrlib.revision import NULL_REVISION
 
4902
        tree, branch = bzrdir.BzrDir.open_containing_tree_or_branch(from_)[:2]
 
4903
        # we may need to write data into branch's repository to calculate
 
4904
        # the data to send.
 
4905
        branch.lock_write()
3856
4906
        try:
3857
 
            branch = Branch.open_containing(from_)[0]
 
4907
            if output is None:
 
4908
                config = branch.get_config()
 
4909
                if mail_to is None:
 
4910
                    mail_to = config.get_user_option('submit_to')
 
4911
                mail_client = config.get_mail_client()
 
4912
                if (not getattr(mail_client, 'supports_body', False)
 
4913
                    and body is not None):
 
4914
                    raise errors.BzrCommandError(
 
4915
                        'Mail client "%s" does not support specifying body' %
 
4916
                        mail_client.__class__.__name__)
3858
4917
            if remember and submit_branch is None:
3859
4918
                raise errors.BzrCommandError(
3860
4919
                    '--remember requires a branch to be specified.')
3861
4920
            stored_submit_branch = branch.get_submit_branch()
3862
 
            remembered_submit_branch = False
 
4921
            remembered_submit_branch = None
3863
4922
            if submit_branch is None:
3864
4923
                submit_branch = stored_submit_branch
3865
 
                remembered_submit_branch = True
 
4924
                remembered_submit_branch = "submit"
3866
4925
            else:
3867
4926
                if stored_submit_branch is None or remember:
3868
4927
                    branch.set_submit_branch(submit_branch)
3869
4928
            if submit_branch is None:
3870
4929
                submit_branch = branch.get_parent()
3871
 
                remembered_submit_branch = True
 
4930
                remembered_submit_branch = "parent"
3872
4931
            if submit_branch is None:
3873
4932
                raise errors.BzrCommandError('No submit branch known or'
3874
4933
                                             ' specified')
3875
 
            if remembered_submit_branch:
3876
 
                note('Using saved location: %s', submit_branch)
 
4934
            if remembered_submit_branch is not None:
 
4935
                note('Using saved %s location "%s" to determine what '
 
4936
                        'changes to submit.', remembered_submit_branch,
 
4937
                        submit_branch)
 
4938
 
 
4939
            if mail_to is None or format is None:
 
4940
                submit_config = Branch.open(submit_branch).get_config()
 
4941
                if mail_to is None:
 
4942
                    mail_to = submit_config.get_user_option("child_submit_to")
 
4943
                if format is None:
 
4944
                    format = submit_config.get_user_option("child_submit_format")
3877
4945
 
3878
4946
            stored_public_branch = branch.get_public_branch()
3879
4947
            if public_branch is None:
3884
4952
                raise errors.BzrCommandError('No public branch specified or'
3885
4953
                                             ' known')
3886
4954
            base_revision_id = None
 
4955
            revision_id = None
3887
4956
            if revision is not None:
3888
4957
                if len(revision) > 2:
3889
4958
                    raise errors.BzrCommandError('bzr send takes '
3890
4959
                        'at most two one revision identifiers')
3891
 
                revision_id = revision[-1].in_history(branch).rev_id
 
4960
                revision_id = revision[-1].as_revision_id(branch)
3892
4961
                if len(revision) == 2:
3893
 
                    base_revision_id = revision[0].in_history(branch).rev_id
3894
 
                    base_revision_id = ensure_null(base_revision_id)
3895
 
            else:
 
4962
                    base_revision_id = revision[0].as_revision_id(branch)
 
4963
            if revision_id is None:
3896
4964
                revision_id = branch.last_revision()
3897
 
            revision_id = ensure_null(revision_id)
3898
4965
            if revision_id == NULL_REVISION:
3899
4966
                raise errors.BzrCommandError('No revisions to submit.')
 
4967
            if format is None:
 
4968
                format = '4'
3900
4969
            if format == '4':
3901
4970
                directive = merge_directive.MergeDirective2.from_objects(
3902
4971
                    branch.repository, revision_id, time.time(),
3903
4972
                    osutils.local_time_offset(), submit_branch,
3904
4973
                    public_branch=public_branch, include_patch=not no_patch,
3905
 
                    include_bundle=not no_bundle, message=None,
 
4974
                    include_bundle=not no_bundle, message=message,
3906
4975
                    base_revision_id=base_revision_id)
3907
4976
            elif format == '0.9':
3908
4977
                if not no_bundle:
3920
4989
                    branch.repository, revision_id, time.time(),
3921
4990
                    osutils.local_time_offset(), submit_branch,
3922
4991
                    public_branch=public_branch, patch_type=patch_type,
3923
 
                    message=None)
 
4992
                    message=message)
 
4993
            else:
 
4994
                raise errors.BzrCommandError("No such send format '%s'." % 
 
4995
                                             format)
3924
4996
 
3925
 
            outfile.writelines(directive.to_lines())
 
4997
            if output is None:
 
4998
                directive.compose_merge_request(mail_client, mail_to, body,
 
4999
                                                branch, tree)
 
5000
            else:
 
5001
                if output == '-':
 
5002
                    outfile = self.outf
 
5003
                else:
 
5004
                    outfile = open(output, 'wb')
 
5005
                try:
 
5006
                    outfile.writelines(directive.to_lines())
 
5007
                finally:
 
5008
                    if outfile is not self.outf:
 
5009
                        outfile.close()
3926
5010
        finally:
3927
 
            if output != '-':
3928
 
                outfile.close()
 
5011
            branch.unlock()
3929
5012
 
3930
5013
 
3931
5014
class cmd_bundle_revisions(cmd_send):
3932
5015
 
3933
 
    """Create a merge-directive for submiting changes.
 
5016
    """Create a merge-directive for submitting changes.
3934
5017
 
3935
5018
    A merge directive provides many things needed for requesting merges:
3936
5019
 
3962
5045
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
3963
5046
    """
3964
5047
 
 
5048
    takes_options = [
 
5049
        Option('no-bundle',
 
5050
               help='Do not include a bundle in the merge directive.'),
 
5051
        Option('no-patch', help='Do not include a preview patch in the merge'
 
5052
               ' directive.'),
 
5053
        Option('remember',
 
5054
               help='Remember submit and public branch.'),
 
5055
        Option('from',
 
5056
               help='Branch to generate the submission from, '
 
5057
               'rather than the one containing the working directory.',
 
5058
               short_name='f',
 
5059
               type=unicode),
 
5060
        Option('output', short_name='o', help='Write directive to this file.',
 
5061
               type=unicode),
 
5062
        'revision',
 
5063
        RegistryOption.from_kwargs('format',
 
5064
        'Use the specified output format.',
 
5065
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
 
5066
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
5067
        ]
3965
5068
    aliases = ['bundle']
3966
5069
 
3967
5070
    _see_also = ['send', 'merge']
3970
5073
 
3971
5074
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
3972
5075
            no_patch=False, revision=None, remember=False, output=None,
3973
 
            format='4', **kwargs):
 
5076
            format=None, **kwargs):
3974
5077
        if output is None:
3975
5078
            output = '-'
3976
5079
        return self._run(submit_branch, revision, public_branch, remember,
3977
5080
                         format, no_bundle, no_patch, output,
3978
 
                         kwargs.get('from', '.'))
 
5081
                         kwargs.get('from', '.'), None, None, None)
3979
5082
 
3980
5083
 
3981
5084
class cmd_tag(Command):
3982
5085
    """Create, remove or modify a tag naming a revision.
3983
 
    
 
5086
 
3984
5087
    Tags give human-meaningful names to revisions.  Commands that take a -r
3985
5088
    (--revision) option can be given -rtag:X, where X is any previously
3986
5089
    created tag.
3988
5091
    Tags are stored in the branch.  Tags are copied from one branch to another
3989
5092
    along when you branch, push, pull or merge.
3990
5093
 
3991
 
    It is an error to give a tag name that already exists unless you pass 
 
5094
    It is an error to give a tag name that already exists unless you pass
3992
5095
    --force, in which case the tag is moved to point to the new revision.
 
5096
 
 
5097
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
 
5098
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
3993
5099
    """
3994
5100
 
3995
5101
    _see_also = ['commit', 'tags']
4027
5133
                        raise errors.BzrCommandError(
4028
5134
                            "Tags can only be placed on a single revision, "
4029
5135
                            "not on a range")
4030
 
                    revision_id = revision[0].in_history(branch).rev_id
 
5136
                    revision_id = revision[0].as_revision_id(branch)
4031
5137
                else:
4032
5138
                    revision_id = branch.last_revision()
4033
5139
                if (not force) and branch.tags.has_tag(tag_name):
4041
5147
class cmd_tags(Command):
4042
5148
    """List tags.
4043
5149
 
4044
 
    This tag shows a table of tag names and the revisions they reference.
 
5150
    This command shows a table of tag names and the revisions they reference.
4045
5151
    """
4046
5152
 
4047
5153
    _see_also = ['tag']
4051
5157
            short_name='d',
4052
5158
            type=unicode,
4053
5159
            ),
 
5160
        RegistryOption.from_kwargs('sort',
 
5161
            'Sort tags by different criteria.', title='Sorting',
 
5162
            alpha='Sort tags lexicographically (default).',
 
5163
            time='Sort tags chronologically.',
 
5164
            ),
 
5165
        'show-ids',
 
5166
        'revision',
4054
5167
    ]
4055
5168
 
4056
5169
    @display_command
4057
5170
    def run(self,
4058
5171
            directory='.',
 
5172
            sort='alpha',
 
5173
            show_ids=False,
 
5174
            revision=None,
4059
5175
            ):
4060
5176
        branch, relpath = Branch.open_containing(directory)
4061
 
        for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
4062
 
            self.outf.write('%-20s %s\n' % (tag_name, target))
4063
 
 
4064
 
 
4065
 
def _create_prefix(cur_transport):
4066
 
    needed = [cur_transport]
4067
 
    # Recurse upwards until we can create a directory successfully
4068
 
    while True:
4069
 
        new_transport = cur_transport.clone('..')
4070
 
        if new_transport.base == cur_transport.base:
4071
 
            raise errors.BzrCommandError(
4072
 
                "Failed to create path prefix for %s."
4073
 
                % cur_transport.base)
4074
 
        try:
4075
 
            new_transport.mkdir('.')
4076
 
        except errors.NoSuchFile:
4077
 
            needed.append(new_transport)
4078
 
            cur_transport = new_transport
4079
 
        else:
4080
 
            break
4081
 
    # Now we only need to create child directories
4082
 
    while needed:
4083
 
        cur_transport = needed.pop()
4084
 
        cur_transport.ensure_base()
4085
 
 
4086
 
 
4087
 
def _get_mergeable_helper(location):
4088
 
    """Get a merge directive or bundle if 'location' points to one.
4089
 
 
4090
 
    Try try to identify a bundle and returns its mergeable form. If it's not,
4091
 
    we return the tried transport anyway so that it can reused to access the
4092
 
    branch
4093
 
 
4094
 
    :param location: can point to a bundle or a branch.
4095
 
 
4096
 
    :return: mergeable, transport
4097
 
    """
4098
 
    mergeable = None
4099
 
    url = urlutils.normalize_url(location)
4100
 
    url, filename = urlutils.split(url, exclude_trailing_slash=False)
4101
 
    location_transport = transport.get_transport(url)
4102
 
    if filename:
4103
 
        try:
4104
 
            # There may be redirections but we ignore the intermediate
4105
 
            # and final transports used
4106
 
            read = bundle.read_mergeable_from_transport
4107
 
            mergeable, t = read(location_transport, filename)
4108
 
        except errors.NotABundle:
4109
 
            # Continue on considering this url a Branch but adjust the
4110
 
            # location_transport
4111
 
            location_transport = location_transport.clone(filename)
4112
 
    return mergeable, location_transport
 
5177
 
 
5178
        tags = branch.tags.get_tag_dict().items()
 
5179
        if not tags:
 
5180
            return
 
5181
 
 
5182
        if revision:
 
5183
            branch.lock_read()
 
5184
            try:
 
5185
                graph = branch.repository.get_graph()
 
5186
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5187
                revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5188
                # only show revisions between revid1 and revid2 (inclusive)
 
5189
                tags = [(tag, revid) for tag, revid in tags if
 
5190
                    graph.is_between(revid, revid1, revid2)]
 
5191
            finally:
 
5192
                branch.unlock()
 
5193
        if sort == 'alpha':
 
5194
            tags.sort()
 
5195
        elif sort == 'time':
 
5196
            timestamps = {}
 
5197
            for tag, revid in tags:
 
5198
                try:
 
5199
                    revobj = branch.repository.get_revision(revid)
 
5200
                except errors.NoSuchRevision:
 
5201
                    timestamp = sys.maxint # place them at the end
 
5202
                else:
 
5203
                    timestamp = revobj.timestamp
 
5204
                timestamps[revid] = timestamp
 
5205
            tags.sort(key=lambda x: timestamps[x[1]])
 
5206
        if not show_ids:
 
5207
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5208
            revno_map = branch.get_revision_id_to_revno_map()
 
5209
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
 
5210
                        for tag, revid in tags ]
 
5211
        for tag, revspec in tags:
 
5212
            self.outf.write('%-20s %s\n' % (tag, revspec))
 
5213
 
 
5214
 
 
5215
class cmd_reconfigure(Command):
 
5216
    """Reconfigure the type of a bzr directory.
 
5217
 
 
5218
    A target configuration must be specified.
 
5219
 
 
5220
    For checkouts, the bind-to location will be auto-detected if not specified.
 
5221
    The order of preference is
 
5222
    1. For a lightweight checkout, the current bound location.
 
5223
    2. For branches that used to be checkouts, the previously-bound location.
 
5224
    3. The push location.
 
5225
    4. The parent location.
 
5226
    If none of these is available, --bind-to must be specified.
 
5227
    """
 
5228
 
 
5229
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
 
5230
    takes_args = ['location?']
 
5231
    takes_options = [
 
5232
        RegistryOption.from_kwargs(
 
5233
            'target_type',
 
5234
            title='Target type',
 
5235
            help='The type to reconfigure the directory to.',
 
5236
            value_switches=True, enum_switch=False,
 
5237
            branch='Reconfigure to be an unbound branch with no working tree.',
 
5238
            tree='Reconfigure to be an unbound branch with a working tree.',
 
5239
            checkout='Reconfigure to be a bound branch with a working tree.',
 
5240
            lightweight_checkout='Reconfigure to be a lightweight'
 
5241
                ' checkout (with no local history).',
 
5242
            standalone='Reconfigure to be a standalone branch '
 
5243
                '(i.e. stop using shared repository).',
 
5244
            use_shared='Reconfigure to use a shared repository.',
 
5245
            with_trees='Reconfigure repository to create '
 
5246
                'working trees on branches by default.',
 
5247
            with_no_trees='Reconfigure repository to not create '
 
5248
                'working trees on branches by default.'
 
5249
            ),
 
5250
        Option('bind-to', help='Branch to bind checkout to.', type=str),
 
5251
        Option('force',
 
5252
               help='Perform reconfiguration even if local changes'
 
5253
               ' will be lost.')
 
5254
        ]
 
5255
 
 
5256
    def run(self, location=None, target_type=None, bind_to=None, force=False):
 
5257
        directory = bzrdir.BzrDir.open(location)
 
5258
        if target_type is None:
 
5259
            raise errors.BzrCommandError('No target configuration specified')
 
5260
        elif target_type == 'branch':
 
5261
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
 
5262
        elif target_type == 'tree':
 
5263
            reconfiguration = reconfigure.Reconfigure.to_tree(directory)
 
5264
        elif target_type == 'checkout':
 
5265
            reconfiguration = reconfigure.Reconfigure.to_checkout(
 
5266
                directory, bind_to)
 
5267
        elif target_type == 'lightweight-checkout':
 
5268
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
 
5269
                directory, bind_to)
 
5270
        elif target_type == 'use-shared':
 
5271
            reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
 
5272
        elif target_type == 'standalone':
 
5273
            reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
 
5274
        elif target_type == 'with-trees':
 
5275
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
 
5276
                directory, True)
 
5277
        elif target_type == 'with-no-trees':
 
5278
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
 
5279
                directory, False)
 
5280
        reconfiguration.apply(force)
 
5281
 
 
5282
 
 
5283
class cmd_switch(Command):
 
5284
    """Set the branch of a checkout and update.
 
5285
 
 
5286
    For lightweight checkouts, this changes the branch being referenced.
 
5287
    For heavyweight checkouts, this checks that there are no local commits
 
5288
    versus the current bound branch, then it makes the local branch a mirror
 
5289
    of the new location and binds to it.
 
5290
 
 
5291
    In both cases, the working tree is updated and uncommitted changes
 
5292
    are merged. The user can commit or revert these as they desire.
 
5293
 
 
5294
    Pending merges need to be committed or reverted before using switch.
 
5295
 
 
5296
    The path to the branch to switch to can be specified relative to the parent
 
5297
    directory of the current branch. For example, if you are currently in a
 
5298
    checkout of /path/to/branch, specifying 'newbranch' will find a branch at
 
5299
    /path/to/newbranch.
 
5300
 
 
5301
    Bound branches use the nickname of its master branch unless it is set
 
5302
    locally, in which case switching will update the the local nickname to be
 
5303
    that of the master.
 
5304
    """
 
5305
 
 
5306
    takes_args = ['to_location']
 
5307
    takes_options = [Option('force',
 
5308
                        help='Switch even if local commits will be lost.')
 
5309
                     ]
 
5310
 
 
5311
    def run(self, to_location, force=False):
 
5312
        from bzrlib import switch
 
5313
        tree_location = '.'
 
5314
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
5315
        try:
 
5316
            branch = control_dir.open_branch()
 
5317
            had_explicit_nick = branch.get_config().has_explicit_nickname()
 
5318
        except errors.NotBranchError:
 
5319
            had_explicit_nick = False
 
5320
        try:
 
5321
            to_branch = Branch.open(to_location)
 
5322
        except errors.NotBranchError:
 
5323
            this_url = self._get_branch_location(control_dir)
 
5324
            to_branch = Branch.open(
 
5325
                urlutils.join(this_url, '..', to_location))
 
5326
        switch.switch(control_dir, to_branch, force)
 
5327
        if had_explicit_nick:
 
5328
            branch = control_dir.open_branch() #get the new branch!
 
5329
            branch.nick = to_branch.nick
 
5330
        note('Switched to branch: %s',
 
5331
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
 
5332
 
 
5333
    def _get_branch_location(self, control_dir):
 
5334
        """Return location of branch for this control dir."""
 
5335
        try:
 
5336
            this_branch = control_dir.open_branch()
 
5337
            # This may be a heavy checkout, where we want the master branch
 
5338
            master_location = this_branch.get_bound_location()
 
5339
            if master_location is not None:
 
5340
                return master_location
 
5341
            # If not, use a local sibling
 
5342
            return this_branch.base
 
5343
        except errors.NotBranchError:
 
5344
            format = control_dir.find_branch_format()
 
5345
            if getattr(format, 'get_reference', None) is not None:
 
5346
                return format.get_reference(control_dir)
 
5347
            else:
 
5348
                return control_dir.root_transport.base
 
5349
 
 
5350
 
 
5351
class cmd_view(Command):
 
5352
    """Manage filtered views.
 
5353
 
 
5354
    Views provide a mask over the tree so that users can focus on
 
5355
    a subset of a tree when doing their work. After creating a view,
 
5356
    commands that support a list of files - status, diff, commit, etc -
 
5357
    effectively have that list of files implicitly given each time.
 
5358
    An explicit list of files can still be given but those files
 
5359
    must be within the current view.
 
5360
 
 
5361
    In most cases, a view has a short life-span: it is created to make
 
5362
    a selected change and is deleted once that change is committed.
 
5363
    At other times, you may wish to create one or more named views
 
5364
    and switch between them.
 
5365
 
 
5366
    To disable the current view without deleting it, you can switch to
 
5367
    the pseudo view called ``off``. This can be useful when you need
 
5368
    to see the whole tree for an operation or two (e.g. merge) but
 
5369
    want to switch back to your view after that.
 
5370
 
 
5371
    :Examples:
 
5372
      To define the current view::
 
5373
 
 
5374
        bzr view file1 dir1 ...
 
5375
 
 
5376
      To list the current view::
 
5377
 
 
5378
        bzr view
 
5379
 
 
5380
      To delete the current view::
 
5381
 
 
5382
        bzr view --delete
 
5383
 
 
5384
      To disable the current view without deleting it::
 
5385
 
 
5386
        bzr view --switch off
 
5387
 
 
5388
      To define a named view and switch to it::
 
5389
 
 
5390
        bzr view --name view-name file1 dir1 ...
 
5391
 
 
5392
      To list a named view::
 
5393
 
 
5394
        bzr view --name view-name
 
5395
 
 
5396
      To delete a named view::
 
5397
 
 
5398
        bzr view --name view-name --delete
 
5399
 
 
5400
      To switch to a named view::
 
5401
 
 
5402
        bzr view --switch view-name
 
5403
 
 
5404
      To list all views defined::
 
5405
 
 
5406
        bzr view --all
 
5407
 
 
5408
      To delete all views::
 
5409
 
 
5410
        bzr view --delete --all
 
5411
    """
 
5412
 
 
5413
    _see_also = []
 
5414
    takes_args = ['file*']
 
5415
    takes_options = [
 
5416
        Option('all',
 
5417
            help='Apply list or delete action to all views.',
 
5418
            ),
 
5419
        Option('delete',
 
5420
            help='Delete the view.',
 
5421
            ),
 
5422
        Option('name',
 
5423
            help='Name of the view to define, list or delete.',
 
5424
            type=unicode,
 
5425
            ),
 
5426
        Option('switch',
 
5427
            help='Name of the view to switch to.',
 
5428
            type=unicode,
 
5429
            ),
 
5430
        ]
 
5431
 
 
5432
    def run(self, file_list,
 
5433
            all=False,
 
5434
            delete=False,
 
5435
            name=None,
 
5436
            switch=None,
 
5437
            ):
 
5438
        tree, file_list = tree_files(file_list, apply_view=False)
 
5439
        current_view, view_dict = tree.views.get_view_info()
 
5440
        if name is None:
 
5441
            name = current_view
 
5442
        if delete:
 
5443
            if file_list:
 
5444
                raise errors.BzrCommandError(
 
5445
                    "Both --delete and a file list specified")
 
5446
            elif switch:
 
5447
                raise errors.BzrCommandError(
 
5448
                    "Both --delete and --switch specified")
 
5449
            elif all:
 
5450
                tree.views.set_view_info(None, {})
 
5451
                self.outf.write("Deleted all views.\n")
 
5452
            elif name is None:
 
5453
                raise errors.BzrCommandError("No current view to delete")
 
5454
            else:
 
5455
                tree.views.delete_view(name)
 
5456
                self.outf.write("Deleted '%s' view.\n" % name)
 
5457
        elif switch:
 
5458
            if file_list:
 
5459
                raise errors.BzrCommandError(
 
5460
                    "Both --switch and a file list specified")
 
5461
            elif all:
 
5462
                raise errors.BzrCommandError(
 
5463
                    "Both --switch and --all specified")
 
5464
            elif switch == 'off':
 
5465
                if current_view is None:
 
5466
                    raise errors.BzrCommandError("No current view to disable")
 
5467
                tree.views.set_view_info(None, view_dict)
 
5468
                self.outf.write("Disabled '%s' view.\n" % (current_view))
 
5469
            else:
 
5470
                tree.views.set_view_info(switch, view_dict)
 
5471
                view_str = views.view_display_str(tree.views.lookup_view())
 
5472
                self.outf.write("Using '%s' view: %s\n" % (switch, view_str))
 
5473
        elif all:
 
5474
            if view_dict:
 
5475
                self.outf.write('Views defined:\n')
 
5476
                for view in sorted(view_dict):
 
5477
                    if view == current_view:
 
5478
                        active = "=>"
 
5479
                    else:
 
5480
                        active = "  "
 
5481
                    view_str = views.view_display_str(view_dict[view])
 
5482
                    self.outf.write('%s %-20s %s\n' % (active, view, view_str))
 
5483
            else:
 
5484
                self.outf.write('No views defined.\n')
 
5485
        elif file_list:
 
5486
            if name is None:
 
5487
                # No name given and no current view set
 
5488
                name = 'my'
 
5489
            elif name == 'off':
 
5490
                raise errors.BzrCommandError(
 
5491
                    "Cannot change the 'off' pseudo view")
 
5492
            tree.views.set_view(name, sorted(file_list))
 
5493
            view_str = views.view_display_str(tree.views.lookup_view())
 
5494
            self.outf.write("Using '%s' view: %s\n" % (name, view_str))
 
5495
        else:
 
5496
            # list the files
 
5497
            if name is None:
 
5498
                # No name given and no current view set
 
5499
                self.outf.write('No current view.\n')
 
5500
            else:
 
5501
                view_str = views.view_display_str(tree.views.lookup_view(name))
 
5502
                self.outf.write("'%s' view is: %s\n" % (name, view_str))
 
5503
 
 
5504
 
 
5505
class cmd_hooks(Command):
 
5506
    """Show hooks."""
 
5507
 
 
5508
    hidden = True
 
5509
 
 
5510
    def run(self):
 
5511
        for hook_key in sorted(hooks.known_hooks.keys()):
 
5512
            some_hooks = hooks.known_hooks_key_to_object(hook_key)
 
5513
            self.outf.write("%s:\n" % type(some_hooks).__name__)
 
5514
            for hook_name, hook_point in sorted(some_hooks.items()):
 
5515
                self.outf.write("  %s:\n" % (hook_name,))
 
5516
                found_hooks = list(hook_point)
 
5517
                if found_hooks:
 
5518
                    for hook in found_hooks:
 
5519
                        self.outf.write("    %s\n" %
 
5520
                                        (some_hooks.get_hook_name(hook),))
 
5521
                else:
 
5522
                    self.outf.write("    <no hooks installed>\n")
 
5523
 
 
5524
 
 
5525
class cmd_shelve(Command):
 
5526
    """Temporarily set aside some changes from the current tree.
 
5527
 
 
5528
    Shelve allows you to temporarily put changes you've made "on the shelf",
 
5529
    ie. out of the way, until a later time when you can bring them back from
 
5530
    the shelf with the 'unshelve' command.  The changes are stored alongside
 
5531
    your working tree, and so they aren't propagated along with your branch nor
 
5532
    will they survive its deletion.
 
5533
 
 
5534
    If shelve --list is specified, previously-shelved changes are listed.
 
5535
 
 
5536
    Shelve is intended to help separate several sets of changes that have
 
5537
    been inappropriately mingled.  If you just want to get rid of all changes
 
5538
    and you don't need to restore them later, use revert.  If you want to
 
5539
    shelve all text changes at once, use shelve --all.
 
5540
 
 
5541
    If filenames are specified, only the changes to those files will be
 
5542
    shelved. Other files will be left untouched.
 
5543
 
 
5544
    If a revision is specified, changes since that revision will be shelved.
 
5545
 
 
5546
    You can put multiple items on the shelf, and by default, 'unshelve' will
 
5547
    restore the most recently shelved changes.
 
5548
    """
 
5549
 
 
5550
    takes_args = ['file*']
 
5551
 
 
5552
    takes_options = [
 
5553
        'revision',
 
5554
        Option('all', help='Shelve all changes.'),
 
5555
        'message',
 
5556
        RegistryOption('writer', 'Method to use for writing diffs.',
 
5557
                       bzrlib.option.diff_writer_registry,
 
5558
                       value_switches=True, enum_switch=False),
 
5559
 
 
5560
        Option('list', help='List shelved changes.'),
 
5561
        Option('destroy',
 
5562
               help='Destroy removed changes instead of shelving them.'),
 
5563
    ]
 
5564
    _see_also = ['unshelve']
 
5565
 
 
5566
    def run(self, revision=None, all=False, file_list=None, message=None,
 
5567
            writer=None, list=False, destroy=False):
 
5568
        if list:
 
5569
            return self.run_for_list()
 
5570
        from bzrlib.shelf_ui import Shelver
 
5571
        if writer is None:
 
5572
            writer = bzrlib.option.diff_writer_registry.get()
 
5573
        try:
 
5574
            Shelver.from_args(writer(sys.stdout), revision, all, file_list,
 
5575
                              message, destroy=destroy).run()
 
5576
        except errors.UserAbort:
 
5577
            return 0
 
5578
 
 
5579
    def run_for_list(self):
 
5580
        tree = WorkingTree.open_containing('.')[0]
 
5581
        tree.lock_read()
 
5582
        try:
 
5583
            manager = tree.get_shelf_manager()
 
5584
            shelves = manager.active_shelves()
 
5585
            if len(shelves) == 0:
 
5586
                note('No shelved changes.')
 
5587
                return 0
 
5588
            for shelf_id in reversed(shelves):
 
5589
                message = manager.get_metadata(shelf_id).get('message')
 
5590
                if message is None:
 
5591
                    message = '<no message>'
 
5592
                self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5593
            return 1
 
5594
        finally:
 
5595
            tree.unlock()
 
5596
 
 
5597
 
 
5598
class cmd_unshelve(Command):
 
5599
    """Restore shelved changes.
 
5600
 
 
5601
    By default, the most recently shelved changes are restored. However if you
 
5602
    specify a shelf by id those changes will be restored instead.  This works
 
5603
    best when the changes don't depend on each other.
 
5604
    """
 
5605
 
 
5606
    takes_args = ['shelf_id?']
 
5607
    takes_options = [
 
5608
        RegistryOption.from_kwargs(
 
5609
            'action', help="The action to perform.",
 
5610
            enum_switch=False, value_switches=True,
 
5611
            apply="Apply changes and remove from the shelf.",
 
5612
            dry_run="Show changes, but do not apply or remove them.",
 
5613
            delete_only="Delete changes without applying them."
 
5614
        )
 
5615
    ]
 
5616
    _see_also = ['shelve']
 
5617
 
 
5618
    def run(self, shelf_id=None, action='apply'):
 
5619
        from bzrlib.shelf_ui import Unshelver
 
5620
        Unshelver.from_args(shelf_id, action).run()
 
5621
 
 
5622
 
 
5623
class cmd_clean_tree(Command):
 
5624
    """Remove unwanted files from working tree.
 
5625
 
 
5626
    By default, only unknown files, not ignored files, are deleted.  Versioned
 
5627
    files are never deleted.
 
5628
 
 
5629
    Another class is 'detritus', which includes files emitted by bzr during
 
5630
    normal operations and selftests.  (The value of these files decreases with
 
5631
    time.)
 
5632
 
 
5633
    If no options are specified, unknown files are deleted.  Otherwise, option
 
5634
    flags are respected, and may be combined.
 
5635
 
 
5636
    To check what clean-tree will do, use --dry-run.
 
5637
    """
 
5638
    takes_options = [Option('ignored', help='Delete all ignored files.'),
 
5639
                     Option('detritus', help='Delete conflict files, merge'
 
5640
                            ' backups, and failed selftest dirs.'),
 
5641
                     Option('unknown',
 
5642
                            help='Delete files unknown to bzr (default).'),
 
5643
                     Option('dry-run', help='Show files to delete instead of'
 
5644
                            ' deleting them.'),
 
5645
                     Option('force', help='Do not prompt before deleting.')]
 
5646
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
 
5647
            force=False):
 
5648
        from bzrlib.clean_tree import clean_tree
 
5649
        if not (unknown or ignored or detritus):
 
5650
            unknown = True
 
5651
        if dry_run:
 
5652
            force = True
 
5653
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
 
5654
                   dry_run=dry_run, no_prompt=force)
 
5655
 
 
5656
 
 
5657
class cmd_reference(Command):
 
5658
    """list, view and set branch locations for nested trees.
 
5659
 
 
5660
    If no arguments are provided, lists the branch locations for nested trees.
 
5661
    If one argument is provided, display the branch location for that tree.
 
5662
    If two arguments are provided, set the branch location for that tree.
 
5663
    """
 
5664
 
 
5665
    hidden = True
 
5666
 
 
5667
    takes_args = ['path?', 'location?']
 
5668
 
 
5669
    def run(self, path=None, location=None):
 
5670
        branchdir = '.'
 
5671
        if path is not None:
 
5672
            branchdir = path
 
5673
        tree, branch, relpath =(
 
5674
            bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
 
5675
        if path is not None:
 
5676
            path = relpath
 
5677
        if tree is None:
 
5678
            tree = branch.basis_tree()
 
5679
        if path is None:
 
5680
            info = branch._get_all_reference_info().iteritems()
 
5681
            self._display_reference_info(tree, branch, info)
 
5682
        else:
 
5683
            file_id = tree.path2id(path)
 
5684
            if file_id is None:
 
5685
                raise errors.NotVersionedError(path)
 
5686
            if location is None:
 
5687
                info = [(file_id, branch.get_reference_info(file_id))]
 
5688
                self._display_reference_info(tree, branch, info)
 
5689
            else:
 
5690
                branch.set_reference_info(file_id, path, location)
 
5691
 
 
5692
    def _display_reference_info(self, tree, branch, info):
 
5693
        ref_list = []
 
5694
        for file_id, (path, location) in info:
 
5695
            try:
 
5696
                path = tree.id2path(file_id)
 
5697
            except errors.NoSuchId:
 
5698
                pass
 
5699
            ref_list.append((path, location))
 
5700
        for path, location in sorted(ref_list):
 
5701
            self.outf.write('%s %s\n' % (path, location))
4113
5702
 
4114
5703
 
4115
5704
# these get imported and then picked up by the scan for cmd_*
4116
5705
# TODO: Some more consistent way to split command definitions across files;
4117
 
# we do need to load at least some information about them to know of 
 
5706
# we do need to load at least some information about them to know of
4118
5707
# aliases.  ideally we would avoid loading the implementation until the
4119
5708
# details were needed.
4120
5709
from bzrlib.cmd_version_info import cmd_version_info
4122
5711
from bzrlib.bundle.commands import (
4123
5712
    cmd_bundle_info,
4124
5713
    )
 
5714
from bzrlib.foreign import cmd_dpush
4125
5715
from bzrlib.sign_my_commits import cmd_sign_my_commits
4126
 
from bzrlib.weave_commands import cmd_versionedfile_list, cmd_weave_join, \
 
5716
from bzrlib.weave_commands import cmd_versionedfile_list, \
4127
5717
        cmd_weave_plan_merge, cmd_weave_merge_text