~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Martin Pool
  • Date: 2005-09-13 23:08:19 UTC
  • Revision ID: mbp@sourcefrog.net-20050913230819-6ceae96050d32faa
ignore .bzr-shelf

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2004, 2005 by Canonical Ltd
 
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
"""builtin bzr commands"""
18
17
 
 
18
import sys
19
19
import os
20
 
from StringIO import StringIO
21
 
 
22
 
from bzrlib.lazy_import import lazy_import
23
 
lazy_import(globals(), """
24
 
import codecs
25
 
import errno
26
 
import sys
27
 
import tempfile
28
 
import time
29
20
 
30
21
import bzrlib
31
 
from bzrlib import (
32
 
    branch,
33
 
    bugtracker,
34
 
    bundle,
35
 
    bzrdir,
36
 
    delta,
37
 
    config,
38
 
    errors,
39
 
    globbing,
40
 
    ignores,
41
 
    log,
42
 
    merge as _mod_merge,
43
 
    merge_directive,
44
 
    osutils,
45
 
    reconfigure,
46
 
    registry,
47
 
    repository,
48
 
    revision as _mod_revision,
49
 
    revisionspec,
50
 
    symbol_versioning,
51
 
    transport,
52
 
    tree as _mod_tree,
53
 
    ui,
54
 
    urlutils,
55
 
    )
56
 
from bzrlib.branch import Branch
57
 
from bzrlib.conflicts import ConflictList
58
 
from bzrlib.revisionspec import RevisionSpec
59
 
from bzrlib.smtp_connection import SMTPConnection
60
 
from bzrlib.workingtree import WorkingTree
61
 
""")
62
 
 
63
 
from bzrlib.commands import Command, display_command
64
 
from bzrlib.option import ListOption, Option, RegistryOption, custom_help
65
 
from bzrlib.progress import DummyProgress, ProgressPhase
66
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
67
 
 
68
 
 
69
 
def tree_files(file_list, default_branch=u'.'):
70
 
    try:
71
 
        return internal_tree_files(file_list, default_branch)
72
 
    except errors.FileInWrongBranch, e:
73
 
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
74
 
                                     (e.path, file_list[0]))
75
 
 
76
 
 
77
 
# XXX: Bad function name; should possibly also be a class method of
78
 
# WorkingTree rather than a function.
79
 
def internal_tree_files(file_list, default_branch=u'.'):
80
 
    """Convert command-line paths to a WorkingTree and relative paths.
81
 
 
82
 
    This is typically used for command-line processors that take one or
83
 
    more filenames, and infer the workingtree that contains them.
84
 
 
85
 
    The filenames given are not required to exist.
86
 
 
87
 
    :param file_list: Filenames to convert.  
88
 
 
89
 
    :param default_branch: Fallback tree path to use if file_list is empty or
90
 
        None.
91
 
 
92
 
    :return: workingtree, [relative_paths]
93
 
    """
94
 
    if file_list is None or len(file_list) == 0:
95
 
        return WorkingTree.open_containing(default_branch)[0], file_list
96
 
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
97
 
    new_list = []
98
 
    for filename in file_list:
99
 
        try:
100
 
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
101
 
        except errors.PathNotChild:
102
 
            raise errors.FileInWrongBranch(tree.branch, filename)
103
 
    return tree, new_list
104
 
 
105
 
 
106
 
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
107
 
def get_format_type(typestring):
108
 
    """Parse and return a format specifier."""
109
 
    # Have to use BzrDirMetaFormat1 directly, so that
110
 
    # RepositoryFormat.set_default_format works
111
 
    if typestring == "default":
112
 
        return bzrdir.BzrDirMetaFormat1()
113
 
    try:
114
 
        return bzrdir.format_registry.make_bzrdir(typestring)
115
 
    except KeyError:
116
 
        msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
117
 
        raise errors.BzrCommandError(msg)
118
 
 
119
 
 
120
 
# TODO: Make sure no commands unconditionally use the working directory as a
121
 
# branch.  If a filename argument is used, the first of them should be used to
122
 
# specify the branch.  (Perhaps this can be factored out into some kind of
123
 
# Argument class, representing a file in a branch, where the first occurrence
124
 
# opens the branch?)
 
22
import bzrlib.trace
 
23
from bzrlib.trace import mutter, note, log_error, warning
 
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
 
25
from bzrlib.branch import find_branch
 
26
from bzrlib import BZRDIR
 
27
from bzrlib.commands import Command
 
28
 
125
29
 
126
30
class cmd_status(Command):
127
31
    """Display status summary.
144
48
    modified
145
49
        Text has changed since the previous revision.
146
50
 
147
 
    kind changed
148
 
        File kind has been changed (e.g. from file to directory).
 
51
    unchanged
 
52
        Nothing about this file has changed since the previous revision.
 
53
        Only shown with --all.
149
54
 
150
55
    unknown
151
56
        Not versioned and not matching an ignore pattern.
152
57
 
153
 
    To see ignored files use 'bzr ignored'.  For details on the
 
58
    To see ignored files use 'bzr ignored'.  For details in the
154
59
    changes to file texts, use 'bzr diff'.
155
 
    
156
 
    Note that --short or -S gives status flags for each item, similar
157
 
    to Subversion's status command. To get output similar to svn -q,
158
 
    use bzr -SV.
159
60
 
160
61
    If no arguments are specified, the status of the entire working
161
62
    directory is shown.  Otherwise, only the status of the specified
162
63
    files or directories is reported.  If a directory is given, status
163
64
    is reported for everything inside that directory.
164
65
 
165
 
    If a revision argument is given, the status is calculated against
166
 
    that revision, or between two revisions if two are provided.
 
66
    If a revision is specified, the changes since that revision are shown.
167
67
    """
168
 
    
169
 
    # TODO: --no-recurse, --recurse options
170
 
    
171
68
    takes_args = ['file*']
172
 
    takes_options = ['show-ids', 'revision', 'change',
173
 
                     Option('short', help='Use short status indicators.',
174
 
                            short_name='S'),
175
 
                     Option('versioned', help='Only show versioned files.',
176
 
                            short_name='V')
177
 
                     ]
 
69
    takes_options = ['all', 'show-ids', 'revision']
178
70
    aliases = ['st', 'stat']
179
 
 
180
 
    encoding_type = 'replace'
181
 
    _see_also = ['diff', 'revert', 'status-flags']
182
71
    
183
 
    @display_command
184
 
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
185
 
            versioned=False):
186
 
        from bzrlib.status import show_tree_status
187
 
 
188
 
        if revision and len(revision) > 2:
189
 
            raise errors.BzrCommandError('bzr status --revision takes exactly'
190
 
                                         ' one or two revision specifiers')
191
 
 
192
 
        tree, file_list = tree_files(file_list)
 
72
    def run(self, all=False, show_ids=False, file_list=None):
 
73
        if file_list:
 
74
            b = find_branch(file_list[0])
 
75
            file_list = [b.relpath(x) for x in file_list]
 
76
            # special case: only one path was given and it's the root
 
77
            # of the branch
 
78
            if file_list == ['']:
 
79
                file_list = None
 
80
        else:
 
81
            b = find_branch('.')
193
82
            
194
 
        show_tree_status(tree, show_ids=show_ids,
195
 
                         specific_files=file_list, revision=revision,
196
 
                         to_file=self.outf, short=short, versioned=versioned)
 
83
        from bzrlib.status import show_status
 
84
        show_status(b, show_unchanged=all, show_ids=show_ids,
 
85
                    specific_files=file_list)
197
86
 
198
87
 
199
88
class cmd_cat_revision(Command):
200
 
    """Write out metadata for a revision.
201
 
    
202
 
    The revision to print can either be specified by a specific
203
 
    revision identifier, or you can use --revision.
204
 
    """
 
89
    """Write out metadata for a revision."""
205
90
 
206
91
    hidden = True
207
 
    takes_args = ['revision_id?']
208
 
    takes_options = ['revision']
209
 
    # cat-revision is more for frontends so should be exact
210
 
    encoding = 'strict'
211
 
    
212
 
    @display_command
213
 
    def run(self, revision_id=None, revision=None):
214
 
 
215
 
        revision_id = osutils.safe_revision_id(revision_id, warn=False)
216
 
        if revision_id is not None and revision is not None:
217
 
            raise errors.BzrCommandError('You can only supply one of'
218
 
                                         ' revision_id or --revision')
219
 
        if revision_id is None and revision is None:
220
 
            raise errors.BzrCommandError('You must supply either'
221
 
                                         ' --revision or a revision_id')
222
 
        b = WorkingTree.open_containing(u'.')[0].branch
223
 
 
224
 
        # TODO: jam 20060112 should cat-revision always output utf-8?
225
 
        if revision_id is not None:
226
 
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
227
 
        elif revision is not None:
228
 
            for rev in revision:
229
 
                if rev is None:
230
 
                    raise errors.BzrCommandError('You cannot specify a NULL'
231
 
                                                 ' revision.')
232
 
                revno, rev_id = rev.in_history(b)
233
 
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
234
 
    
235
 
 
236
 
class cmd_remove_tree(Command):
237
 
    """Remove the working tree from a given branch/checkout.
238
 
 
239
 
    Since a lightweight checkout is little more than a working tree
240
 
    this will refuse to run against one.
241
 
 
242
 
    To re-create the working tree, use "bzr checkout".
243
 
    """
244
 
    _see_also = ['checkout', 'working-trees']
245
 
 
246
 
    takes_args = ['location?']
247
 
 
248
 
    def run(self, location='.'):
249
 
        d = bzrdir.BzrDir.open(location)
250
 
        
251
 
        try:
252
 
            working = d.open_workingtree()
253
 
        except errors.NoWorkingTree:
254
 
            raise errors.BzrCommandError("No working tree to remove")
255
 
        except errors.NotLocalUrl:
256
 
            raise errors.BzrCommandError("You cannot remove the working tree of a "
257
 
                                         "remote path")
258
 
        
259
 
        working_path = working.bzrdir.root_transport.base
260
 
        branch_path = working.branch.bzrdir.root_transport.base
261
 
        if working_path != branch_path:
262
 
            raise errors.BzrCommandError("You cannot remove the working tree from "
263
 
                                         "a lightweight checkout")
264
 
        
265
 
        d.destroy_workingtree()
266
 
        
 
92
    takes_args = ['revision_id']
 
93
    
 
94
    def run(self, revision_id):
 
95
        b = find_branch('.')
 
96
        sys.stdout.write(b.get_revision_xml_file(revision_id).read())
 
97
 
267
98
 
268
99
class cmd_revno(Command):
269
100
    """Show current revision number.
270
101
 
271
 
    This is equal to the number of revisions on this branch.
272
 
    """
273
 
 
274
 
    _see_also = ['info']
275
 
    takes_args = ['location?']
276
 
 
277
 
    @display_command
278
 
    def run(self, location=u'.'):
279
 
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
280
 
        self.outf.write('\n')
 
102
    This is equal to the number of revisions on this branch."""
 
103
    def run(self):
 
104
        print find_branch('.').revno()
281
105
 
282
106
 
283
107
class cmd_revision_info(Command):
286
110
    hidden = True
287
111
    takes_args = ['revision_info*']
288
112
    takes_options = ['revision']
289
 
 
290
 
    @display_command
291
 
    def run(self, revision=None, revision_info_list=[]):
 
113
    def run(self, revision=None, revision_info_list=None):
 
114
        from bzrlib.branch import find_branch
292
115
 
293
116
        revs = []
294
117
        if revision is not None:
295
118
            revs.extend(revision)
296
119
        if revision_info_list is not None:
297
 
            for rev in revision_info_list:
298
 
                revs.append(RevisionSpec.from_string(rev))
299
 
 
300
 
        b = Branch.open_containing(u'.')[0]
301
 
 
 
120
            revs.extend(revision_info_list)
302
121
        if len(revs) == 0:
303
 
            revs.append(RevisionSpec.from_string('-1'))
 
122
            raise BzrCommandError('You must supply a revision identifier')
 
123
 
 
124
        b = find_branch('.')
304
125
 
305
126
        for rev in revs:
306
 
            revinfo = rev.in_history(b)
307
 
            if revinfo.revno is None:
308
 
                dotted_map = b.get_revision_id_to_revno_map()
309
 
                revno = '.'.join(str(i) for i in dotted_map[revinfo.rev_id])
310
 
                print '%s %s' % (revno, revinfo.rev_id)
311
 
            else:
312
 
                print '%4d %s' % (revinfo.revno, revinfo.rev_id)
 
127
            print '%4d %s' % b.get_revision_info(rev)
313
128
 
314
129
    
315
130
class cmd_add(Command):
330
145
    Therefore simply saying 'bzr add' will version all files that
331
146
    are currently unknown.
332
147
 
333
 
    Adding a file whose parent directory is not versioned will
334
 
    implicitly add the parent, and so on up to the root. This means
335
 
    you should never need to explicitly add a directory, they'll just
336
 
    get added when you add a file in the directory.
337
 
 
338
 
    --dry-run will show which files would be added, but not actually 
339
 
    add them.
340
 
 
341
 
    --file-ids-from will try to use the file ids from the supplied path.
342
 
    It looks up ids trying to find a matching parent directory with the
343
 
    same filename, and then by pure path. This option is rarely needed
344
 
    but can be useful when adding the same logical file into two
345
 
    branches that will be merged later (without showing the two different
346
 
    adds as a conflict). It is also useful when merging another project
347
 
    into a subdirectory of this one.
 
148
    TODO: Perhaps adding a file whose directly is not versioned should
 
149
    recursively add that parent, rather than giving an error?
348
150
    """
349
151
    takes_args = ['file*']
350
 
    takes_options = [
351
 
        Option('no-recurse',
352
 
               help="Don't recursively add the contents of directories."),
353
 
        Option('dry-run',
354
 
               help="Show what would be done, but don't actually do anything."),
355
 
        'verbose',
356
 
        Option('file-ids-from',
357
 
               type=unicode,
358
 
               help='Lookup file ids from this tree.'),
359
 
        ]
360
 
    encoding_type = 'replace'
361
 
    _see_also = ['remove']
362
 
 
363
 
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
364
 
            file_ids_from=None):
365
 
        import bzrlib.add
366
 
 
367
 
        base_tree = None
368
 
        if file_ids_from is not None:
369
 
            try:
370
 
                base_tree, base_path = WorkingTree.open_containing(
371
 
                                            file_ids_from)
372
 
            except errors.NoWorkingTree:
373
 
                base_branch, base_path = Branch.open_containing(
374
 
                                            file_ids_from)
375
 
                base_tree = base_branch.basis_tree()
376
 
 
377
 
            action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
378
 
                          to_file=self.outf, should_print=(not is_quiet()))
379
 
        else:
380
 
            action = bzrlib.add.AddAction(to_file=self.outf,
381
 
                should_print=(not is_quiet()))
382
 
 
383
 
        if base_tree:
384
 
            base_tree.lock_read()
385
 
        try:
386
 
            file_list = self._maybe_expand_globs(file_list)
387
 
            if file_list:
388
 
                tree = WorkingTree.open_containing(file_list[0])[0]
389
 
            else:
390
 
                tree = WorkingTree.open_containing(u'.')[0]
391
 
            added, ignored = tree.smart_add(file_list, not
392
 
                no_recurse, action=action, save=not dry_run)
393
 
        finally:
394
 
            if base_tree is not None:
395
 
                base_tree.unlock()
396
 
        if len(ignored) > 0:
397
 
            if verbose:
398
 
                for glob in sorted(ignored.keys()):
399
 
                    for path in ignored[glob]:
400
 
                        self.outf.write("ignored %s matching \"%s\"\n" 
401
 
                                        % (path, glob))
402
 
            else:
403
 
                match_len = 0
404
 
                for glob, paths in ignored.items():
405
 
                    match_len += len(paths)
406
 
                self.outf.write("ignored %d file(s).\n" % match_len)
407
 
            self.outf.write("If you wish to add some of these files,"
408
 
                            " please add them by name.\n")
 
152
    takes_options = ['verbose', 'no-recurse']
 
153
    
 
154
    def run(self, file_list, verbose=False, no_recurse=False):
 
155
        # verbose currently has no effect
 
156
        from bzrlib.add import smart_add, add_reporter_print
 
157
        smart_add(file_list, not no_recurse, add_reporter_print)
 
158
 
409
159
 
410
160
 
411
161
class cmd_mkdir(Command):
413
163
 
414
164
    This is equivalent to creating the directory and then adding it.
415
165
    """
416
 
 
417
166
    takes_args = ['dir+']
418
 
    encoding_type = 'replace'
419
167
 
420
168
    def run(self, dir_list):
 
169
        b = None
 
170
        
421
171
        for d in dir_list:
422
172
            os.mkdir(d)
423
 
            wt, dd = WorkingTree.open_containing(d)
424
 
            wt.add([dd])
425
 
            self.outf.write('added %s\n' % d)
 
173
            if not b:
 
174
                b = find_branch(d)
 
175
            b.add([d])
 
176
            print 'added', d
426
177
 
427
178
 
428
179
class cmd_relpath(Command):
429
180
    """Show path of a file relative to root"""
430
 
 
431
181
    takes_args = ['filename']
432
182
    hidden = True
433
183
    
434
 
    @display_command
435
184
    def run(self, filename):
436
 
        # TODO: jam 20050106 Can relpath return a munged path if
437
 
        #       sys.stdout encoding cannot represent it?
438
 
        tree, relpath = WorkingTree.open_containing(filename)
439
 
        self.outf.write(relpath)
440
 
        self.outf.write('\n')
 
185
        print find_branch(filename).relpath(filename)
 
186
 
441
187
 
442
188
 
443
189
class cmd_inventory(Command):
444
 
    """Show inventory of the current working copy or a revision.
445
 
 
446
 
    It is possible to limit the output to a particular entry
447
 
    type using the --kind option.  For example: --kind file.
448
 
 
449
 
    It is also possible to restrict the list of files to a specific
450
 
    set. For example: bzr inventory --show-ids this/file
451
 
    """
452
 
 
453
 
    hidden = True
454
 
    _see_also = ['ls']
455
 
    takes_options = [
456
 
        'revision',
457
 
        'show-ids',
458
 
        Option('kind',
459
 
               help='List entries of a particular kind: file, directory, symlink.',
460
 
               type=unicode),
461
 
        ]
462
 
    takes_args = ['file*']
463
 
 
464
 
    @display_command
465
 
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
466
 
        if kind and kind not in ['file', 'directory', 'symlink']:
467
 
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
468
 
 
469
 
        work_tree, file_list = tree_files(file_list)
470
 
        work_tree.lock_read()
471
 
        try:
472
 
            if revision is not None:
473
 
                if len(revision) > 1:
474
 
                    raise errors.BzrCommandError(
475
 
                        'bzr inventory --revision takes exactly one revision'
476
 
                        ' identifier')
477
 
                revision_id = revision[0].in_history(work_tree.branch).rev_id
478
 
                tree = work_tree.branch.repository.revision_tree(revision_id)
479
 
 
480
 
                extra_trees = [work_tree]
481
 
                tree.lock_read()
482
 
            else:
483
 
                tree = work_tree
484
 
                extra_trees = []
485
 
 
486
 
            if file_list is not None:
487
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
488
 
                                          require_versioned=True)
489
 
                # find_ids_across_trees may include some paths that don't
490
 
                # exist in 'tree'.
491
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
492
 
                                 for file_id in file_ids if file_id in tree)
493
 
            else:
494
 
                entries = tree.inventory.entries()
495
 
        finally:
496
 
            tree.unlock()
497
 
            if tree is not work_tree:
498
 
                work_tree.unlock()
499
 
 
500
 
        for path, entry in entries:
501
 
            if kind and kind != entry.kind:
502
 
                continue
 
190
    """Show inventory of the current working copy or a revision."""
 
191
    takes_options = ['revision', 'show-ids']
 
192
    
 
193
    def run(self, revision=None, show_ids=False):
 
194
        b = find_branch('.')
 
195
        if revision == None:
 
196
            inv = b.read_working_inventory()
 
197
        else:
 
198
            if len(revision) > 1:
 
199
                raise BzrCommandError('bzr inventory --revision takes'
 
200
                    ' exactly one revision identifier')
 
201
            inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
 
202
 
 
203
        for path, entry in inv.entries():
503
204
            if show_ids:
504
 
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
 
205
                print '%-50s %s' % (path, entry.file_id)
505
206
            else:
506
 
                self.outf.write(path)
507
 
                self.outf.write('\n')
 
207
                print path
 
208
 
 
209
 
 
210
class cmd_move(Command):
 
211
    """Move files to a different directory.
 
212
 
 
213
    examples:
 
214
        bzr move *.txt doc
 
215
 
 
216
    The destination must be a versioned directory in the same branch.
 
217
    """
 
218
    takes_args = ['source$', 'dest']
 
219
    def run(self, source_list, dest):
 
220
        b = find_branch('.')
 
221
 
 
222
        # TODO: glob expansion on windows?
 
223
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
 
224
 
 
225
 
 
226
class cmd_rename(Command):
 
227
    """Change the name of an entry.
 
228
 
 
229
    examples:
 
230
      bzr rename frob.c frobber.c
 
231
      bzr rename src/frob.c lib/frob.c
 
232
 
 
233
    It is an error if the destination name exists.
 
234
 
 
235
    See also the 'move' command, which moves files into a different
 
236
    directory without changing their name.
 
237
 
 
238
    TODO: Some way to rename multiple files without invoking bzr for each
 
239
    one?"""
 
240
    takes_args = ['from_name', 'to_name']
 
241
    
 
242
    def run(self, from_name, to_name):
 
243
        b = find_branch('.')
 
244
        b.rename_one(b.relpath(from_name), b.relpath(to_name))
 
245
 
508
246
 
509
247
 
510
248
class cmd_mv(Command):
511
249
    """Move or rename a file.
512
250
 
513
 
    :Usage:
 
251
    usage:
514
252
        bzr mv OLDNAME NEWNAME
515
 
 
516
253
        bzr mv SOURCE... DESTINATION
517
254
 
518
255
    If the last argument is a versioned directory, all the other names
519
256
    are moved into it.  Otherwise, there must be exactly two arguments
520
 
    and the file is changed to a new name.
521
 
 
522
 
    If OLDNAME does not exist on the filesystem but is versioned and
523
 
    NEWNAME does exist on the filesystem but is not versioned, mv
524
 
    assumes that the file has been manually moved and only updates
525
 
    its internal inventory to reflect that change.
526
 
    The same is valid when moving many SOURCE files to a DESTINATION.
 
257
    and the file is changed to a new name, which must not already exist.
527
258
 
528
259
    Files cannot be moved between branches.
529
260
    """
530
 
 
531
261
    takes_args = ['names*']
532
 
    takes_options = [Option("after", help="Move only the bzr identifier"
533
 
        " of the file, because the file has already been moved."),
534
 
        ]
535
 
    aliases = ['move', 'rename']
536
 
    encoding_type = 'replace'
537
 
 
538
 
    def run(self, names_list, after=False):
539
 
        if names_list is None:
540
 
            names_list = []
541
 
 
 
262
    def run(self, names_list):
542
263
        if len(names_list) < 2:
543
 
            raise errors.BzrCommandError("missing file argument")
544
 
        tree, rel_names = tree_files(names_list)
 
264
            raise BzrCommandError("missing file argument")
 
265
        b = find_branch(names_list[0])
 
266
 
 
267
        rel_names = [b.relpath(x) for x in names_list]
545
268
        
546
269
        if os.path.isdir(names_list[-1]):
547
270
            # move into existing directory
548
 
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
549
 
                self.outf.write("%s => %s\n" % pair)
 
271
            for pair in b.move(rel_names[:-1], rel_names[-1]):
 
272
                print "%s => %s" % pair
550
273
        else:
551
274
            if len(names_list) != 2:
552
 
                raise errors.BzrCommandError('to mv multiple files the'
553
 
                                             ' destination must be a versioned'
554
 
                                             ' directory')
555
 
            tree.rename_one(rel_names[0], rel_names[1], after=after)
556
 
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
 
275
                raise BzrCommandError('to mv multiple files the destination '
 
276
                                      'must be a versioned directory')
 
277
            for pair in b.move(rel_names[0], rel_names[1]):
 
278
                print "%s => %s" % pair
557
279
            
558
280
    
 
281
 
 
282
 
559
283
class cmd_pull(Command):
560
 
    """Turn this branch into a mirror of another branch.
561
 
 
562
 
    This command only works on branches that have not diverged.  Branches are
563
 
    considered diverged if the destination branch's most recent commit is one
564
 
    that has not been merged (directly or indirectly) into the parent.
565
 
 
566
 
    If branches have diverged, you can use 'bzr merge' to integrate the changes
567
 
    from one into the other.  Once one branch has merged, the other should
568
 
    be able to pull it again.
569
 
 
570
 
    If you want to forget your local changes and just update your branch to
571
 
    match the remote one, use pull --overwrite.
572
 
 
573
 
    If there is no default location set, the first pull will set it.  After
574
 
    that, you can omit the location to use the default.  To change the
575
 
    default, use --remember. The value will only be saved if the remote
576
 
    location can be accessed.
577
 
    """
578
 
 
579
 
    _see_also = ['push', 'update', 'status-flags']
580
 
    takes_options = ['remember', 'overwrite', 'revision',
581
 
        custom_help('verbose',
582
 
            help='Show logs of pulled revisions.'),
583
 
        Option('directory',
584
 
            help='Branch to pull into, '
585
 
                 'rather than the one containing the working directory.',
586
 
            short_name='d',
587
 
            type=unicode,
588
 
            ),
589
 
        ]
590
 
    takes_args = ['location?']
591
 
    encoding_type = 'replace'
592
 
 
593
 
    def run(self, location=None, remember=False, overwrite=False,
594
 
            revision=None, verbose=False,
595
 
            directory=None):
596
 
        # FIXME: too much stuff is in the command class
597
 
        revision_id = None
598
 
        mergeable = None
599
 
        if directory is None:
600
 
            directory = u'.'
601
 
        try:
602
 
            tree_to = WorkingTree.open_containing(directory)[0]
603
 
            branch_to = tree_to.branch
604
 
        except errors.NoWorkingTree:
605
 
            tree_to = None
606
 
            branch_to = Branch.open_containing(directory)[0]
607
 
 
608
 
        if location is not None:
609
 
            mergeable, location_transport = _get_mergeable_helper(location)
610
 
 
611
 
        stored_loc = branch_to.get_parent()
612
 
        if location is None:
613
 
            if stored_loc is None:
614
 
                raise errors.BzrCommandError("No pull location known or"
615
 
                                             " specified.")
616
 
            else:
617
 
                display_url = urlutils.unescape_for_display(stored_loc,
618
 
                        self.outf.encoding)
619
 
                self.outf.write("Using saved location: %s\n" % display_url)
620
 
                location = stored_loc
621
 
                location_transport = transport.get_transport(location)
622
 
 
623
 
        if mergeable is not None:
624
 
            if revision is not None:
625
 
                raise errors.BzrCommandError(
626
 
                    'Cannot use -r with merge directives or bundles')
627
 
            mergeable.install_revisions(branch_to.repository)
628
 
            base_revision_id, revision_id, verified = \
629
 
                mergeable.get_merge_request(branch_to.repository)
630
 
            branch_from = branch_to
631
 
        else:
632
 
            branch_from = Branch.open_from_transport(location_transport)
633
 
 
634
 
            if branch_to.get_parent() is None or remember:
635
 
                branch_to.set_parent(branch_from.base)
636
 
 
637
 
        if revision is not None:
638
 
            if len(revision) == 1:
639
 
                revision_id = revision[0].in_history(branch_from).rev_id
640
 
            else:
641
 
                raise errors.BzrCommandError(
642
 
                    'bzr pull --revision takes one value.')
643
 
 
644
 
        if verbose:
645
 
            old_rh = branch_to.revision_history()
646
 
        if tree_to is not None:
647
 
            result = tree_to.pull(branch_from, overwrite, revision_id,
648
 
                delta._ChangeReporter(unversioned_filter=tree_to.is_ignored))
649
 
        else:
650
 
            result = branch_to.pull(branch_from, overwrite, revision_id)
651
 
 
652
 
        result.report(self.outf)
653
 
        if verbose:
654
 
            new_rh = branch_to.revision_history()
655
 
            log.show_changed_revisions(branch_to, old_rh, new_rh,
656
 
                                       to_file=self.outf)
657
 
 
658
 
 
659
 
class cmd_push(Command):
660
 
    """Update a mirror of this branch.
661
 
    
662
 
    The target branch will not have its working tree populated because this
663
 
    is both expensive, and is not supported on remote file systems.
664
 
    
665
 
    Some smart servers or protocols *may* put the working tree in place in
666
 
    the future.
667
 
 
668
 
    This command only works on branches that have not diverged.  Branches are
669
 
    considered diverged if the destination branch's most recent commit is one
670
 
    that has not been merged (directly or indirectly) by the source branch.
671
 
 
672
 
    If branches have diverged, you can use 'bzr push --overwrite' to replace
673
 
    the other branch completely, discarding its unmerged changes.
674
 
    
675
 
    If you want to ensure you have the different changes in the other branch,
676
 
    do a merge (see bzr help merge) from the other branch, and commit that.
677
 
    After that you will be able to do a push without '--overwrite'.
678
 
 
679
 
    If there is no default push location set, the first push will set it.
680
 
    After that, you can omit the location to use the default.  To change the
681
 
    default, use --remember. The value will only be saved if the remote
682
 
    location can be accessed.
683
 
    """
684
 
 
685
 
    _see_also = ['pull', 'update', 'working-trees']
686
 
    takes_options = ['remember', 'overwrite', 'verbose',
687
 
        Option('create-prefix',
688
 
               help='Create the path leading up to the branch '
689
 
                    'if it does not already exist.'),
690
 
        Option('directory',
691
 
            help='Branch to push from, '
692
 
                 'rather than the one containing the working directory.',
693
 
            short_name='d',
694
 
            type=unicode,
695
 
            ),
696
 
        Option('use-existing-dir',
697
 
               help='By default push will fail if the target'
698
 
                    ' directory exists, but does not already'
699
 
                    ' have a control directory.  This flag will'
700
 
                    ' allow push to proceed.'),
701
 
        ]
702
 
    takes_args = ['location?']
703
 
    encoding_type = 'replace'
704
 
 
705
 
    def run(self, location=None, remember=False, overwrite=False,
706
 
            create_prefix=False, verbose=False,
707
 
            use_existing_dir=False,
708
 
            directory=None):
709
 
        # FIXME: Way too big!  Put this into a function called from the
710
 
        # command.
711
 
        if directory is None:
712
 
            directory = '.'
713
 
        br_from = Branch.open_containing(directory)[0]
714
 
        stored_loc = br_from.get_push_location()
715
 
        if location is None:
716
 
            if stored_loc is None:
717
 
                raise errors.BzrCommandError("No push location known or specified.")
718
 
            else:
719
 
                display_url = urlutils.unescape_for_display(stored_loc,
720
 
                        self.outf.encoding)
721
 
                self.outf.write("Using saved location: %s\n" % display_url)
722
 
                location = stored_loc
723
 
 
724
 
        to_transport = transport.get_transport(location)
725
 
 
726
 
        br_to = repository_to = dir_to = None
727
 
        try:
728
 
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
729
 
        except errors.NotBranchError:
730
 
            pass # Didn't find anything
731
 
        else:
732
 
            # If we can open a branch, use its direct repository, otherwise see
733
 
            # if there is a repository without a branch.
734
 
            try:
735
 
                br_to = dir_to.open_branch()
736
 
            except errors.NotBranchError:
737
 
                # Didn't find a branch, can we find a repository?
738
 
                try:
739
 
                    repository_to = dir_to.find_repository()
740
 
                except errors.NoRepositoryPresent:
741
 
                    pass
742
 
            else:
743
 
                # Found a branch, so we must have found a repository
744
 
                repository_to = br_to.repository
745
 
        push_result = None
746
 
        if verbose:
747
 
            old_rh = []
748
 
        if dir_to is None:
749
 
            # The destination doesn't exist; create it.
750
 
            # XXX: Refactor the create_prefix/no_create_prefix code into a
751
 
            #      common helper function
752
 
            try:
753
 
                to_transport.mkdir('.')
754
 
            except errors.FileExists:
755
 
                if not use_existing_dir:
756
 
                    raise errors.BzrCommandError("Target directory %s"
757
 
                         " already exists, but does not have a valid .bzr"
758
 
                         " directory. Supply --use-existing-dir to push"
759
 
                         " there anyway." % location)
760
 
            except errors.NoSuchFile:
761
 
                if not create_prefix:
762
 
                    raise errors.BzrCommandError("Parent directory of %s"
763
 
                        " does not exist."
764
 
                        "\nYou may supply --create-prefix to create all"
765
 
                        " leading parent directories."
766
 
                        % location)
767
 
                _create_prefix(to_transport)
768
 
 
769
 
            # Now the target directory exists, but doesn't have a .bzr
770
 
            # directory. So we need to create it, along with any work to create
771
 
            # all of the dependent branches, etc.
772
 
            dir_to = br_from.bzrdir.clone_on_transport(to_transport,
773
 
                revision_id=br_from.last_revision())
774
 
            br_to = dir_to.open_branch()
775
 
            # TODO: Some more useful message about what was copied
776
 
            note('Created new branch.')
777
 
            # We successfully created the target, remember it
778
 
            if br_from.get_push_location() is None or remember:
779
 
                br_from.set_push_location(br_to.base)
780
 
        elif repository_to is None:
781
 
            # we have a bzrdir but no branch or repository
782
 
            # XXX: Figure out what to do other than complain.
783
 
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
784
 
                " directory, but not a branch or repository. This is an"
785
 
                " unsupported configuration. Please move the target directory"
786
 
                " out of the way and try again."
787
 
                % location)
788
 
        elif br_to is None:
789
 
            # We have a repository but no branch, copy the revisions, and then
790
 
            # create a branch.
791
 
            last_revision_id = br_from.last_revision()
792
 
            repository_to.fetch(br_from.repository,
793
 
                                revision_id=last_revision_id)
794
 
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
795
 
            note('Created new branch.')
796
 
            if br_from.get_push_location() is None or remember:
797
 
                br_from.set_push_location(br_to.base)
798
 
        else: # We have a valid to branch
799
 
            # We were able to connect to the remote location, so remember it
800
 
            # we don't need to successfully push because of possible divergence.
801
 
            if br_from.get_push_location() is None or remember:
802
 
                br_from.set_push_location(br_to.base)
803
 
            if verbose:
804
 
                old_rh = br_to.revision_history()
805
 
            try:
806
 
                try:
807
 
                    tree_to = dir_to.open_workingtree()
808
 
                except errors.NotLocalUrl:
809
 
                    warning("This transport does not update the working " 
810
 
                            "tree of: %s. See 'bzr help working-trees' for "
811
 
                            "more information." % br_to.base)
812
 
                    push_result = br_from.push(br_to, overwrite)
813
 
                except errors.NoWorkingTree:
814
 
                    push_result = br_from.push(br_to, overwrite)
815
 
                else:
816
 
                    tree_to.lock_write()
817
 
                    try:
818
 
                        push_result = br_from.push(tree_to.branch, overwrite)
819
 
                        tree_to.update()
820
 
                    finally:
821
 
                        tree_to.unlock()
822
 
            except errors.DivergedBranches:
823
 
                raise errors.BzrCommandError('These branches have diverged.'
824
 
                                        '  Try using "merge" and then "push".')
825
 
        if push_result is not None:
826
 
            push_result.report(self.outf)
827
 
        elif verbose:
828
 
            new_rh = br_to.revision_history()
829
 
            if old_rh != new_rh:
830
 
                # Something changed
831
 
                from bzrlib.log import show_changed_revisions
832
 
                show_changed_revisions(br_to, old_rh, new_rh,
833
 
                                       to_file=self.outf)
834
 
        else:
835
 
            # we probably did a clone rather than a push, so a message was
836
 
            # emitted above
837
 
            pass
 
284
    """Pull any changes from another branch into the current one.
 
285
 
 
286
    If the location is omitted, the last-used location will be used.
 
287
    Both the revision history and the working directory will be
 
288
    updated.
 
289
 
 
290
    This command only works on branches that have not diverged.  Branches are
 
291
    considered diverged if both branches have had commits without first
 
292
    pulling from the other.
 
293
 
 
294
    If branches have diverged, you can use 'bzr merge' to pull the text changes
 
295
    from one into the other.
 
296
    """
 
297
    takes_args = ['location?']
 
298
 
 
299
    def run(self, location=None):
 
300
        from bzrlib.merge import merge
 
301
        import tempfile
 
302
        from shutil import rmtree
 
303
        import errno
 
304
        from bzrlib.branch import pull_loc
 
305
        
 
306
        br_to = find_branch('.')
 
307
        stored_loc = None
 
308
        try:
 
309
            stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
 
310
        except IOError, e:
 
311
            if e.errno != errno.ENOENT:
 
312
                raise
 
313
        if location is None:
 
314
            if stored_loc is None:
 
315
                raise BzrCommandError("No pull location known or specified.")
 
316
            else:
 
317
                print "Using last location: %s" % stored_loc
 
318
                location = stored_loc
 
319
        cache_root = tempfile.mkdtemp()
 
320
        from bzrlib.branch import DivergedBranches
 
321
        br_from = find_branch(location)
 
322
        location = pull_loc(br_from)
 
323
        old_revno = br_to.revno()
 
324
        try:
 
325
            from branch import find_cached_branch, DivergedBranches
 
326
            br_from = find_cached_branch(location, cache_root)
 
327
            location = pull_loc(br_from)
 
328
            old_revno = br_to.revno()
 
329
            try:
 
330
                br_to.update_revisions(br_from)
 
331
            except DivergedBranches:
 
332
                raise BzrCommandError("These branches have diverged."
 
333
                    "  Try merge.")
 
334
                
 
335
            merge(('.', -1), ('.', old_revno), check_clean=False)
 
336
            if location != stored_loc:
 
337
                br_to.controlfile("x-pull", "wb").write(location + "\n")
 
338
        finally:
 
339
            rmtree(cache_root)
 
340
 
838
341
 
839
342
 
840
343
class cmd_branch(Command):
842
345
 
843
346
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
844
347
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
845
 
    If the FROM_LOCATION has no / or path separator embedded, the TO_LOCATION
846
 
    is derived from the FROM_LOCATION by stripping a leading scheme or drive
847
 
    identifier, if any. For example, "branch lp:foo-bar" will attempt to
848
 
    create ./foo-bar.
849
348
 
850
349
    To retrieve the branch as of a particular revision, supply the --revision
851
350
    parameter, as in "branch foo/bar -r 5".
852
351
    """
853
 
 
854
 
    _see_also = ['checkout']
855
352
    takes_args = ['from_location', 'to_location?']
856
353
    takes_options = ['revision']
857
354
    aliases = ['get', 'clone']
858
355
 
859
356
    def run(self, from_location, to_location=None, revision=None):
860
 
        from bzrlib.tag import _merge_tags_if_possible
861
 
        if revision is None:
862
 
            revision = [None]
863
 
        elif len(revision) > 1:
864
 
            raise errors.BzrCommandError(
865
 
                'bzr branch --revision takes exactly 1 revision value')
866
 
 
867
 
        br_from = Branch.open(from_location)
868
 
        br_from.lock_read()
 
357
        from bzrlib.branch import copy_branch, find_cached_branch
 
358
        import tempfile
 
359
        import errno
 
360
        from shutil import rmtree
 
361
        cache_root = tempfile.mkdtemp()
869
362
        try:
870
 
            if len(revision) == 1 and revision[0] is not None:
871
 
                revision_id = revision[0].in_history(br_from)[1]
872
 
            else:
873
 
                # FIXME - wt.last_revision, fallback to branch, fall back to
874
 
                # None or perhaps NULL_REVISION to mean copy nothing
875
 
                # RBC 20060209
876
 
                revision_id = br_from.last_revision()
 
363
            if revision is None:
 
364
                revision = [None]
 
365
            elif len(revision) > 1:
 
366
                raise BzrCommandError(
 
367
                    'bzr branch --revision takes exactly 1 revision value')
 
368
            try:
 
369
                br_from = find_cached_branch(from_location, cache_root)
 
370
            except OSError, e:
 
371
                if e.errno == errno.ENOENT:
 
372
                    raise BzrCommandError('Source location "%s" does not'
 
373
                                          ' exist.' % to_location)
 
374
                else:
 
375
                    raise
877
376
            if to_location is None:
878
 
                to_location = urlutils.derive_to_location(from_location)
879
 
                name = None
880
 
            else:
881
 
                name = os.path.basename(to_location) + '\n'
882
 
 
883
 
            to_transport = transport.get_transport(to_location)
884
 
            try:
885
 
                to_transport.mkdir('.')
886
 
            except errors.FileExists:
887
 
                raise errors.BzrCommandError('Target directory "%s" already'
888
 
                                             ' exists.' % to_location)
889
 
            except errors.NoSuchFile:
890
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
891
 
                                             % to_location)
892
 
            try:
893
 
                # preserve whatever source format we have.
894
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
895
 
                                            possible_transports=[to_transport])
896
 
                branch = dir.open_branch()
897
 
            except errors.NoSuchRevision:
898
 
                to_transport.delete_tree('.')
899
 
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
900
 
                raise errors.BzrCommandError(msg)
901
 
            if name:
902
 
                branch.control_files.put_utf8('branch-name', name)
903
 
            _merge_tags_if_possible(br_from, branch)
904
 
            note('Branched %d revision(s).' % branch.revno())
 
377
                to_location = os.path.basename(from_location.rstrip("/\\"))
 
378
            try:
 
379
                os.mkdir(to_location)
 
380
            except OSError, e:
 
381
                if e.errno == errno.EEXIST:
 
382
                    raise BzrCommandError('Target directory "%s" already'
 
383
                                          ' exists.' % to_location)
 
384
                if e.errno == errno.ENOENT:
 
385
                    raise BzrCommandError('Parent of "%s" does not exist.' %
 
386
                                          to_location)
 
387
                else:
 
388
                    raise
 
389
            try:
 
390
                copy_branch(br_from, to_location, revision[0])
 
391
            except bzrlib.errors.NoSuchRevision:
 
392
                rmtree(to_location)
 
393
                msg = "The branch %s has no revision %d." % (from_location, revision[0])
 
394
                raise BzrCommandError(msg)
905
395
        finally:
906
 
            br_from.unlock()
907
 
 
908
 
 
909
 
class cmd_checkout(Command):
910
 
    """Create a new checkout of an existing branch.
911
 
 
912
 
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
913
 
    the branch found in '.'. This is useful if you have removed the working tree
914
 
    or if it was never created - i.e. if you pushed the branch to its current
915
 
    location using SFTP.
916
 
    
917
 
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
918
 
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
919
 
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
920
 
    is derived from the BRANCH_LOCATION by stripping a leading scheme or drive
921
 
    identifier, if any. For example, "checkout lp:foo-bar" will attempt to
922
 
    create ./foo-bar.
923
 
 
924
 
    To retrieve the branch as of a particular revision, supply the --revision
925
 
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
926
 
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
927
 
    code.)
928
 
    """
929
 
 
930
 
    _see_also = ['checkouts', 'branch']
931
 
    takes_args = ['branch_location?', 'to_location?']
932
 
    takes_options = ['revision',
933
 
                     Option('lightweight',
934
 
                            help="Perform a lightweight checkout.  Lightweight "
935
 
                                 "checkouts depend on access to the branch for "
936
 
                                 "every operation.  Normal checkouts can perform "
937
 
                                 "common operations like diff and status without "
938
 
                                 "such access, and also support local commits."
939
 
                            ),
940
 
                     ]
941
 
    aliases = ['co']
942
 
 
943
 
    def run(self, branch_location=None, to_location=None, revision=None,
944
 
            lightweight=False):
945
 
        if revision is None:
946
 
            revision = [None]
947
 
        elif len(revision) > 1:
948
 
            raise errors.BzrCommandError(
949
 
                'bzr checkout --revision takes exactly 1 revision value')
950
 
        if branch_location is None:
951
 
            branch_location = osutils.getcwd()
952
 
            to_location = branch_location
953
 
        source = Branch.open(branch_location)
954
 
        if len(revision) == 1 and revision[0] is not None:
955
 
            revision_id = _mod_revision.ensure_null(
956
 
                revision[0].in_history(source)[1])
957
 
        else:
958
 
            revision_id = None
959
 
        if to_location is None:
960
 
            to_location = urlutils.derive_to_location(branch_location)
961
 
        # if the source and to_location are the same, 
962
 
        # and there is no working tree,
963
 
        # then reconstitute a branch
964
 
        if (osutils.abspath(to_location) ==
965
 
            osutils.abspath(branch_location)):
966
 
            try:
967
 
                source.bzrdir.open_workingtree()
968
 
            except errors.NoWorkingTree:
969
 
                source.bzrdir.create_workingtree(revision_id)
970
 
                return
971
 
        source.create_checkout(to_location, revision_id, lightweight)
 
396
            rmtree(cache_root)
972
397
 
973
398
 
974
399
class cmd_renames(Command):
975
400
    """Show list of renamed files.
976
 
    """
977
 
    # TODO: Option to show renames between two historical versions.
978
 
 
979
 
    # TODO: Only show renames under dir, rather than in the whole branch.
980
 
    _see_also = ['status']
981
 
    takes_args = ['dir?']
982
 
 
983
 
    @display_command
984
 
    def run(self, dir=u'.'):
985
 
        tree = WorkingTree.open_containing(dir)[0]
986
 
        tree.lock_read()
987
 
        try:
988
 
            new_inv = tree.inventory
989
 
            old_tree = tree.basis_tree()
990
 
            old_tree.lock_read()
991
 
            try:
992
 
                old_inv = old_tree.inventory
993
 
                renames = list(_mod_tree.find_renames(old_inv, new_inv))
994
 
                renames.sort()
995
 
                for old_name, new_name in renames:
996
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
997
 
            finally:
998
 
                old_tree.unlock()
999
 
        finally:
1000
 
            tree.unlock()
1001
 
 
1002
 
 
1003
 
class cmd_update(Command):
1004
 
    """Update a tree to have the latest code committed to its branch.
1005
 
    
1006
 
    This will perform a merge into the working tree, and may generate
1007
 
    conflicts. If you have any local changes, you will still 
1008
 
    need to commit them after the update for the update to be complete.
1009
 
    
1010
 
    If you want to discard your local changes, you can just do a 
1011
 
    'bzr revert' instead of 'bzr commit' after the update.
1012
 
    """
1013
 
 
1014
 
    _see_also = ['pull', 'working-trees', 'status-flags']
1015
 
    takes_args = ['dir?']
1016
 
    aliases = ['up']
 
401
 
 
402
    TODO: Option to show renames between two historical versions.
 
403
 
 
404
    TODO: Only show renames under dir, rather than in the whole branch.
 
405
    """
 
406
    takes_args = ['dir?']
1017
407
 
1018
408
    def run(self, dir='.'):
1019
 
        tree = WorkingTree.open_containing(dir)[0]
1020
 
        possible_transports = []
1021
 
        master = tree.branch.get_master_branch(
1022
 
            possible_transports=possible_transports)
1023
 
        if master is not None:
1024
 
            tree.lock_write()
1025
 
        else:
1026
 
            tree.lock_tree_write()
1027
 
        try:
1028
 
            existing_pending_merges = tree.get_parent_ids()[1:]
1029
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1030
 
            if last_rev == _mod_revision.ensure_null(
1031
 
                tree.branch.last_revision()):
1032
 
                # may be up to date, check master too.
1033
 
                if master is None or last_rev == _mod_revision.ensure_null(
1034
 
                    master.last_revision()):
1035
 
                    revno = tree.branch.revision_id_to_revno(last_rev)
1036
 
                    note("Tree is up to date at revision %d." % (revno,))
1037
 
                    return 0
1038
 
            conflicts = tree.update(
1039
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored),
1040
 
                possible_transports=possible_transports)
1041
 
            revno = tree.branch.revision_id_to_revno(
1042
 
                _mod_revision.ensure_null(tree.last_revision()))
1043
 
            note('Updated to revision %d.' % (revno,))
1044
 
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1045
 
                note('Your local commits will now show as pending merges with '
1046
 
                     "'bzr status', and can be committed with 'bzr commit'.")
1047
 
            if conflicts != 0:
1048
 
                return 1
1049
 
            else:
1050
 
                return 0
1051
 
        finally:
1052
 
            tree.unlock()
 
409
        b = find_branch(dir)
 
410
        old_inv = b.basis_tree().inventory
 
411
        new_inv = b.read_working_inventory()
 
412
 
 
413
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
 
414
        renames.sort()
 
415
        for old_name, new_name in renames:
 
416
            print "%s => %s" % (old_name, new_name)        
1053
417
 
1054
418
 
1055
419
class cmd_info(Command):
1056
 
    """Show information about a working tree, branch or repository.
1057
 
 
1058
 
    This command will show all known locations and formats associated to the
1059
 
    tree, branch or repository.  Statistical information is included with
1060
 
    each report.
1061
 
 
1062
 
    Branches and working trees will also report any missing revisions.
1063
 
    """
1064
 
    _see_also = ['revno', 'working-trees', 'repositories']
1065
 
    takes_args = ['location?']
1066
 
    takes_options = ['verbose']
1067
 
 
1068
 
    @display_command
1069
 
    def run(self, location=None, verbose=False):
1070
 
        if verbose:
1071
 
            noise_level = 2
1072
 
        else:
1073
 
            noise_level = 0
1074
 
        from bzrlib.info import show_bzrdir_info
1075
 
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1076
 
                         verbose=noise_level)
 
420
    """Show statistical information about a branch."""
 
421
    takes_args = ['branch?']
 
422
    
 
423
    def run(self, branch=None):
 
424
        import info
 
425
 
 
426
        b = find_branch(branch)
 
427
        info.show_info(b)
1077
428
 
1078
429
 
1079
430
class cmd_remove(Command):
1080
 
    """Remove files or directories.
1081
 
 
1082
 
    This makes bzr stop tracking changes to the specified files and
1083
 
    delete them if they can easily be recovered using revert.
1084
 
 
1085
 
    You can specify one or more files, and/or --new.  If you specify --new,
1086
 
    only 'added' files will be removed.  If you specify both, then new files
1087
 
    in the specified directories will be removed.  If the directories are
1088
 
    also new, they will also be removed.
 
431
    """Make a file unversioned.
 
432
 
 
433
    This makes bzr stop tracking changes to a versioned file.  It does
 
434
    not delete the working copy.
1089
435
    """
1090
 
    takes_args = ['file*']
1091
 
    takes_options = ['verbose',
1092
 
        Option('new', help='Remove newly-added files.'),
1093
 
        RegistryOption.from_kwargs('file-deletion-strategy',
1094
 
            'The file deletion mode to be used.',
1095
 
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1096
 
            safe='Only delete files if they can be'
1097
 
                 ' safely recovered (default).',
1098
 
            keep="Don't delete any files.",
1099
 
            force='Delete all the specified files, even if they can not be '
1100
 
                'recovered and even if they are non-empty directories.')]
1101
 
    aliases = ['rm']
1102
 
    encoding_type = 'replace'
1103
 
 
1104
 
    def run(self, file_list, verbose=False, new=False,
1105
 
        file_deletion_strategy='safe'):
1106
 
        tree, file_list = tree_files(file_list)
1107
 
 
1108
 
        if file_list is not None:
1109
 
            file_list = [f for f in file_list]
1110
 
        elif not new:
1111
 
            raise errors.BzrCommandError('Specify one or more files to'
1112
 
            ' remove, or use --new.')
1113
 
 
1114
 
        if new:
1115
 
            added = tree.changes_from(tree.basis_tree(),
1116
 
                specific_files=file_list).added
1117
 
            file_list = sorted([f[0] for f in added], reverse=True)
1118
 
            if len(file_list) == 0:
1119
 
                raise errors.BzrCommandError('No matching files.')
1120
 
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1121
 
            keep_files=file_deletion_strategy=='keep',
1122
 
            force=file_deletion_strategy=='force')
 
436
    takes_args = ['file+']
 
437
    takes_options = ['verbose']
 
438
    
 
439
    def run(self, file_list, verbose=False):
 
440
        b = find_branch(file_list[0])
 
441
        b.remove([b.relpath(f) for f in file_list], verbose=verbose)
1123
442
 
1124
443
 
1125
444
class cmd_file_id(Command):
1129
448
    same through all revisions where the file exists, even when it is
1130
449
    moved or renamed.
1131
450
    """
1132
 
 
1133
451
    hidden = True
1134
 
    _see_also = ['inventory', 'ls']
1135
452
    takes_args = ['filename']
1136
 
 
1137
 
    @display_command
1138
453
    def run(self, filename):
1139
 
        tree, relpath = WorkingTree.open_containing(filename)
1140
 
        i = tree.path2id(relpath)
1141
 
        if i is None:
1142
 
            raise errors.NotVersionedError(filename)
 
454
        b = find_branch(filename)
 
455
        i = b.inventory.path2id(b.relpath(filename))
 
456
        if i == None:
 
457
            raise BzrError("%r is not a versioned file" % filename)
1143
458
        else:
1144
 
            self.outf.write(i + '\n')
 
459
            print i
1145
460
 
1146
461
 
1147
462
class cmd_file_path(Command):
1148
463
    """Print path of file_ids to a file or directory.
1149
464
 
1150
465
    This prints one line for each directory down to the target,
1151
 
    starting at the branch root.
1152
 
    """
1153
 
 
 
466
    starting at the branch root."""
1154
467
    hidden = True
1155
468
    takes_args = ['filename']
1156
 
 
1157
 
    @display_command
1158
469
    def run(self, filename):
1159
 
        tree, relpath = WorkingTree.open_containing(filename)
1160
 
        fid = tree.path2id(relpath)
1161
 
        if fid is None:
1162
 
            raise errors.NotVersionedError(filename)
1163
 
        segments = osutils.splitpath(relpath)
1164
 
        for pos in range(1, len(segments) + 1):
1165
 
            path = osutils.joinpath(segments[:pos])
1166
 
            self.outf.write("%s\n" % tree.path2id(path))
1167
 
 
1168
 
 
1169
 
class cmd_reconcile(Command):
1170
 
    """Reconcile bzr metadata in a branch.
1171
 
 
1172
 
    This can correct data mismatches that may have been caused by
1173
 
    previous ghost operations or bzr upgrades. You should only
1174
 
    need to run this command if 'bzr check' or a bzr developer 
1175
 
    advises you to run it.
1176
 
 
1177
 
    If a second branch is provided, cross-branch reconciliation is
1178
 
    also attempted, which will check that data like the tree root
1179
 
    id which was not present in very early bzr versions is represented
1180
 
    correctly in both branches.
1181
 
 
1182
 
    At the same time it is run it may recompress data resulting in 
1183
 
    a potential saving in disk space or performance gain.
1184
 
 
1185
 
    The branch *MUST* be on a listable system such as local disk or sftp.
1186
 
    """
1187
 
 
1188
 
    _see_also = ['check']
1189
 
    takes_args = ['branch?']
1190
 
 
1191
 
    def run(self, branch="."):
1192
 
        from bzrlib.reconcile import reconcile
1193
 
        dir = bzrdir.BzrDir.open(branch)
1194
 
        reconcile(dir)
 
470
        b = find_branch(filename)
 
471
        inv = b.inventory
 
472
        fid = inv.path2id(b.relpath(filename))
 
473
        if fid == None:
 
474
            raise BzrError("%r is not a versioned file" % filename)
 
475
        for fip in inv.get_idpath(fid):
 
476
            print fip
1195
477
 
1196
478
 
1197
479
class cmd_revision_history(Command):
1198
 
    """Display the list of revision ids on a branch."""
1199
 
 
1200
 
    _see_also = ['log']
1201
 
    takes_args = ['location?']
1202
 
 
 
480
    """Display list of revision ids on this branch."""
1203
481
    hidden = True
1204
 
 
1205
 
    @display_command
1206
 
    def run(self, location="."):
1207
 
        branch = Branch.open_containing(location)[0]
1208
 
        for revid in branch.revision_history():
1209
 
            self.outf.write(revid)
1210
 
            self.outf.write('\n')
 
482
    def run(self):
 
483
        for patchid in find_branch('.').revision_history():
 
484
            print patchid
1211
485
 
1212
486
 
1213
487
class cmd_ancestry(Command):
1214
488
    """List all revisions merged into this branch."""
1215
 
 
1216
 
    _see_also = ['log', 'revision-history']
1217
 
    takes_args = ['location?']
1218
 
 
1219
489
    hidden = True
1220
 
 
1221
 
    @display_command
1222
 
    def run(self, location="."):
1223
 
        try:
1224
 
            wt = WorkingTree.open_containing(location)[0]
1225
 
        except errors.NoWorkingTree:
1226
 
            b = Branch.open(location)
1227
 
            last_revision = b.last_revision()
1228
 
        else:
1229
 
            b = wt.branch
1230
 
            last_revision = wt.last_revision()
1231
 
 
1232
 
        revision_ids = b.repository.get_ancestry(last_revision)
1233
 
        assert revision_ids[0] is None
1234
 
        revision_ids.pop(0)
1235
 
        for revision_id in revision_ids:
1236
 
            self.outf.write(revision_id + '\n')
 
490
    def run(self):
 
491
        b = find_branch('.')
 
492
        for revision_id in b.get_ancestry(b.last_patch()):
 
493
            print revision_id
 
494
 
 
495
 
 
496
class cmd_directories(Command):
 
497
    """Display list of versioned directories in this branch."""
 
498
    def run(self):
 
499
        for name, ie in find_branch('.').read_working_inventory().directories():
 
500
            if name == '':
 
501
                print '.'
 
502
            else:
 
503
                print name
1237
504
 
1238
505
 
1239
506
class cmd_init(Command):
1242
509
    Use this to create an empty branch, or before importing an
1243
510
    existing project.
1244
511
 
1245
 
    If there is a repository in a parent directory of the location, then 
1246
 
    the history of the branch will be stored in the repository.  Otherwise
1247
 
    init creates a standalone branch which carries its own history
1248
 
    in the .bzr directory.
1249
 
 
1250
 
    If there is already a branch at the location but it has no working tree,
1251
 
    the tree can be populated with 'bzr checkout'.
1252
 
 
1253
 
    Recipe for importing a tree of files::
1254
 
 
 
512
    Recipe for importing a tree of files:
1255
513
        cd ~/project
1256
514
        bzr init
1257
 
        bzr add .
 
515
        bzr add -v .
1258
516
        bzr status
1259
517
        bzr commit -m 'imported project'
1260
518
    """
1261
 
 
1262
 
    _see_also = ['init-repository', 'branch', 'checkout']
1263
 
    takes_args = ['location?']
1264
 
    takes_options = [
1265
 
        Option('create-prefix',
1266
 
               help='Create the path leading up to the branch '
1267
 
                    'if it does not already exist.'),
1268
 
         RegistryOption('format',
1269
 
                help='Specify a format for this branch. '
1270
 
                'See "help formats".',
1271
 
                registry=bzrdir.format_registry,
1272
 
                converter=bzrdir.format_registry.make_bzrdir,
1273
 
                value_switches=True,
1274
 
                title="Branch Format",
1275
 
                ),
1276
 
         Option('append-revisions-only',
1277
 
                help='Never change revnos or the existing log.'
1278
 
                '  Append revisions to it only.')
1279
 
         ]
1280
 
    def run(self, location=None, format=None, append_revisions_only=False,
1281
 
            create_prefix=False):
1282
 
        if format is None:
1283
 
            format = bzrdir.format_registry.make_bzrdir('default')
1284
 
        if location is None:
1285
 
            location = u'.'
1286
 
 
1287
 
        to_transport = transport.get_transport(location)
1288
 
 
1289
 
        # The path has to exist to initialize a
1290
 
        # branch inside of it.
1291
 
        # Just using os.mkdir, since I don't
1292
 
        # believe that we want to create a bunch of
1293
 
        # locations if the user supplies an extended path
1294
 
        try:
1295
 
            to_transport.ensure_base()
1296
 
        except errors.NoSuchFile:
1297
 
            if not create_prefix:
1298
 
                raise errors.BzrCommandError("Parent directory of %s"
1299
 
                    " does not exist."
1300
 
                    "\nYou may supply --create-prefix to create all"
1301
 
                    " leading parent directories."
1302
 
                    % location)
1303
 
            _create_prefix(to_transport)
1304
 
 
1305
 
        try:
1306
 
            existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1307
 
        except errors.NotBranchError:
1308
 
            # really a NotBzrDir error...
1309
 
            create_branch = bzrdir.BzrDir.create_branch_convenience
1310
 
            branch = create_branch(to_transport.base, format=format,
1311
 
                                   possible_transports=[to_transport])
1312
 
        else:
1313
 
            from bzrlib.transport.local import LocalTransport
1314
 
            if existing_bzrdir.has_branch():
1315
 
                if (isinstance(to_transport, LocalTransport)
1316
 
                    and not existing_bzrdir.has_workingtree()):
1317
 
                        raise errors.BranchExistsWithoutWorkingTree(location)
1318
 
                raise errors.AlreadyBranchError(location)
1319
 
            else:
1320
 
                branch = existing_bzrdir.create_branch()
1321
 
                existing_bzrdir.create_workingtree()
1322
 
        if append_revisions_only:
1323
 
            try:
1324
 
                branch.set_append_revisions_only(True)
1325
 
            except errors.UpgradeRequired:
1326
 
                raise errors.BzrCommandError('This branch format cannot be set'
1327
 
                    ' to append-revisions-only.  Try --experimental-branch6')
1328
 
 
1329
 
 
1330
 
class cmd_init_repository(Command):
1331
 
    """Create a shared repository to hold branches.
1332
 
 
1333
 
    New branches created under the repository directory will store their
1334
 
    revisions in the repository, not in the branch directory.
1335
 
 
1336
 
    If the --no-trees option is used then the branches in the repository
1337
 
    will not have working trees by default.
1338
 
 
1339
 
    :Examples:
1340
 
        Create a shared repositories holding just branches::
1341
 
 
1342
 
            bzr init-repo --no-trees repo
1343
 
            bzr init repo/trunk
1344
 
 
1345
 
        Make a lightweight checkout elsewhere::
1346
 
 
1347
 
            bzr checkout --lightweight repo/trunk trunk-checkout
1348
 
            cd trunk-checkout
1349
 
            (add files here)
1350
 
    """
1351
 
 
1352
 
    _see_also = ['init', 'branch', 'checkout', 'repositories']
1353
 
    takes_args = ["location"]
1354
 
    takes_options = [RegistryOption('format',
1355
 
                            help='Specify a format for this repository. See'
1356
 
                                 ' "bzr help formats" for details.',
1357
 
                            registry=bzrdir.format_registry,
1358
 
                            converter=bzrdir.format_registry.make_bzrdir,
1359
 
                            value_switches=True, title='Repository format'),
1360
 
                     Option('no-trees',
1361
 
                             help='Branches in the repository will default to'
1362
 
                                  ' not having a working tree.'),
1363
 
                    ]
1364
 
    aliases = ["init-repo"]
1365
 
 
1366
 
    def run(self, location, format=None, no_trees=False):
1367
 
        if format is None:
1368
 
            format = bzrdir.format_registry.make_bzrdir('default')
1369
 
 
1370
 
        if location is None:
1371
 
            location = '.'
1372
 
 
1373
 
        to_transport = transport.get_transport(location)
1374
 
        to_transport.ensure_base()
1375
 
 
1376
 
        newdir = format.initialize_on_transport(to_transport)
1377
 
        repo = newdir.create_repository(shared=True)
1378
 
        repo.set_make_working_trees(not no_trees)
 
519
    def run(self):
 
520
        from bzrlib.branch import Branch
 
521
        Branch('.', init=True)
1379
522
 
1380
523
 
1381
524
class cmd_diff(Command):
1382
 
    """Show differences in the working tree or between revisions.
 
525
    """Show differences in working tree.
1383
526
    
1384
527
    If files are listed, only the changes in those files are listed.
1385
528
    Otherwise, all changes for the tree are listed.
1386
529
 
1387
 
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1388
 
    produces patches suitable for "patch -p1".
1389
 
 
1390
 
    :Examples:
1391
 
        Shows the difference in the working tree versus the last commit::
1392
 
 
1393
 
            bzr diff
1394
 
 
1395
 
        Difference between the working tree and revision 1::
1396
 
 
1397
 
            bzr diff -r1
1398
 
 
1399
 
        Difference between revision 2 and revision 1::
1400
 
 
1401
 
            bzr diff -r1..2
1402
 
 
1403
 
        Same as 'bzr diff' but prefix paths with old/ and new/::
1404
 
 
1405
 
            bzr diff --prefix old/:new/
1406
 
 
1407
 
        Show the differences between the two working trees::
1408
 
 
1409
 
            bzr diff bzr.mine bzr.dev
1410
 
 
1411
 
        Show just the differences for 'foo.c'::
1412
 
 
1413
 
            bzr diff foo.c
 
530
    TODO: Allow diff across branches.
 
531
 
 
532
    TODO: Option to use external diff command; could be GNU diff, wdiff,
 
533
          or a graphical diff.
 
534
 
 
535
    TODO: Python difflib is not exactly the same as unidiff; should
 
536
          either fix it up or prefer to use an external diff.
 
537
 
 
538
    TODO: If a directory is given, diff everything under that.
 
539
 
 
540
    TODO: Selected-file diff is inefficient and doesn't show you
 
541
          deleted files.
 
542
 
 
543
    TODO: This probably handles non-Unix newlines poorly.
 
544
 
 
545
    examples:
 
546
        bzr diff
 
547
        bzr diff -r1
 
548
        bzr diff -r1:2
1414
549
    """
1415
 
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
1416
 
    #       or a graphical diff.
1417
 
 
1418
 
    # TODO: Python difflib is not exactly the same as unidiff; should
1419
 
    #       either fix it up or prefer to use an external diff.
1420
 
 
1421
 
    # TODO: Selected-file diff is inefficient and doesn't show you
1422
 
    #       deleted files.
1423
 
 
1424
 
    # TODO: This probably handles non-Unix newlines poorly.
1425
 
 
1426
 
    _see_also = ['status']
 
550
    
1427
551
    takes_args = ['file*']
1428
 
    takes_options = [
1429
 
        Option('diff-options', type=str,
1430
 
               help='Pass these options to the external diff program.'),
1431
 
        Option('prefix', type=str,
1432
 
               short_name='p',
1433
 
               help='Set prefixes to added to old and new filenames, as '
1434
 
                    'two values separated by a colon. (eg "old/:new/").'),
1435
 
        'revision',
1436
 
        'change',
1437
 
        ]
 
552
    takes_options = ['revision', 'diff-options']
1438
553
    aliases = ['di', 'dif']
1439
 
    encoding_type = 'exact'
1440
 
 
1441
 
    @display_command
1442
 
    def run(self, revision=None, file_list=None, diff_options=None,
1443
 
            prefix=None):
1444
 
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
1445
 
 
1446
 
        if (prefix is None) or (prefix == '0'):
1447
 
            # diff -p0 format
1448
 
            old_label = ''
1449
 
            new_label = ''
1450
 
        elif prefix == '1':
1451
 
            old_label = 'old/'
1452
 
            new_label = 'new/'
1453
 
        elif ':' in prefix:
1454
 
            old_label, new_label = prefix.split(":")
 
554
 
 
555
    def run(self, revision=None, file_list=None, diff_options=None):
 
556
        from bzrlib.diff import show_diff
 
557
 
 
558
        if file_list:
 
559
            b = find_branch(file_list[0])
 
560
            file_list = [b.relpath(f) for f in file_list]
 
561
            if file_list == ['']:
 
562
                # just pointing to top-of-tree
 
563
                file_list = None
1455
564
        else:
1456
 
            raise errors.BzrCommandError(
1457
 
                '--prefix expects two values separated by a colon'
1458
 
                ' (eg "old/:new/")')
1459
 
 
1460
 
        if revision and len(revision) > 2:
1461
 
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1462
 
                                         ' one or two revision specifiers')
1463
 
 
1464
 
        try:
1465
 
            tree1, file_list = internal_tree_files(file_list)
1466
 
            tree2 = None
1467
 
            b = None
1468
 
            b2 = None
1469
 
        except errors.FileInWrongBranch:
1470
 
            if len(file_list) != 2:
1471
 
                raise errors.BzrCommandError("Files are in different branches")
1472
 
 
1473
 
            tree1, file1 = WorkingTree.open_containing(file_list[0])
1474
 
            tree2, file2 = WorkingTree.open_containing(file_list[1])
1475
 
            if file1 != "" or file2 != "":
1476
 
                # FIXME diff those two files. rbc 20051123
1477
 
                raise errors.BzrCommandError("Files are in different branches")
1478
 
            file_list = None
1479
 
        except errors.NotBranchError:
1480
 
            if (revision is not None and len(revision) == 2
1481
 
                and not revision[0].needs_branch()
1482
 
                and not revision[1].needs_branch()):
1483
 
                # If both revision specs include a branch, we can
1484
 
                # diff them without needing a local working tree
1485
 
                tree1, tree2 = None, None
 
565
            b = find_branch('.')
 
566
 
 
567
        if revision is not None:
 
568
            if len(revision) == 1:
 
569
                show_diff(b, revision[0], specific_files=file_list,
 
570
                          external_diff_options=diff_options)
 
571
            elif len(revision) == 2:
 
572
                show_diff(b, revision[0], specific_files=file_list,
 
573
                          external_diff_options=diff_options,
 
574
                          revision2=revision[1])
1486
575
            else:
1487
 
                raise
1488
 
 
1489
 
        if tree2 is not None:
1490
 
            if revision is not None:
1491
 
                # FIXME: but there should be a clean way to diff between
1492
 
                # non-default versions of two trees, it's not hard to do
1493
 
                # internally...
1494
 
                raise errors.BzrCommandError(
1495
 
                        "Sorry, diffing arbitrary revisions across branches "
1496
 
                        "is not implemented yet")
1497
 
            return show_diff_trees(tree1, tree2, sys.stdout, 
1498
 
                                   specific_files=file_list,
1499
 
                                   external_diff_options=diff_options,
1500
 
                                   old_label=old_label, new_label=new_label)
1501
 
 
1502
 
        return diff_cmd_helper(tree1, file_list, diff_options,
1503
 
                               revision_specs=revision,
1504
 
                               old_label=old_label, new_label=new_label)
 
576
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
 
577
        else:
 
578
            show_diff(b, None, specific_files=file_list,
 
579
                      external_diff_options=diff_options)
 
580
 
 
581
        
1505
582
 
1506
583
 
1507
584
class cmd_deleted(Command):
1508
585
    """List files deleted in the working tree.
 
586
 
 
587
    TODO: Show files deleted since a previous revision, or between two revisions.
1509
588
    """
1510
 
    # TODO: Show files deleted since a previous revision, or
1511
 
    # between two revisions.
1512
 
    # TODO: Much more efficient way to do this: read in new
1513
 
    # directories with readdir, rather than stating each one.  Same
1514
 
    # level of effort but possibly much less IO.  (Or possibly not,
1515
 
    # if the directories are very large...)
1516
 
    _see_also = ['status', 'ls']
1517
 
    takes_options = ['show-ids']
1518
 
 
1519
 
    @display_command
1520
589
    def run(self, show_ids=False):
1521
 
        tree = WorkingTree.open_containing(u'.')[0]
1522
 
        tree.lock_read()
1523
 
        try:
1524
 
            old = tree.basis_tree()
1525
 
            old.lock_read()
1526
 
            try:
1527
 
                for path, ie in old.inventory.iter_entries():
1528
 
                    if not tree.has_id(ie.file_id):
1529
 
                        self.outf.write(path)
1530
 
                        if show_ids:
1531
 
                            self.outf.write(' ')
1532
 
                            self.outf.write(ie.file_id)
1533
 
                        self.outf.write('\n')
1534
 
            finally:
1535
 
                old.unlock()
1536
 
        finally:
1537
 
            tree.unlock()
 
590
        b = find_branch('.')
 
591
        old = b.basis_tree()
 
592
        new = b.working_tree()
 
593
 
 
594
        ## TODO: Much more efficient way to do this: read in new
 
595
        ## directories with readdir, rather than stating each one.  Same
 
596
        ## level of effort but possibly much less IO.  (Or possibly not,
 
597
        ## if the directories are very large...)
 
598
 
 
599
        for path, ie in old.inventory.iter_entries():
 
600
            if not new.has_id(ie.file_id):
 
601
                if show_ids:
 
602
                    print '%-50s %s' % (path, ie.file_id)
 
603
                else:
 
604
                    print path
1538
605
 
1539
606
 
1540
607
class cmd_modified(Command):
1541
 
    """List files modified in working tree.
1542
 
    """
1543
 
 
 
608
    """List files modified in working tree."""
1544
609
    hidden = True
1545
 
    _see_also = ['status', 'ls']
1546
 
 
1547
 
    @display_command
1548
610
    def run(self):
1549
 
        tree = WorkingTree.open_containing(u'.')[0]
1550
 
        td = tree.changes_from(tree.basis_tree())
1551
 
        for path, id, kind, text_modified, meta_modified in td.modified:
1552
 
            self.outf.write(path + '\n')
 
611
        from bzrlib.delta import compare_trees
 
612
 
 
613
        b = find_branch('.')
 
614
        td = compare_trees(b.basis_tree(), b.working_tree())
 
615
 
 
616
        for path, id, kind in td.modified:
 
617
            print path
 
618
 
1553
619
 
1554
620
 
1555
621
class cmd_added(Command):
1556
 
    """List files added in working tree.
1557
 
    """
1558
 
 
 
622
    """List files added in working tree."""
1559
623
    hidden = True
1560
 
    _see_also = ['status', 'ls']
1561
 
 
1562
 
    @display_command
1563
624
    def run(self):
1564
 
        wt = WorkingTree.open_containing(u'.')[0]
1565
 
        wt.lock_read()
1566
 
        try:
1567
 
            basis = wt.basis_tree()
1568
 
            basis.lock_read()
1569
 
            try:
1570
 
                basis_inv = basis.inventory
1571
 
                inv = wt.inventory
1572
 
                for file_id in inv:
1573
 
                    if file_id in basis_inv:
1574
 
                        continue
1575
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
1576
 
                        continue
1577
 
                    path = inv.id2path(file_id)
1578
 
                    if not os.access(osutils.abspath(path), os.F_OK):
1579
 
                        continue
1580
 
                    self.outf.write(path + '\n')
1581
 
            finally:
1582
 
                basis.unlock()
1583
 
        finally:
1584
 
            wt.unlock()
1585
 
 
 
625
        b = find_branch('.')
 
626
        wt = b.working_tree()
 
627
        basis_inv = b.basis_tree().inventory
 
628
        inv = wt.inventory
 
629
        for file_id in inv:
 
630
            if file_id in basis_inv:
 
631
                continue
 
632
            path = inv.id2path(file_id)
 
633
            if not os.access(b.abspath(path), os.F_OK):
 
634
                continue
 
635
            print path
 
636
                
 
637
        
1586
638
 
1587
639
class cmd_root(Command):
1588
640
    """Show the tree root directory.
1589
641
 
1590
642
    The root is the nearest enclosing directory with a .bzr control
1591
643
    directory."""
1592
 
 
1593
644
    takes_args = ['filename?']
1594
 
    @display_command
1595
645
    def run(self, filename=None):
1596
646
        """Print the branch root."""
1597
 
        tree = WorkingTree.open_containing(filename)[0]
1598
 
        self.outf.write(tree.basedir + '\n')
1599
 
 
1600
 
 
1601
 
def _parse_limit(limitstring):
1602
 
    try:
1603
 
        return int(limitstring)
1604
 
    except ValueError:
1605
 
        msg = "The limit argument must be an integer."
1606
 
        raise errors.BzrCommandError(msg)
 
647
        b = find_branch(filename)
 
648
        print getattr(b, 'base', None) or getattr(b, 'baseurl')
1607
649
 
1608
650
 
1609
651
class cmd_log(Command):
1610
 
    """Show log of a branch, file, or directory.
1611
 
 
1612
 
    By default show the log of the branch containing the working directory.
1613
 
 
1614
 
    To request a range of logs, you can use the command -r begin..end
1615
 
    -r revision requests a specific revision, -r ..end or -r begin.. are
 
652
    """Show log of this branch.
 
653
 
 
654
    To request a range of logs, you can use the command -r begin:end
 
655
    -r revision requests a specific revision, -r :end or -r begin: are
1616
656
    also valid.
1617
657
 
1618
 
    :Examples:
1619
 
        Log the current branch::
1620
 
 
1621
 
            bzr log
1622
 
 
1623
 
        Log a file::
1624
 
 
1625
 
            bzr log foo.c
1626
 
 
1627
 
        Log the last 10 revisions of a branch::
1628
 
 
1629
 
            bzr log -r -10.. http://server/branch
 
658
    --message allows you to give a regular expression, which will be evaluated
 
659
    so that only matching entries will be displayed.
 
660
 
 
661
    TODO: Make --revision support uuid: and hash: [future tag:] notation.
 
662
  
1630
663
    """
1631
664
 
1632
 
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1633
 
 
1634
 
    takes_args = ['location?']
1635
 
    takes_options = [
1636
 
            Option('forward',
1637
 
                   help='Show from oldest to newest.'),
1638
 
            Option('timezone',
1639
 
                   type=str,
1640
 
                   help='Display timezone as local, original, or utc.'),
1641
 
            custom_help('verbose',
1642
 
                   help='Show files changed in each revision.'),
1643
 
            'show-ids',
1644
 
            'revision',
1645
 
            'log-format',
1646
 
            Option('message',
1647
 
                   short_name='m',
1648
 
                   help='Show revisions whose message matches this '
1649
 
                        'regular expression.',
1650
 
                   type=str),
1651
 
            Option('limit',
1652
 
                   help='Limit the output to the first N revisions.',
1653
 
                   argname='N',
1654
 
                   type=_parse_limit),
1655
 
            ]
1656
 
    encoding_type = 'replace'
1657
 
 
1658
 
    @display_command
1659
 
    def run(self, location=None, timezone='original',
 
665
    takes_args = ['filename?']
 
666
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
 
667
                     'long', 'message', 'short',]
 
668
    
 
669
    def run(self, filename=None, timezone='original',
1660
670
            verbose=False,
1661
671
            show_ids=False,
1662
672
            forward=False,
1663
673
            revision=None,
1664
 
            log_format=None,
1665
674
            message=None,
1666
 
            limit=None):
1667
 
        from bzrlib.log import show_log
1668
 
        assert message is None or isinstance(message, basestring), \
1669
 
            "invalid message argument %r" % message
 
675
            long=False,
 
676
            short=False):
 
677
        from bzrlib.log import log_formatter, show_log
 
678
        import codecs
 
679
 
1670
680
        direction = (forward and 'forward') or 'reverse'
1671
681
        
1672
 
        # log everything
1673
 
        file_id = None
1674
 
        if location:
1675
 
            # find the file id to log:
1676
 
 
1677
 
            tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1678
 
                location)
1679
 
            if fp != '':
1680
 
                if tree is None:
1681
 
                    tree = b.basis_tree()
1682
 
                file_id = tree.path2id(fp)
1683
 
                if file_id is None:
1684
 
                    raise errors.BzrCommandError(
1685
 
                        "Path does not have any revision history: %s" %
1686
 
                        location)
1687
 
        else:
1688
 
            # local dir only
1689
 
            # FIXME ? log the current subdir only RBC 20060203 
1690
 
            if revision is not None \
1691
 
                    and len(revision) > 0 and revision[0].get_branch():
1692
 
                location = revision[0].get_branch()
1693
 
            else:
1694
 
                location = '.'
1695
 
            dir, relpath = bzrdir.BzrDir.open_containing(location)
1696
 
            b = dir.open_branch()
1697
 
 
1698
 
        b.lock_read()
1699
 
        try:
1700
 
            if revision is None:
1701
 
                rev1 = None
1702
 
                rev2 = None
1703
 
            elif len(revision) == 1:
1704
 
                rev1 = rev2 = revision[0].in_history(b)
1705
 
            elif len(revision) == 2:
1706
 
                if revision[1].get_branch() != revision[0].get_branch():
1707
 
                    # b is taken from revision[0].get_branch(), and
1708
 
                    # show_log will use its revision_history. Having
1709
 
                    # different branches will lead to weird behaviors.
1710
 
                    raise errors.BzrCommandError(
1711
 
                        "Log doesn't accept two revisions in different"
1712
 
                        " branches.")
1713
 
                rev1 = revision[0].in_history(b)
1714
 
                rev2 = revision[1].in_history(b)
1715
 
            else:
1716
 
                raise errors.BzrCommandError(
1717
 
                    'bzr log --revision takes one or two values.')
1718
 
 
1719
 
            if log_format is None:
1720
 
                log_format = log.log_formatter_registry.get_default(b)
1721
 
 
1722
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
1723
 
                            show_timezone=timezone)
1724
 
 
1725
 
            show_log(b,
1726
 
                     lf,
1727
 
                     file_id,
1728
 
                     verbose=verbose,
1729
 
                     direction=direction,
1730
 
                     start_revision=rev1,
1731
 
                     end_revision=rev2,
1732
 
                     search=message,
1733
 
                     limit=limit)
1734
 
        finally:
1735
 
            b.unlock()
1736
 
 
1737
 
 
1738
 
def get_log_format(long=False, short=False, line=False, default='long'):
1739
 
    log_format = default
1740
 
    if long:
1741
 
        log_format = 'long'
1742
 
    if short:
1743
 
        log_format = 'short'
1744
 
    if line:
1745
 
        log_format = 'line'
1746
 
    return log_format
 
682
        if filename:
 
683
            b = find_branch(filename)
 
684
            fp = b.relpath(filename)
 
685
            if fp:
 
686
                file_id = b.read_working_inventory().path2id(fp)
 
687
            else:
 
688
                file_id = None  # points to branch root
 
689
        else:
 
690
            b = find_branch('.')
 
691
            file_id = None
 
692
 
 
693
        if revision is None:
 
694
            rev1 = None
 
695
            rev2 = None
 
696
        elif len(revision) == 1:
 
697
            rev1 = rev2 = b.get_revision_info(revision[0])[0]
 
698
        elif len(revision) == 2:
 
699
            rev1 = b.get_revision_info(revision[0])[0]
 
700
            rev2 = b.get_revision_info(revision[1])[0]
 
701
        else:
 
702
            raise BzrCommandError('bzr log --revision takes one or two values.')
 
703
 
 
704
        if rev1 == 0:
 
705
            rev1 = None
 
706
        if rev2 == 0:
 
707
            rev2 = None
 
708
 
 
709
        mutter('encoding log as %r' % bzrlib.user_encoding)
 
710
 
 
711
        # use 'replace' so that we don't abort if trying to write out
 
712
        # in e.g. the default C locale.
 
713
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
 
714
 
 
715
        if not short:
 
716
            log_format = 'long'
 
717
        else:
 
718
            log_format = 'short'
 
719
        lf = log_formatter(log_format,
 
720
                           show_ids=show_ids,
 
721
                           to_file=outf,
 
722
                           show_timezone=timezone)
 
723
 
 
724
        show_log(b,
 
725
                 lf,
 
726
                 file_id,
 
727
                 verbose=verbose,
 
728
                 direction=direction,
 
729
                 start_revision=rev1,
 
730
                 end_revision=rev2,
 
731
                 search=message)
 
732
 
1747
733
 
1748
734
 
1749
735
class cmd_touching_revisions(Command):
1750
736
    """Return revision-ids which affected a particular file.
1751
737
 
1752
 
    A more user-friendly interface is "bzr log FILE".
1753
 
    """
1754
 
 
 
738
    A more user-friendly interface is "bzr log FILE"."""
1755
739
    hidden = True
1756
740
    takes_args = ["filename"]
1757
 
 
1758
 
    @display_command
1759
741
    def run(self, filename):
1760
 
        tree, relpath = WorkingTree.open_containing(filename)
1761
 
        b = tree.branch
1762
 
        file_id = tree.path2id(relpath)
1763
 
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1764
 
            self.outf.write("%6d %s\n" % (revno, what))
 
742
        b = find_branch(filename)
 
743
        inv = b.read_working_inventory()
 
744
        file_id = inv.path2id(b.relpath(filename))
 
745
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
 
746
            print "%6d %s" % (revno, what)
1765
747
 
1766
748
 
1767
749
class cmd_ls(Command):
1768
750
    """List files in a tree.
 
751
 
 
752
    TODO: Take a revision or remote path and list that tree instead.
1769
753
    """
1770
 
 
1771
 
    _see_also = ['status', 'cat']
1772
 
    takes_args = ['path?']
1773
 
    # TODO: Take a revision or remote path and list that tree instead.
1774
 
    takes_options = [
1775
 
            'verbose',
1776
 
            'revision',
1777
 
            Option('non-recursive',
1778
 
                   help='Don\'t recurse into subdirectories.'),
1779
 
            Option('from-root',
1780
 
                   help='Print paths relative to the root of the branch.'),
1781
 
            Option('unknown', help='Print unknown files.'),
1782
 
            Option('versioned', help='Print versioned files.'),
1783
 
            Option('ignored', help='Print ignored files.'),
1784
 
            Option('null',
1785
 
                   help='Write an ascii NUL (\\0) separator '
1786
 
                   'between files rather than a newline.'),
1787
 
            Option('kind',
1788
 
                   help='List entries of a particular kind: file, directory, symlink.',
1789
 
                   type=unicode),
1790
 
            'show-ids',
1791
 
            ]
1792
 
    @display_command
1793
 
    def run(self, revision=None, verbose=False,
1794
 
            non_recursive=False, from_root=False,
1795
 
            unknown=False, versioned=False, ignored=False,
1796
 
            null=False, kind=None, show_ids=False, path=None):
1797
 
 
1798
 
        if kind and kind not in ('file', 'directory', 'symlink'):
1799
 
            raise errors.BzrCommandError('invalid kind specified')
1800
 
 
1801
 
        if verbose and null:
1802
 
            raise errors.BzrCommandError('Cannot set both --verbose and --null')
1803
 
        all = not (unknown or versioned or ignored)
1804
 
 
1805
 
        selection = {'I':ignored, '?':unknown, 'V':versioned}
1806
 
 
1807
 
        if path is None:
1808
 
            fs_path = '.'
1809
 
            prefix = ''
 
754
    hidden = True
 
755
    def run(self, revision=None, verbose=False):
 
756
        b = find_branch('.')
 
757
        if revision == None:
 
758
            tree = b.working_tree()
1810
759
        else:
1811
 
            if from_root:
1812
 
                raise errors.BzrCommandError('cannot specify both --from-root'
1813
 
                                             ' and PATH')
1814
 
            fs_path = path
1815
 
            prefix = path
1816
 
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
1817
 
            fs_path)
1818
 
        if from_root:
1819
 
            relpath = u''
1820
 
        elif relpath:
1821
 
            relpath += '/'
1822
 
        if revision is not None:
1823
 
            tree = branch.repository.revision_tree(
1824
 
                revision[0].in_history(branch).rev_id)
1825
 
        elif tree is None:
1826
 
            tree = branch.basis_tree()
1827
 
 
1828
 
        tree.lock_read()
1829
 
        try:
1830
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
1831
 
                if fp.startswith(relpath):
1832
 
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
1833
 
                    if non_recursive and '/' in fp:
1834
 
                        continue
1835
 
                    if not all and not selection[fc]:
1836
 
                        continue
1837
 
                    if kind is not None and fkind != kind:
1838
 
                        continue
1839
 
                    if verbose:
1840
 
                        kindch = entry.kind_character()
1841
 
                        outstring = '%-8s %s%s' % (fc, fp, kindch)
1842
 
                        if show_ids and fid is not None:
1843
 
                            outstring = "%-50s %s" % (outstring, fid)
1844
 
                        self.outf.write(outstring + '\n')
1845
 
                    elif null:
1846
 
                        self.outf.write(fp + '\0')
1847
 
                        if show_ids:
1848
 
                            if fid is not None:
1849
 
                                self.outf.write(fid)
1850
 
                            self.outf.write('\0')
1851
 
                        self.outf.flush()
1852
 
                    else:
1853
 
                        if fid is not None:
1854
 
                            my_id = fid
1855
 
                        else:
1856
 
                            my_id = ''
1857
 
                        if show_ids:
1858
 
                            self.outf.write('%-50s %s\n' % (fp, my_id))
1859
 
                        else:
1860
 
                            self.outf.write(fp + '\n')
1861
 
        finally:
1862
 
            tree.unlock()
 
760
            tree = b.revision_tree(b.lookup_revision(revision))
 
761
 
 
762
        for fp, fc, kind, fid in tree.list_files():
 
763
            if verbose:
 
764
                if kind == 'directory':
 
765
                    kindch = '/'
 
766
                elif kind == 'file':
 
767
                    kindch = ''
 
768
                else:
 
769
                    kindch = '???'
 
770
 
 
771
                print '%-8s %s%s' % (fc, fp, kindch)
 
772
            else:
 
773
                print fp
 
774
 
1863
775
 
1864
776
 
1865
777
class cmd_unknowns(Command):
1866
 
    """List unknown files.
1867
 
    """
1868
 
 
1869
 
    hidden = True
1870
 
    _see_also = ['ls']
1871
 
 
1872
 
    @display_command
 
778
    """List unknown files."""
1873
779
    def run(self):
1874
 
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1875
 
            self.outf.write(osutils.quotefn(f) + '\n')
 
780
        from bzrlib.osutils import quotefn
 
781
        for f in find_branch('.').unknowns():
 
782
            print quotefn(f)
 
783
 
1876
784
 
1877
785
 
1878
786
class cmd_ignore(Command):
1879
 
    """Ignore specified files or patterns.
 
787
    """Ignore a command or pattern.
1880
788
 
1881
789
    To remove patterns from the ignore list, edit the .bzrignore file.
1882
790
 
1883
 
    Trailing slashes on patterns are ignored. 
1884
 
    If the pattern contains a slash or is a regular expression, it is compared 
1885
 
    to the whole path from the branch root.  Otherwise, it is compared to only
1886
 
    the last component of the path.  To match a file only in the root 
1887
 
    directory, prepend './'.
1888
 
 
1889
 
    Ignore patterns specifying absolute paths are not allowed.
1890
 
 
1891
 
    Ignore patterns may include globbing wildcards such as::
1892
 
 
1893
 
      ? - Matches any single character except '/'
1894
 
      * - Matches 0 or more characters except '/'
1895
 
      /**/ - Matches 0 or more directories in a path
1896
 
      [a-z] - Matches a single character from within a group of characters
1897
 
 
1898
 
    Ignore patterns may also be Python regular expressions.  
1899
 
    Regular expression ignore patterns are identified by a 'RE:' prefix 
1900
 
    followed by the regular expression.  Regular expression ignore patterns
1901
 
    may not include named or numbered groups.
1902
 
 
1903
 
    Note: ignore patterns containing shell wildcards must be quoted from 
1904
 
    the shell on Unix.
1905
 
 
1906
 
    :Examples:
1907
 
        Ignore the top level Makefile::
1908
 
 
1909
 
            bzr ignore ./Makefile
1910
 
 
1911
 
        Ignore class files in all directories::
1912
 
 
1913
 
            bzr ignore '*.class'
1914
 
 
1915
 
        Ignore .o files under the lib directory::
1916
 
 
1917
 
            bzr ignore 'lib/**/*.o'
1918
 
 
1919
 
        Ignore .o files under the lib directory::
1920
 
 
1921
 
            bzr ignore 'RE:lib/.*\.o'
 
791
    If the pattern contains a slash, it is compared to the whole path
 
792
    from the branch root.  Otherwise, it is comapred to only the last
 
793
    component of the path.
 
794
 
 
795
    Ignore patterns are case-insensitive on case-insensitive systems.
 
796
 
 
797
    Note: wildcards must be quoted from the shell on Unix.
 
798
 
 
799
    examples:
 
800
        bzr ignore ./Makefile
 
801
        bzr ignore '*.class'
1922
802
    """
1923
 
 
1924
 
    _see_also = ['status', 'ignored']
1925
 
    takes_args = ['name_pattern*']
1926
 
    takes_options = [
1927
 
        Option('old-default-rules',
1928
 
               help='Write out the ignore rules bzr < 0.9 always used.')
1929
 
        ]
 
803
    takes_args = ['name_pattern']
1930
804
    
1931
 
    def run(self, name_pattern_list=None, old_default_rules=None):
 
805
    def run(self, name_pattern):
1932
806
        from bzrlib.atomicfile import AtomicFile
1933
 
        if old_default_rules is not None:
1934
 
            # dump the rules and exit
1935
 
            for pattern in ignores.OLD_DEFAULTS:
1936
 
                print pattern
1937
 
            return
1938
 
        if not name_pattern_list:
1939
 
            raise errors.BzrCommandError("ignore requires at least one "
1940
 
                                  "NAME_PATTERN or --old-default-rules")
1941
 
        name_pattern_list = [globbing.normalize_pattern(p) 
1942
 
                             for p in name_pattern_list]
1943
 
        for name_pattern in name_pattern_list:
1944
 
            if (name_pattern[0] == '/' or 
1945
 
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
1946
 
                raise errors.BzrCommandError(
1947
 
                    "NAME_PATTERN should not be an absolute path")
1948
 
        tree, relpath = WorkingTree.open_containing(u'.')
1949
 
        ifn = tree.abspath('.bzrignore')
 
807
        import os.path
 
808
 
 
809
        b = find_branch('.')
 
810
        ifn = b.abspath('.bzrignore')
 
811
 
1950
812
        if os.path.exists(ifn):
1951
813
            f = open(ifn, 'rt')
1952
814
            try:
1961
823
 
1962
824
        if igns and igns[-1] != '\n':
1963
825
            igns += '\n'
1964
 
        for name_pattern in name_pattern_list:
1965
 
            igns += name_pattern + '\n'
 
826
        igns += name_pattern + '\n'
1966
827
 
1967
 
        f = AtomicFile(ifn, 'wb')
1968
828
        try:
 
829
            f = AtomicFile(ifn, 'wt')
1969
830
            f.write(igns.encode('utf-8'))
1970
831
            f.commit()
1971
832
        finally:
1972
833
            f.close()
1973
834
 
1974
 
        if not tree.path2id('.bzrignore'):
1975
 
            tree.add(['.bzrignore'])
1976
 
 
1977
 
        ignored = globbing.Globster(name_pattern_list)
1978
 
        matches = []
1979
 
        tree.lock_read()
1980
 
        for entry in tree.list_files():
1981
 
            id = entry[3]
1982
 
            if id is not None:
1983
 
                filename = entry[0]
1984
 
                if ignored.match(filename):
1985
 
                    matches.append(filename.encode('utf-8'))
1986
 
        tree.unlock()
1987
 
        if len(matches) > 0:
1988
 
            print "Warning: the following files are version controlled and" \
1989
 
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
 
835
        inv = b.working_tree().inventory
 
836
        if inv.path2id('.bzrignore'):
 
837
            mutter('.bzrignore is already versioned')
 
838
        else:
 
839
            mutter('need to make new .bzrignore file versioned')
 
840
            b.add(['.bzrignore'])
 
841
 
 
842
 
1990
843
 
1991
844
class cmd_ignored(Command):
1992
845
    """List ignored files and the patterns that matched them.
1993
 
    """
1994
846
 
1995
 
    _see_also = ['ignore']
1996
 
    @display_command
 
847
    See also: bzr ignore"""
1997
848
    def run(self):
1998
 
        tree = WorkingTree.open_containing(u'.')[0]
1999
 
        tree.lock_read()
2000
 
        try:
2001
 
            for path, file_class, kind, file_id, entry in tree.list_files():
2002
 
                if file_class != 'I':
2003
 
                    continue
2004
 
                ## XXX: Slightly inefficient since this was already calculated
2005
 
                pat = tree.is_ignored(path)
2006
 
                print '%-50s %s' % (path, pat)
2007
 
        finally:
2008
 
            tree.unlock()
 
849
        tree = find_branch('.').working_tree()
 
850
        for path, file_class, kind, file_id in tree.list_files():
 
851
            if file_class != 'I':
 
852
                continue
 
853
            ## XXX: Slightly inefficient since this was already calculated
 
854
            pat = tree.is_ignored(path)
 
855
            print '%-50s %s' % (path, pat)
2009
856
 
2010
857
 
2011
858
class cmd_lookup_revision(Command):
2012
859
    """Lookup the revision-id from a revision-number
2013
860
 
2014
 
    :Examples:
 
861
    example:
2015
862
        bzr lookup-revision 33
2016
863
    """
2017
864
    hidden = True
2018
865
    takes_args = ['revno']
2019
866
    
2020
 
    @display_command
2021
867
    def run(self, revno):
2022
868
        try:
2023
869
            revno = int(revno)
2024
870
        except ValueError:
2025
 
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
 
871
            raise BzrCommandError("not a valid revision-number: %r" % revno)
2026
872
 
2027
 
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
873
        print find_branch('.').lookup_revision(revno)
2028
874
 
2029
875
 
2030
876
class cmd_export(Command):
2031
 
    """Export current or past revision to a destination directory or archive.
 
877
    """Export past revision to destination directory.
2032
878
 
2033
879
    If no revision is specified this exports the last committed revision.
2034
880
 
2036
882
    given, try to find the format with the extension. If no extension
2037
883
    is found exports to a directory (equivalent to --format=dir).
2038
884
 
2039
 
    If root is supplied, it will be used as the root directory inside
2040
 
    container formats (tar, zip, etc). If it is not supplied it will default
2041
 
    to the exported filename. The root option has no effect for 'dir' format.
2042
 
 
2043
 
    If branch is omitted then the branch containing the current working
2044
 
    directory will be used.
2045
 
 
2046
 
    Note: Export of tree with non-ASCII filenames to zip is not supported.
2047
 
 
2048
 
      =================       =========================
2049
 
      Supported formats       Autodetected by extension
2050
 
      =================       =========================
2051
 
         dir                         (none)
2052
 
         tar                          .tar
2053
 
         tbz2                    .tar.bz2, .tbz2
2054
 
         tgz                      .tar.gz, .tgz
2055
 
         zip                          .zip
2056
 
      =================       =========================
2057
 
    """
2058
 
    takes_args = ['dest', 'branch?']
2059
 
    takes_options = [
2060
 
        Option('format',
2061
 
               help="Type of file to export to.",
2062
 
               type=unicode),
2063
 
        'revision',
2064
 
        Option('root',
2065
 
               type=str,
2066
 
               help="Name of the root directory inside the exported file."),
2067
 
        ]
2068
 
    def run(self, dest, branch=None, revision=None, format=None, root=None):
2069
 
        from bzrlib.export import export
2070
 
 
2071
 
        if branch is None:
2072
 
            tree = WorkingTree.open_containing(u'.')[0]
2073
 
            b = tree.branch
2074
 
        else:
2075
 
            b = Branch.open(branch)
2076
 
            
 
885
    Root may be the top directory for tar, tgz and tbz2 formats. If none
 
886
    is given, the top directory will be the root name of the file."""
 
887
    # TODO: list known exporters
 
888
    takes_args = ['dest']
 
889
    takes_options = ['revision', 'format', 'root']
 
890
    def run(self, dest, revision=None, format=None, root=None):
 
891
        import os.path
 
892
        b = find_branch('.')
2077
893
        if revision is None:
2078
 
            # should be tree.last_revision  FIXME
2079
 
            rev_id = b.last_revision()
 
894
            rev_id = b.last_patch()
2080
895
        else:
2081
896
            if len(revision) != 1:
2082
 
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2083
 
            rev_id = revision[0].in_history(b).rev_id
2084
 
        t = b.repository.revision_tree(rev_id)
2085
 
        try:
2086
 
            export(t, dest, format, root)
2087
 
        except errors.NoSuchExportFormat, e:
2088
 
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
 
897
                raise BzrError('bzr export --revision takes exactly 1 argument')
 
898
            revno, rev_id = b.get_revision_info(revision[0])
 
899
        t = b.revision_tree(rev_id)
 
900
        root, ext = os.path.splitext(dest)
 
901
        if not format:
 
902
            if ext in (".tar",):
 
903
                format = "tar"
 
904
            elif ext in (".gz", ".tgz"):
 
905
                format = "tgz"
 
906
            elif ext in (".bz2", ".tbz2"):
 
907
                format = "tbz2"
 
908
            else:
 
909
                format = "dir"
 
910
        t.export(dest, format, root)
2089
911
 
2090
912
 
2091
913
class cmd_cat(Command):
2092
 
    """Write the contents of a file as of a given revision to standard output.
2093
 
 
2094
 
    If no revision is nominated, the last revision is used.
2095
 
 
2096
 
    Note: Take care to redirect standard output when using this command on a
2097
 
    binary file. 
2098
 
    """
2099
 
 
2100
 
    _see_also = ['ls']
2101
 
    takes_options = [
2102
 
        Option('name-from-revision', help='The path name in the old tree.'),
2103
 
        'revision',
2104
 
        ]
 
914
    """Write a file's text from a previous revision."""
 
915
 
 
916
    takes_options = ['revision']
2105
917
    takes_args = ['filename']
2106
 
    encoding_type = 'exact'
2107
 
 
2108
 
    @display_command
2109
 
    def run(self, filename, revision=None, name_from_revision=False):
2110
 
        if revision is not None and len(revision) != 1:
2111
 
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2112
 
                                        " one number")
2113
 
 
2114
 
        tree = None
2115
 
        try:
2116
 
            tree, b, relpath = \
2117
 
                    bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2118
 
        except errors.NotBranchError:
2119
 
            pass
2120
 
 
2121
 
        if revision is not None and revision[0].get_branch() is not None:
2122
 
            b = Branch.open(revision[0].get_branch())
2123
 
        if tree is None:
2124
 
            tree = b.basis_tree()
2125
 
        if revision is None:
2126
 
            revision_id = b.last_revision()
2127
 
        else:
2128
 
            revision_id = revision[0].in_history(b).rev_id
2129
 
 
2130
 
        cur_file_id = tree.path2id(relpath)
2131
 
        rev_tree = b.repository.revision_tree(revision_id)
2132
 
        old_file_id = rev_tree.path2id(relpath)
2133
 
        
2134
 
        if name_from_revision:
2135
 
            if old_file_id is None:
2136
 
                raise errors.BzrCommandError("%r is not present in revision %s"
2137
 
                                                % (filename, revision_id))
2138
 
            else:
2139
 
                rev_tree.print_file(old_file_id)
2140
 
        elif cur_file_id is not None:
2141
 
            rev_tree.print_file(cur_file_id)
2142
 
        elif old_file_id is not None:
2143
 
            rev_tree.print_file(old_file_id)
2144
 
        else:
2145
 
            raise errors.BzrCommandError("%r is not present in revision %s" %
2146
 
                                         (filename, revision_id))
 
918
 
 
919
    def run(self, filename, revision=None):
 
920
        if revision == None:
 
921
            raise BzrCommandError("bzr cat requires a revision number")
 
922
        elif len(revision) != 1:
 
923
            raise BzrCommandError("bzr cat --revision takes exactly one number")
 
924
        b = find_branch('.')
 
925
        b.print_file(b.relpath(filename), revision[0])
2147
926
 
2148
927
 
2149
928
class cmd_local_time_offset(Command):
2150
929
    """Show the offset in seconds from GMT to local time."""
2151
930
    hidden = True    
2152
 
    @display_command
2153
931
    def run(self):
2154
 
        print osutils.local_time_offset()
 
932
        print bzrlib.osutils.local_time_offset()
2155
933
 
2156
934
 
2157
935
 
2164
942
    committed.  If a directory is specified then the directory and everything 
2165
943
    within it is committed.
2166
944
 
2167
 
    If author of the change is not the same person as the committer, you can
2168
 
    specify the author's name using the --author option. The name should be
2169
 
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2170
 
 
2171
945
    A selected-file commit may fail in some cases where the committed
2172
 
    tree would be invalid. Consider::
2173
 
 
2174
 
      bzr init foo
2175
 
      mkdir foo/bar
2176
 
      bzr add foo/bar
2177
 
      bzr commit foo -m "committing foo"
2178
 
      bzr mv foo/bar foo/baz
2179
 
      mkdir foo/bar
2180
 
      bzr add foo/bar
2181
 
      bzr commit foo/bar -m "committing bar but not baz"
2182
 
 
2183
 
    In the example above, the last commit will fail by design. This gives
2184
 
    the user the opportunity to decide whether they want to commit the
2185
 
    rename at the same time, separately first, or not at all. (As a general
2186
 
    rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2187
 
 
2188
 
    Note: A selected-file commit after a merge is not yet supported.
 
946
    tree would be invalid, such as trying to commit a file in a
 
947
    newly-added directory that is not itself committed.
 
948
 
 
949
    TODO: Run hooks on tree to-be-committed, and after commit.
 
950
 
 
951
    TODO: Strict commit that fails if there are unknown or deleted files.
2189
952
    """
2190
 
    # TODO: Run hooks on tree to-be-committed, and after commit.
2191
 
 
2192
 
    # TODO: Strict commit that fails if there are deleted files.
2193
 
    #       (what does "deleted files" mean ??)
 
953
    takes_args = ['selected*']
 
954
    takes_options = ['message', 'file', 'verbose', 'unchanged']
 
955
    aliases = ['ci', 'checkin']
2194
956
 
2195
957
    # TODO: Give better message for -s, --summary, used by tla people
2196
958
 
2197
959
    # XXX: verbose currently does nothing
2198
 
 
2199
 
    _see_also = ['bugs', 'uncommit']
2200
 
    takes_args = ['selected*']
2201
 
    takes_options = [
2202
 
            Option('message', type=unicode,
2203
 
                   short_name='m',
2204
 
                   help="Description of the new revision."),
2205
 
            'verbose',
2206
 
             Option('unchanged',
2207
 
                    help='Commit even if nothing has changed.'),
2208
 
             Option('file', type=str,
2209
 
                    short_name='F',
2210
 
                    argname='msgfile',
2211
 
                    help='Take commit message from this file.'),
2212
 
             Option('strict',
2213
 
                    help="Refuse to commit if there are unknown "
2214
 
                    "files in the working tree."),
2215
 
             ListOption('fixes', type=str,
2216
 
                    help="Mark a bug as being fixed by this revision."),
2217
 
             Option('author', type=str,
2218
 
                    help="Set the author's name, if it's different "
2219
 
                         "from the committer."),
2220
 
             Option('local',
2221
 
                    help="Perform a local commit in a bound "
2222
 
                         "branch.  Local commits are not pushed to "
2223
 
                         "the master branch until a normal commit "
2224
 
                         "is performed."
2225
 
                    ),
2226
 
              Option('show-diff',
2227
 
                     help='When no message is supplied, show the diff along'
2228
 
                     ' with the status summary in the message editor.'),
2229
 
             ]
2230
 
    aliases = ['ci', 'checkin']
2231
 
 
2232
 
    def _get_bug_fix_properties(self, fixes, branch):
2233
 
        properties = []
2234
 
        # Configure the properties for bug fixing attributes.
2235
 
        for fixed_bug in fixes:
2236
 
            tokens = fixed_bug.split(':')
2237
 
            if len(tokens) != 2:
2238
 
                raise errors.BzrCommandError(
2239
 
                    "Invalid bug %s. Must be in the form of 'tag:id'. "
2240
 
                    "Commit refused." % fixed_bug)
2241
 
            tag, bug_id = tokens
2242
 
            try:
2243
 
                bug_url = bugtracker.get_bug_url(tag, branch, bug_id)
2244
 
            except errors.UnknownBugTrackerAbbreviation:
2245
 
                raise errors.BzrCommandError(
2246
 
                    'Unrecognized bug %s. Commit refused.' % fixed_bug)
2247
 
            except errors.MalformedBugIdentifier:
2248
 
                raise errors.BzrCommandError(
2249
 
                    "Invalid bug identifier for %s. Commit refused."
2250
 
                    % fixed_bug)
2251
 
            properties.append('%s fixed' % bug_url)
2252
 
        return '\n'.join(properties)
2253
 
 
2254
 
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2255
 
            unchanged=False, strict=False, local=False, fixes=None,
2256
 
            author=None, show_diff=False):
2257
 
        from bzrlib.commit import (
2258
 
            NullCommitReporter,
2259
 
            ReportCommitToLog
2260
 
        )
2261
 
        from bzrlib.errors import (
2262
 
            PointlessCommit,
2263
 
            ConflictsInTree,
2264
 
            StrictCommitFailed
2265
 
        )
2266
 
        from bzrlib.msgeditor import (
2267
 
            edit_commit_message_encoded,
2268
 
            make_commit_message_template_encoded
2269
 
        )
2270
 
 
2271
 
        # TODO: Need a blackbox test for invoking the external editor; may be
2272
 
        # slightly problematic to run this cross-platform.
2273
 
 
2274
 
        # TODO: do more checks that the commit will succeed before 
2275
 
        # spending the user's valuable time typing a commit message.
2276
 
 
2277
 
        properties = {}
2278
 
 
2279
 
        tree, selected_list = tree_files(selected_list)
2280
 
        if selected_list == ['']:
2281
 
            # workaround - commit of root of tree should be exactly the same
2282
 
            # as just default commit in that tree, and succeed even though
2283
 
            # selected-file merge commit is not done yet
2284
 
            selected_list = []
2285
 
 
2286
 
        bug_property = self._get_bug_fix_properties(fixes, tree.branch)
2287
 
        if bug_property:
2288
 
            properties['bugs'] = bug_property
2289
 
 
2290
 
        if local and not tree.branch.get_bound_location():
2291
 
            raise errors.LocalRequiresBoundBranch()
2292
 
 
2293
 
        def get_message(commit_obj):
2294
 
            """Callback to get commit message"""
2295
 
            my_message = message
2296
 
            if my_message is None and not file:
2297
 
                t = make_commit_message_template_encoded(tree,
2298
 
                        selected_list, diff=show_diff,
2299
 
                        output_encoding=bzrlib.user_encoding)
2300
 
                my_message = edit_commit_message_encoded(t)
2301
 
                if my_message is None:
2302
 
                    raise errors.BzrCommandError("please specify a commit"
2303
 
                        " message with either --message or --file")
2304
 
            elif my_message and file:
2305
 
                raise errors.BzrCommandError(
2306
 
                    "please specify either --message or --file")
2307
 
            if file:
2308
 
                my_message = codecs.open(file, 'rt', 
2309
 
                                         bzrlib.user_encoding).read()
2310
 
            if my_message == "":
2311
 
                raise errors.BzrCommandError("empty commit message specified")
2312
 
            return my_message
 
960
    
 
961
    def run(self, message=None, file=None, verbose=True, selected_list=None,
 
962
            unchanged=False):
 
963
        from bzrlib.errors import PointlessCommit
 
964
        from bzrlib.msgeditor import edit_commit_message
 
965
        from bzrlib.status import show_status
 
966
        from cStringIO import StringIO
 
967
 
 
968
        b = find_branch('.')
 
969
        if selected_list:
 
970
            selected_list = [b.relpath(s) for s in selected_list]
 
971
            
 
972
        if not message and not file:
 
973
            catcher = StringIO()
 
974
            show_status(b, specific_files=selected_list,
 
975
                        to_file=catcher)
 
976
            message = edit_commit_message(catcher.getvalue())
 
977
            
 
978
            if message is None:
 
979
                raise BzrCommandError("please specify a commit message"
 
980
                                      " with either --message or --file")
 
981
        elif message and file:
 
982
            raise BzrCommandError("please specify either --message or --file")
 
983
        
 
984
        if file:
 
985
            import codecs
 
986
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
2313
987
 
2314
988
        try:
2315
 
            tree.commit(message_callback=get_message,
2316
 
                        specific_files=selected_list,
2317
 
                        allow_pointless=unchanged, strict=strict, local=local,
2318
 
                        reporter=None, verbose=verbose, revprops=properties,
2319
 
                        author=author)
 
989
            b.commit(message,
 
990
                     specific_files=selected_list,
 
991
                     allow_pointless=unchanged)
2320
992
        except PointlessCommit:
2321
993
            # FIXME: This should really happen before the file is read in;
2322
994
            # perhaps prepare the commit; get the message; then actually commit
2323
 
            raise errors.BzrCommandError("no changes to commit."
2324
 
                              " use --unchanged to commit anyhow")
2325
 
        except ConflictsInTree:
2326
 
            raise errors.BzrCommandError('Conflicts detected in working '
2327
 
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
2328
 
                ' resolve.')
2329
 
        except StrictCommitFailed:
2330
 
            raise errors.BzrCommandError("Commit refused because there are"
2331
 
                              " unknown files in the working tree.")
2332
 
        except errors.BoundBranchOutOfDate, e:
2333
 
            raise errors.BzrCommandError(str(e) + "\n"
2334
 
            'To commit to master branch, run update and then commit.\n'
2335
 
            'You can also pass --local to commit to continue working '
2336
 
            'disconnected.')
 
995
            raise BzrCommandError("no changes to commit",
 
996
                                  ["use --unchanged to commit anyhow"])
2337
997
 
2338
998
 
2339
999
class cmd_check(Command):
2341
1001
 
2342
1002
    This command checks various invariants about the branch storage to
2343
1003
    detect data corruption or bzr bugs.
 
1004
 
 
1005
    If given the --update flag, it will update some optional fields
 
1006
    to help ensure data consistency.
2344
1007
    """
2345
 
 
2346
 
    _see_also = ['reconcile']
2347
 
    takes_args = ['branch?']
2348
 
    takes_options = ['verbose']
2349
 
 
2350
 
    def run(self, branch=None, verbose=False):
 
1008
    takes_args = ['dir?']
 
1009
 
 
1010
    def run(self, dir='.'):
2351
1011
        from bzrlib.check import check
2352
 
        if branch is None:
2353
 
            tree = WorkingTree.open_containing()[0]
2354
 
            branch = tree.branch
2355
 
        else:
2356
 
            branch = Branch.open(branch)
2357
 
        check(branch, verbose)
 
1012
 
 
1013
        check(find_branch(dir))
 
1014
 
 
1015
 
 
1016
class cmd_scan_cache(Command):
 
1017
    hidden = True
 
1018
    def run(self):
 
1019
        from bzrlib.hashcache import HashCache
 
1020
 
 
1021
        c = HashCache('.')
 
1022
        c.read()
 
1023
        c.scan()
 
1024
            
 
1025
        print '%6d stats' % c.stat_count
 
1026
        print '%6d in hashcache' % len(c._cache)
 
1027
        print '%6d files removed from cache' % c.removed_count
 
1028
        print '%6d hashes updated' % c.update_count
 
1029
        print '%6d files changed too recently to cache' % c.danger_count
 
1030
 
 
1031
        if c.needs_write:
 
1032
            c.write()
 
1033
            
2358
1034
 
2359
1035
 
2360
1036
class cmd_upgrade(Command):
2361
1037
    """Upgrade branch storage to current format.
2362
1038
 
2363
1039
    The check command or bzr developers may sometimes advise you to run
2364
 
    this command. When the default format has changed you may also be warned
2365
 
    during other operations to upgrade.
 
1040
    this command.
2366
1041
    """
2367
 
 
2368
 
    _see_also = ['check']
2369
 
    takes_args = ['url?']
2370
 
    takes_options = [
2371
 
                    RegistryOption('format',
2372
 
                        help='Upgrade to a specific format.  See "bzr help'
2373
 
                             ' formats" for details.',
2374
 
                        registry=bzrdir.format_registry,
2375
 
                        converter=bzrdir.format_registry.make_bzrdir,
2376
 
                        value_switches=True, title='Branch format'),
2377
 
                    ]
2378
 
 
2379
 
    def run(self, url='.', format=None):
 
1042
    takes_args = ['dir?']
 
1043
 
 
1044
    def run(self, dir='.'):
2380
1045
        from bzrlib.upgrade import upgrade
2381
 
        if format is None:
2382
 
            format = bzrdir.format_registry.make_bzrdir('default')
2383
 
        upgrade(url, format)
 
1046
        upgrade(find_branch(dir))
 
1047
 
2384
1048
 
2385
1049
 
2386
1050
class cmd_whoami(Command):
2387
 
    """Show or set bzr user id.
2388
 
    
2389
 
    :Examples:
2390
 
        Show the email of the current user::
2391
 
 
2392
 
            bzr whoami --email
2393
 
 
2394
 
        Set the current user::
2395
 
 
2396
 
            bzr whoami 'Frank Chu <fchu@example.com>'
2397
 
    """
2398
 
    takes_options = [ Option('email',
2399
 
                             help='Display email address only.'),
2400
 
                      Option('branch',
2401
 
                             help='Set identity for the current branch instead of '
2402
 
                                  'globally.'),
2403
 
                    ]
2404
 
    takes_args = ['name?']
2405
 
    encoding_type = 'replace'
2406
 
    
2407
 
    @display_command
2408
 
    def run(self, email=False, branch=False, name=None):
2409
 
        if name is None:
2410
 
            # use branch if we're inside one; otherwise global config
2411
 
            try:
2412
 
                c = Branch.open_containing('.')[0].get_config()
2413
 
            except errors.NotBranchError:
2414
 
                c = config.GlobalConfig()
2415
 
            if email:
2416
 
                self.outf.write(c.user_email() + '\n')
2417
 
            else:
2418
 
                self.outf.write(c.username() + '\n')
2419
 
            return
2420
 
 
2421
 
        # display a warning if an email address isn't included in the given name.
 
1051
    """Show bzr user id."""
 
1052
    takes_options = ['email']
 
1053
    
 
1054
    def run(self, email=False):
2422
1055
        try:
2423
 
            config.extract_email_address(name)
2424
 
        except errors.NoEmailInUsername, e:
2425
 
            warning('"%s" does not seem to contain an email address.  '
2426
 
                    'This is allowed, but not recommended.', name)
 
1056
            b = bzrlib.branch.find_branch('.')
 
1057
        except:
 
1058
            b = None
2427
1059
        
2428
 
        # use global config unless --branch given
2429
 
        if branch:
2430
 
            c = Branch.open_containing('.')[0].get_config()
2431
 
        else:
2432
 
            c = config.GlobalConfig()
2433
 
        c.set_user_option('email', name)
2434
 
 
2435
 
 
2436
 
class cmd_nick(Command):
2437
 
    """Print or set the branch nickname.  
2438
 
 
2439
 
    If unset, the tree root directory name is used as the nickname
2440
 
    To print the current nickname, execute with no argument.  
2441
 
    """
2442
 
 
2443
 
    _see_also = ['info']
2444
 
    takes_args = ['nickname?']
2445
 
    def run(self, nickname=None):
2446
 
        branch = Branch.open_containing(u'.')[0]
2447
 
        if nickname is None:
2448
 
            self.printme(branch)
2449
 
        else:
2450
 
            branch.nick = nickname
2451
 
 
2452
 
    @display_command
2453
 
    def printme(self, branch):
2454
 
        print branch.nick
 
1060
        if email:
 
1061
            print bzrlib.osutils.user_email(b)
 
1062
        else:
 
1063
            print bzrlib.osutils.username(b)
2455
1064
 
2456
1065
 
2457
1066
class cmd_selftest(Command):
2458
 
    """Run internal test suite.
2459
 
    
2460
 
    If arguments are given, they are regular expressions that say which tests
2461
 
    should run.  Tests matching any expression are run, and other tests are
2462
 
    not run.
2463
 
 
2464
 
    Alternatively if --first is given, matching tests are run first and then
2465
 
    all other tests are run.  This is useful if you have been working in a
2466
 
    particular area, but want to make sure nothing else was broken.
2467
 
 
2468
 
    If --exclude is given, tests that match that regular expression are
2469
 
    excluded, regardless of whether they match --first or not.
2470
 
 
2471
 
    To help catch accidential dependencies between tests, the --randomize
2472
 
    option is useful. In most cases, the argument used is the word 'now'.
2473
 
    Note that the seed used for the random number generator is displayed
2474
 
    when this option is used. The seed can be explicitly passed as the
2475
 
    argument to this option if required. This enables reproduction of the
2476
 
    actual ordering used if and when an order sensitive problem is encountered.
2477
 
 
2478
 
    If --list-only is given, the tests that would be run are listed. This is
2479
 
    useful when combined with --first, --exclude and/or --randomize to
2480
 
    understand their impact. The test harness reports "Listed nn tests in ..."
2481
 
    instead of "Ran nn tests in ..." when list mode is enabled.
2482
 
 
2483
 
    If the global option '--no-plugins' is given, plugins are not loaded
2484
 
    before running the selftests.  This has two effects: features provided or
2485
 
    modified by plugins will not be tested, and tests provided by plugins will
2486
 
    not be run.
2487
 
 
2488
 
    Tests that need working space on disk use a common temporary directory, 
2489
 
    typically inside $TMPDIR or /tmp.
2490
 
 
2491
 
    :Examples:
2492
 
        Run only tests relating to 'ignore'::
2493
 
 
2494
 
            bzr selftest ignore
2495
 
 
2496
 
        Disable plugins and list tests as they're run::
2497
 
 
2498
 
            bzr --no-plugins selftest -v
2499
 
    """
2500
 
    # NB: this is used from the class without creating an instance, which is
2501
 
    # why it does not have a self parameter.
2502
 
    def get_transport_type(typestring):
2503
 
        """Parse and return a transport specifier."""
2504
 
        if typestring == "sftp":
2505
 
            from bzrlib.transport.sftp import SFTPAbsoluteServer
2506
 
            return SFTPAbsoluteServer
2507
 
        if typestring == "memory":
2508
 
            from bzrlib.transport.memory import MemoryServer
2509
 
            return MemoryServer
2510
 
        if typestring == "fakenfs":
2511
 
            from bzrlib.transport.fakenfs import FakeNFSServer
2512
 
            return FakeNFSServer
2513
 
        msg = "No known transport type %s. Supported types are: sftp\n" %\
2514
 
            (typestring)
2515
 
        raise errors.BzrCommandError(msg)
2516
 
 
 
1067
    """Run internal test suite"""
2517
1068
    hidden = True
2518
 
    takes_args = ['testspecs*']
2519
 
    takes_options = ['verbose',
2520
 
                     Option('one',
2521
 
                             help='Stop when one test fails.',
2522
 
                             short_name='1',
2523
 
                             ),
2524
 
                     Option('transport',
2525
 
                            help='Use a different transport by default '
2526
 
                                 'throughout the test suite.',
2527
 
                            type=get_transport_type),
2528
 
                     Option('benchmark',
2529
 
                            help='Run the benchmarks rather than selftests.'),
2530
 
                     Option('lsprof-timed',
2531
 
                            help='Generate lsprof output for benchmarked'
2532
 
                                 ' sections of code.'),
2533
 
                     Option('cache-dir', type=str,
2534
 
                            help='Cache intermediate benchmark output in this '
2535
 
                                 'directory.'),
2536
 
                     Option('first',
2537
 
                            help='Run all tests, but run specified tests first.',
2538
 
                            short_name='f',
2539
 
                            ),
2540
 
                     Option('list-only',
2541
 
                            help='List the tests instead of running them.'),
2542
 
                     Option('randomize', type=str, argname="SEED",
2543
 
                            help='Randomize the order of tests using the given'
2544
 
                                 ' seed or "now" for the current time.'),
2545
 
                     Option('exclude', type=str, argname="PATTERN",
2546
 
                            short_name='x',
2547
 
                            help='Exclude tests that match this regular'
2548
 
                                 ' expression.'),
2549
 
                     Option('strict', help='Fail on missing dependencies or '
2550
 
                            'known failures.'),
2551
 
                     ]
2552
 
    encoding_type = 'replace'
2553
 
 
2554
 
    def run(self, testspecs_list=None, verbose=False, one=False,
2555
 
            transport=None, benchmark=None,
2556
 
            lsprof_timed=None, cache_dir=None,
2557
 
            first=False, list_only=False,
2558
 
            randomize=None, exclude=None, strict=False):
 
1069
    takes_options = ['verbose', 'pattern']
 
1070
    def run(self, verbose=False, pattern=".*"):
2559
1071
        import bzrlib.ui
2560
 
        from bzrlib.tests import selftest
2561
 
        import bzrlib.benchmarks as benchmarks
2562
 
        from bzrlib.benchmarks import tree_creator
2563
 
 
2564
 
        if cache_dir is not None:
2565
 
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2566
 
        if not list_only:
2567
 
            print 'testing: %s' % (osutils.realpath(sys.argv[0]),)
2568
 
            print '   %s (%s python%s)' % (
2569
 
                    bzrlib.__path__[0],
2570
 
                    bzrlib.version_string,
2571
 
                    '.'.join(map(str, sys.version_info)),
2572
 
                    )
2573
 
        print
2574
 
        if testspecs_list is not None:
2575
 
            pattern = '|'.join(testspecs_list)
2576
 
        else:
2577
 
            pattern = ".*"
2578
 
        if benchmark:
2579
 
            test_suite_factory = benchmarks.test_suite
2580
 
            # Unless user explicitly asks for quiet, be verbose in benchmarks
2581
 
            verbose = not is_quiet()
2582
 
            # TODO: should possibly lock the history file...
2583
 
            benchfile = open(".perf_history", "at", buffering=1)
2584
 
        else:
2585
 
            test_suite_factory = None
2586
 
            benchfile = None
 
1072
        from bzrlib.selftest import selftest
 
1073
        # we don't want progress meters from the tests to go to the
 
1074
        # real output; and we don't want log messages cluttering up
 
1075
        # the real logs.
 
1076
        save_ui = bzrlib.ui.ui_factory
 
1077
        bzrlib.trace.info('running tests...')
2587
1078
        try:
2588
 
            result = selftest(verbose=verbose,
2589
 
                              pattern=pattern,
2590
 
                              stop_on_failure=one,
2591
 
                              transport=transport,
2592
 
                              test_suite_factory=test_suite_factory,
2593
 
                              lsprof_timed=lsprof_timed,
2594
 
                              bench_history=benchfile,
2595
 
                              matching_tests_first=first,
2596
 
                              list_only=list_only,
2597
 
                              random_seed=randomize,
2598
 
                              exclude_pattern=exclude,
2599
 
                              strict=strict,
2600
 
                              )
 
1079
            bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
 
1080
            result = selftest(verbose=verbose, pattern=pattern)
 
1081
            if result:
 
1082
                bzrlib.trace.info('tests passed')
 
1083
            else:
 
1084
                bzrlib.trace.info('tests failed')
 
1085
            return int(not result)
2601
1086
        finally:
2602
 
            if benchfile is not None:
2603
 
                benchfile.close()
2604
 
        if result:
2605
 
            info('tests passed')
2606
 
        else:
2607
 
            info('tests failed')
2608
 
        return int(not result)
 
1087
            bzrlib.ui.ui_factory = save_ui
 
1088
 
 
1089
 
 
1090
def show_version():
 
1091
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
 
1092
    # is bzrlib itself in a branch?
 
1093
    bzrrev = bzrlib.get_bzr_revision()
 
1094
    if bzrrev:
 
1095
        print "  (bzr checkout, revision %d {%s})" % bzrrev
 
1096
    print bzrlib.__copyright__
 
1097
    print "http://bazaar-ng.org/"
 
1098
    print
 
1099
    print "bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and"
 
1100
    print "you may use, modify and redistribute it under the terms of the GNU"
 
1101
    print "General Public License version 2 or later."
2609
1102
 
2610
1103
 
2611
1104
class cmd_version(Command):
2612
1105
    """Show version of bzr."""
2613
 
 
2614
 
    encoding_type = 'replace'
2615
 
 
2616
 
    @display_command
2617
1106
    def run(self):
2618
 
        from bzrlib.version import show_version
2619
 
        show_version(to_file=self.outf)
2620
 
 
 
1107
        show_version()
2621
1108
 
2622
1109
class cmd_rocks(Command):
2623
1110
    """Statement of optimism."""
2624
 
 
2625
1111
    hidden = True
2626
 
 
2627
 
    @display_command
2628
1112
    def run(self):
2629
 
        print "It sure does!"
 
1113
        print "it sure does!"
2630
1114
 
2631
1115
 
2632
1116
class cmd_find_merge_base(Command):
2633
 
    """Find and print a base revision for merging two branches."""
2634
 
    # TODO: Options to specify revisions on either side, as if
2635
 
    #       merging only part of the history.
 
1117
    """Find and print a base revision for merging two branches.
 
1118
 
 
1119
    TODO: Options to specify revisions on either side, as if
 
1120
          merging only part of the history.
 
1121
    """
2636
1122
    takes_args = ['branch', 'other']
2637
1123
    hidden = True
2638
1124
    
2639
 
    @display_command
2640
1125
    def run(self, branch, other):
2641
 
        from bzrlib.revision import ensure_null, MultipleRevisionSources
2642
 
        
2643
 
        branch1 = Branch.open_containing(branch)[0]
2644
 
        branch2 = Branch.open_containing(other)[0]
2645
 
 
2646
 
        last1 = ensure_null(branch1.last_revision())
2647
 
        last2 = ensure_null(branch2.last_revision())
2648
 
 
2649
 
        graph = branch1.repository.get_graph(branch2.repository)
2650
 
        base_rev_id = graph.find_unique_lca(last1, last2)
 
1126
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
 
1127
        
 
1128
        branch1 = find_branch(branch)
 
1129
        branch2 = find_branch(other)
 
1130
 
 
1131
        history_1 = branch1.revision_history()
 
1132
        history_2 = branch2.revision_history()
 
1133
 
 
1134
        last1 = branch1.last_patch()
 
1135
        last2 = branch2.last_patch()
 
1136
 
 
1137
        source = MultipleRevisionSources(branch1, branch2)
 
1138
        
 
1139
        base_rev_id = common_ancestor(last1, last2, source)
2651
1140
 
2652
1141
        print 'merge base is revision %s' % base_rev_id
 
1142
        
 
1143
        return
 
1144
 
 
1145
        if base_revno is None:
 
1146
            raise bzrlib.errors.UnrelatedBranches()
 
1147
 
 
1148
        print ' r%-6d in %s' % (base_revno, branch)
 
1149
 
 
1150
        other_revno = branch2.revision_id_to_revno(base_revid)
 
1151
        
 
1152
        print ' r%-6d in %s' % (other_revno, other)
 
1153
 
2653
1154
 
2654
1155
 
2655
1156
class cmd_merge(Command):
2656
1157
    """Perform a three-way merge.
2657
1158
    
2658
 
    The branch is the branch you will merge from.  By default, it will merge
2659
 
    the latest revision.  If you specify a revision, that revision will be
2660
 
    merged.  If you specify two revisions, the first will be used as a BASE,
2661
 
    and the second one as OTHER.  Revision numbers are always relative to the
2662
 
    specified branch.
 
1159
    The branch is the branch you will merge from.  By default, it will
 
1160
    merge the latest revision.  If you specify a revision, that
 
1161
    revision will be merged.  If you specify two revisions, the first
 
1162
    will be used as a BASE, and the second one as OTHER.  Revision
 
1163
    numbers are always relative to the specified branch.
2663
1164
 
2664
 
    By default, bzr will try to merge in all new work from the other
 
1165
    By default bzr will try to merge in all new work from the other
2665
1166
    branch, automatically determining an appropriate base.  If this
2666
1167
    fails, you may need to give an explicit base.
2667
1168
    
2668
 
    Merge will do its best to combine the changes in two branches, but there
2669
 
    are some kinds of problems only a human can fix.  When it encounters those,
2670
 
    it will mark a conflict.  A conflict means that you need to fix something,
2671
 
    before you should commit.
2672
 
 
2673
 
    Use bzr resolve when you have fixed a problem.  See also bzr conflicts.
2674
 
 
2675
 
    If there is no default branch set, the first merge will set it. After
2676
 
    that, you can omit the branch to use the default.  To change the
2677
 
    default, use --remember. The value will only be saved if the remote
2678
 
    location can be accessed.
2679
 
 
2680
 
    The results of the merge are placed into the destination working
2681
 
    directory, where they can be reviewed (with bzr diff), tested, and then
2682
 
    committed to record the result of the merge.
 
1169
    Examples:
 
1170
 
 
1171
    To merge the latest revision from bzr.dev
 
1172
    bzr merge ../bzr.dev
 
1173
 
 
1174
    To merge changes up to and including revision 82 from bzr.dev
 
1175
    bzr merge -r 82 ../bzr.dev
 
1176
 
 
1177
    To merge the changes introduced by 82, without previous changes:
 
1178
    bzr merge -r 81..82 ../bzr.dev
2683
1179
    
2684
1180
    merge refuses to run if there are any uncommitted changes, unless
2685
1181
    --force is given.
2686
 
 
2687
 
    :Examples:
2688
 
        To merge the latest revision from bzr.dev::
2689
 
 
2690
 
            bzr merge ../bzr.dev
2691
 
 
2692
 
        To merge changes up to and including revision 82 from bzr.dev::
2693
 
 
2694
 
            bzr merge -r 82 ../bzr.dev
2695
 
 
2696
 
        To merge the changes introduced by 82, without previous changes::
2697
 
 
2698
 
            bzr merge -r 81..82 ../bzr.dev
2699
1182
    """
2700
 
 
2701
 
    _see_also = ['update', 'remerge', 'status-flags']
2702
1183
    takes_args = ['branch?']
2703
 
    takes_options = [
2704
 
        'revision',
2705
 
        Option('force',
2706
 
               help='Merge even if the destination tree has uncommitted changes.'),
2707
 
        'merge-type',
2708
 
        'reprocess',
2709
 
        'remember',
2710
 
        Option('show-base', help="Show base revision text in "
2711
 
               "conflicts."),
2712
 
        Option('uncommitted', help='Apply uncommitted changes'
2713
 
               ' from a working copy, instead of branch changes.'),
2714
 
        Option('pull', help='If the destination is already'
2715
 
                ' completely merged into the source, pull from the'
2716
 
                ' source rather than merging.  When this happens,'
2717
 
                ' you do not need to commit the result.'),
2718
 
        Option('directory',
2719
 
               help='Branch to merge into, '
2720
 
                    'rather than the one containing the working directory.',
2721
 
               short_name='d',
2722
 
               type=unicode,
2723
 
               ),
2724
 
    ]
2725
 
 
2726
 
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2727
 
            show_base=False, reprocess=False, remember=False,
2728
 
            uncommitted=False, pull=False,
2729
 
            directory=None,
2730
 
            ):
2731
 
        from bzrlib.tag import _merge_tags_if_possible
2732
 
        # This is actually a branch (or merge-directive) *location*.
2733
 
        location = branch
2734
 
        del branch
2735
 
 
2736
 
        if merge_type is None:
2737
 
            merge_type = _mod_merge.Merge3Merger
2738
 
 
2739
 
        if directory is None: directory = u'.'
2740
 
        possible_transports = []
2741
 
        merger = None
2742
 
        allow_pending = True
2743
 
        verified = 'inapplicable'
2744
 
        tree = WorkingTree.open_containing(directory)[0]
2745
 
        change_reporter = delta._ChangeReporter(
2746
 
            unversioned_filter=tree.is_ignored)
2747
 
        cleanups = []
2748
 
        try:
2749
 
            pb = ui.ui_factory.nested_progress_bar()
2750
 
            cleanups.append(pb.finished)
2751
 
            tree.lock_write()
2752
 
            cleanups.append(tree.unlock)
2753
 
            if location is not None:
2754
 
                mergeable, other_transport = _get_mergeable_helper(location)
2755
 
                if mergeable:
2756
 
                    if uncommitted:
2757
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
2758
 
                            ' with bundles or merge directives.')
2759
 
 
2760
 
                    if revision is not None:
2761
 
                        raise errors.BzrCommandError(
2762
 
                            'Cannot use -r with merge directives or bundles')
2763
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
2764
 
                       mergeable, pb)
2765
 
                possible_transports.append(other_transport)
2766
 
 
2767
 
            if merger is None and uncommitted:
2768
 
                if revision is not None and len(revision) > 0:
2769
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
2770
 
                        ' --revision at the same time.')
2771
 
                location = self._select_branch_location(tree, location)[0]
2772
 
                other_tree, other_path = WorkingTree.open_containing(location)
2773
 
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
2774
 
                    pb)
2775
 
                allow_pending = False
2776
 
 
2777
 
            if merger is None:
2778
 
                merger, allow_pending = self._get_merger_from_branch(tree,
2779
 
                    location, revision, remember, possible_transports, pb)
2780
 
 
2781
 
            merger.merge_type = merge_type
2782
 
            merger.reprocess = reprocess
2783
 
            merger.show_base = show_base
2784
 
            merger.change_reporter = change_reporter
2785
 
            self.sanity_check_merger(merger)
2786
 
            if (merger.base_rev_id == merger.other_rev_id and
2787
 
                merger.other_rev_id != None):
2788
 
                note('Nothing to do.')
2789
 
                return 0
2790
 
            if pull:
2791
 
                if merger.interesting_files is not None:
2792
 
                    raise BzrCommandError('Cannot pull individual files')
2793
 
                if (merger.base_rev_id == tree.last_revision()):
2794
 
                    result = tree.pull(merger.other_branch, False,
2795
 
                                       merger.other_rev_id)
2796
 
                    result.report(self.outf)
2797
 
                    return 0
2798
 
            merger.check_basis(not force)
2799
 
            conflict_count = merger.do_merge()
2800
 
            if allow_pending:
2801
 
                merger.set_pending()
2802
 
            if verified == 'failed':
2803
 
                warning('Preview patch does not match changes')
2804
 
            if conflict_count != 0:
2805
 
                return 1
2806
 
            else:
2807
 
                return 0
2808
 
        finally:
2809
 
            for cleanup in reversed(cleanups):
2810
 
                cleanup()
2811
 
 
2812
 
    def sanity_check_merger(self, merger):
2813
 
        if (merger.show_base and
2814
 
            not merger.merge_type is _mod_merge.Merge3Merger):
2815
 
            raise errors.BzrCommandError("Show-base is not supported for this"
2816
 
                                         " merge type. %s" % merger.merge_type)
2817
 
        if merger.reprocess and not merger.merge_type.supports_reprocess:
2818
 
            raise errors.BzrCommandError("Conflict reduction is not supported"
2819
 
                                         " for merge type %s." %
2820
 
                                         merger.merge_type)
2821
 
        if merger.reprocess and merger.show_base:
2822
 
            raise errors.BzrCommandError("Cannot do conflict reduction and"
2823
 
                                         " show base.")
2824
 
 
2825
 
    def _get_merger_from_branch(self, tree, location, revision, remember,
2826
 
                                possible_transports, pb):
2827
 
        """Produce a merger from a location, assuming it refers to a branch."""
2828
 
        from bzrlib.tag import _merge_tags_if_possible
2829
 
        assert revision is None or len(revision) < 3
2830
 
        # find the branch locations
2831
 
        other_loc, location = self._select_branch_location(tree, location,
2832
 
            revision, -1)
2833
 
        if revision is not None and len(revision) == 2:
2834
 
            base_loc, location = self._select_branch_location(tree, location,
2835
 
                                                              revision, 0)
2836
 
        else:
2837
 
            base_loc = other_loc
2838
 
        # Open the branches
2839
 
        other_branch, other_path = Branch.open_containing(other_loc,
2840
 
            possible_transports)
2841
 
        if base_loc == other_loc:
2842
 
            base_branch = other_branch
2843
 
        else:
2844
 
            base_branch, base_path = Branch.open_containing(base_loc,
2845
 
                possible_transports)
2846
 
        # Find the revision ids
2847
 
        if revision is None or len(revision) < 1 or revision[-1] is None:
2848
 
            other_revision_id = _mod_revision.ensure_null(
2849
 
                other_branch.last_revision())
2850
 
        else:
2851
 
            other_revision_id = \
2852
 
                _mod_revision.ensure_null(
2853
 
                    revision[-1].in_history(other_branch).rev_id)
2854
 
        if (revision is not None and len(revision) == 2
2855
 
            and revision[0] is not None):
2856
 
            base_revision_id = \
2857
 
                _mod_revision.ensure_null(
2858
 
                    revision[0].in_history(base_branch).rev_id)
2859
 
        else:
2860
 
            base_revision_id = None
2861
 
        # Remember where we merge from
2862
 
        if ((tree.branch.get_parent() is None or remember) and
2863
 
            other_branch is not None):
2864
 
            tree.branch.set_parent(other_branch.base)
2865
 
        _merge_tags_if_possible(other_branch, tree.branch)
2866
 
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
2867
 
            other_revision_id, base_revision_id, other_branch, base_branch)
2868
 
        if other_path != '':
2869
 
            allow_pending = False
2870
 
            merger.interesting_files = [other_path]
2871
 
        else:
2872
 
            allow_pending = True
2873
 
        return merger, allow_pending
2874
 
 
2875
 
    def _select_branch_location(self, tree, location, revision=None,
2876
 
                                index=None):
2877
 
        """Select a branch location, according to possible inputs.
2878
 
 
2879
 
        If provided, branches from ``revision`` are preferred.  (Both
2880
 
        ``revision`` and ``index`` must be supplied.)
2881
 
 
2882
 
        Otherwise, the ``location`` parameter is used.  If it is None, then the
2883
 
        ``parent`` location is used, and a note is printed.
2884
 
 
2885
 
        :param tree: The working tree to select a branch for merging into
2886
 
        :param location: The location entered by the user
2887
 
        :param revision: The revision parameter to the command
2888
 
        :param index: The index to use for the revision parameter.  Negative
2889
 
            indices are permitted.
2890
 
        :return: (selected_location, default_location).  The default location
2891
 
            will be the user-entered location, if any, or else the remembered
2892
 
            location.
2893
 
        """
2894
 
        if (revision is not None and index is not None
2895
 
            and revision[index] is not None):
2896
 
            branch = revision[index].get_branch()
2897
 
            if branch is not None:
2898
 
                return branch, location
2899
 
        location = self._get_remembered_parent(tree, location, 'Merging from')
2900
 
        return location, location
2901
 
 
2902
 
    # TODO: move up to common parent; this isn't merge-specific anymore. 
2903
 
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
2904
 
        """Use tree.branch's parent if none was supplied.
2905
 
 
2906
 
        Report if the remembered location was used.
2907
 
        """
2908
 
        if supplied_location is not None:
2909
 
            return supplied_location
2910
 
        stored_location = tree.branch.get_parent()
2911
 
        mutter("%s", stored_location)
2912
 
        if stored_location is None:
2913
 
            raise errors.BzrCommandError("No location specified or remembered")
2914
 
        display_url = urlutils.unescape_for_display(stored_location,
2915
 
            self.outf.encoding)
2916
 
        self.outf.write("%s remembered location %s\n" % (verb_string,
2917
 
            display_url))
2918
 
        return stored_location
2919
 
 
2920
 
 
2921
 
class cmd_remerge(Command):
2922
 
    """Redo a merge.
2923
 
 
2924
 
    Use this if you want to try a different merge technique while resolving
2925
 
    conflicts.  Some merge techniques are better than others, and remerge 
2926
 
    lets you try different ones on different files.
2927
 
 
2928
 
    The options for remerge have the same meaning and defaults as the ones for
2929
 
    merge.  The difference is that remerge can (only) be run when there is a
2930
 
    pending merge, and it lets you specify particular files.
2931
 
 
2932
 
    :Examples:
2933
 
        Re-do the merge of all conflicted files, and show the base text in
2934
 
        conflict regions, in addition to the usual THIS and OTHER texts::
2935
 
      
2936
 
            bzr remerge --show-base
2937
 
 
2938
 
        Re-do the merge of "foobar", using the weave merge algorithm, with
2939
 
        additional processing to reduce the size of conflict regions::
2940
 
      
2941
 
            bzr remerge --merge-type weave --reprocess foobar
2942
 
    """
2943
 
    takes_args = ['file*']
2944
 
    takes_options = [
2945
 
            'merge-type',
2946
 
            'reprocess',
2947
 
            Option('show-base',
2948
 
                   help="Show base revision text in conflicts."),
2949
 
            ]
2950
 
 
2951
 
    def run(self, file_list=None, merge_type=None, show_base=False,
2952
 
            reprocess=False):
2953
 
        if merge_type is None:
2954
 
            merge_type = _mod_merge.Merge3Merger
2955
 
        tree, file_list = tree_files(file_list)
2956
 
        tree.lock_write()
2957
 
        try:
2958
 
            parents = tree.get_parent_ids()
2959
 
            if len(parents) != 2:
2960
 
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
2961
 
                                             " merges.  Not cherrypicking or"
2962
 
                                             " multi-merges.")
2963
 
            repository = tree.branch.repository
2964
 
            graph = repository.get_graph()
2965
 
            base_revision = graph.find_unique_lca(parents[0], parents[1])
2966
 
            base_tree = repository.revision_tree(base_revision)
2967
 
            other_tree = repository.revision_tree(parents[1])
2968
 
            interesting_ids = None
2969
 
            new_conflicts = []
2970
 
            conflicts = tree.conflicts()
2971
 
            if file_list is not None:
2972
 
                interesting_ids = set()
2973
 
                for filename in file_list:
2974
 
                    file_id = tree.path2id(filename)
2975
 
                    if file_id is None:
2976
 
                        raise errors.NotVersionedError(filename)
2977
 
                    interesting_ids.add(file_id)
2978
 
                    if tree.kind(file_id) != "directory":
2979
 
                        continue
2980
 
                    
2981
 
                    for name, ie in tree.inventory.iter_entries(file_id):
2982
 
                        interesting_ids.add(ie.file_id)
2983
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2984
 
            else:
2985
 
                # Remerge only supports resolving contents conflicts
2986
 
                allowed_conflicts = ('text conflict', 'contents conflict')
2987
 
                restore_files = [c.path for c in conflicts
2988
 
                                 if c.typestring in allowed_conflicts]
2989
 
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
2990
 
            tree.set_conflicts(ConflictList(new_conflicts))
2991
 
            if file_list is not None:
2992
 
                restore_files = file_list
2993
 
            for filename in restore_files:
2994
 
                try:
2995
 
                    restore(tree.abspath(filename))
2996
 
                except errors.NotConflicted:
2997
 
                    pass
2998
 
            # Disable pending merges, because the file texts we are remerging
2999
 
            # have not had those merges performed.  If we use the wrong parents
3000
 
            # list, we imply that the working tree text has seen and rejected
3001
 
            # all the changes from the other tree, when in fact those changes
3002
 
            # have not yet been seen.
3003
 
            tree.set_parent_ids(parents[:1])
3004
 
            try:
3005
 
                conflicts = _mod_merge.merge_inner(
3006
 
                                          tree.branch, other_tree, base_tree,
3007
 
                                          this_tree=tree,
3008
 
                                          interesting_ids=interesting_ids,
3009
 
                                          other_rev_id=parents[1],
3010
 
                                          merge_type=merge_type,
3011
 
                                          show_base=show_base,
3012
 
                                          reprocess=reprocess)
3013
 
            finally:
3014
 
                tree.set_parent_ids(parents)
3015
 
        finally:
3016
 
            tree.unlock()
3017
 
        if conflicts > 0:
3018
 
            return 1
3019
 
        else:
3020
 
            return 0
 
1184
    takes_options = ['revision', 'force', 'merge-type']
 
1185
 
 
1186
    def run(self, branch='.', revision=None, force=False, 
 
1187
            merge_type=None):
 
1188
        from bzrlib.merge import merge
 
1189
        from bzrlib.merge_core import ApplyMerge3
 
1190
        if merge_type is None:
 
1191
            merge_type = ApplyMerge3
 
1192
 
 
1193
        if revision is None or len(revision) < 1:
 
1194
            base = [None, None]
 
1195
            other = [branch, -1]
 
1196
        else:
 
1197
            if len(revision) == 1:
 
1198
                other = [branch, revision[0]]
 
1199
                base = [None, None]
 
1200
            else:
 
1201
                assert len(revision) == 2
 
1202
                if None in revision:
 
1203
                    raise BzrCommandError(
 
1204
                        "Merge doesn't permit that revision specifier.")
 
1205
                base = [branch, revision[0]]
 
1206
                other = [branch, revision[1]]
 
1207
 
 
1208
        try:
 
1209
            merge(other, base, check_clean=(not force), merge_type=merge_type)
 
1210
        except bzrlib.errors.AmbiguousBase, e:
 
1211
            m = ("sorry, bzr can't determine the right merge base yet\n"
 
1212
                 "candidates are:\n  "
 
1213
                 + "\n  ".join(e.bases)
 
1214
                 + "\n"
 
1215
                 "please specify an explicit base with -r,\n"
 
1216
                 "and (if you want) report this to the bzr developers\n")
 
1217
            log_error(m)
3021
1218
 
3022
1219
 
3023
1220
class cmd_revert(Command):
3024
 
    """Revert files to a previous revision.
3025
 
 
3026
 
    Giving a list of files will revert only those files.  Otherwise, all files
3027
 
    will be reverted.  If the revision is not specified with '--revision', the
3028
 
    last committed revision is used.
3029
 
 
3030
 
    To remove only some changes, without reverting to a prior version, use
3031
 
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
3032
 
    introduced by -2, without affecting the changes introduced by -1.  Or
3033
 
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
3034
 
    
3035
 
    By default, any files that have been manually changed will be backed up
3036
 
    first.  (Files changed only by merge are not backed up.)  Backup files have
3037
 
    '.~#~' appended to their name, where # is a number.
3038
 
 
3039
 
    When you provide files, you can use their current pathname or the pathname
3040
 
    from the target revision.  So you can use revert to "undelete" a file by
3041
 
    name.  If you name a directory, all the contents of that directory will be
3042
 
    reverted.
3043
 
 
3044
 
    Any files that have been newly added since that revision will be deleted,
3045
 
    with a backup kept if appropriate.  Directories containing unknown files
3046
 
    will not be deleted.
 
1221
    """Reverse all changes since the last commit.
 
1222
 
 
1223
    Only versioned files are affected.  Specify filenames to revert only 
 
1224
    those files.  By default, any files that are changed will be backed up
 
1225
    first.  Backup files have a '~' appended to their name.
3047
1226
    """
3048
 
 
3049
 
    _see_also = ['cat', 'export']
3050
 
    takes_options = [
3051
 
            'revision',
3052
 
            Option('no-backup', "Do not save backups of reverted files."),
3053
 
            ]
 
1227
    takes_options = ['revision', 'no-backup']
3054
1228
    takes_args = ['file*']
 
1229
    aliases = ['merge-revert']
3055
1230
 
3056
1231
    def run(self, revision=None, no_backup=False, file_list=None):
 
1232
        from bzrlib.merge import merge
 
1233
        from bzrlib.branch import Branch
 
1234
        from bzrlib.commands import parse_spec
 
1235
 
3057
1236
        if file_list is not None:
3058
1237
            if len(file_list) == 0:
3059
 
                raise errors.BzrCommandError("No files specified")
3060
 
        
3061
 
        tree, file_list = tree_files(file_list)
 
1238
                raise BzrCommandError("No files specified")
3062
1239
        if revision is None:
3063
 
            # FIXME should be tree.last_revision
3064
 
            rev_id = tree.last_revision()
 
1240
            revision = [-1]
3065
1241
        elif len(revision) != 1:
3066
 
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3067
 
        else:
3068
 
            rev_id = revision[0].in_history(tree.branch).rev_id
3069
 
        pb = ui.ui_factory.nested_progress_bar()
3070
 
        try:
3071
 
            tree.revert(file_list, 
3072
 
                        tree.branch.repository.revision_tree(rev_id),
3073
 
                        not no_backup, pb, report_changes=True)
3074
 
        finally:
3075
 
            pb.finished()
 
1242
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
 
1243
        merge(('.', revision[0]), parse_spec('.'),
 
1244
              check_clean=False,
 
1245
              ignore_zero=True,
 
1246
              backup_files=not no_backup,
 
1247
              file_list=file_list)
 
1248
        if not file_list:
 
1249
            Branch('.').set_pending_merges([])
3076
1250
 
3077
1251
 
3078
1252
class cmd_assert_fail(Command):
3079
1253
    """Test reporting of assertion failures"""
3080
 
    # intended just for use in testing
3081
 
 
3082
1254
    hidden = True
3083
 
 
3084
1255
    def run(self):
3085
 
        raise AssertionError("always fails")
 
1256
        assert False, "always fails"
3086
1257
 
3087
1258
 
3088
1259
class cmd_help(Command):
3089
1260
    """Show help on a command or other topic.
3090
 
    """
3091
1261
 
3092
 
    _see_also = ['topics']
3093
 
    takes_options = [
3094
 
            Option('long', 'Show help on all commands.'),
3095
 
            ]
 
1262
    For a list of all available commands, say 'bzr help commands'."""
 
1263
    takes_options = ['long']
3096
1264
    takes_args = ['topic?']
3097
 
    aliases = ['?', '--help', '-?', '-h']
 
1265
    aliases = ['?']
3098
1266
    
3099
 
    @display_command
3100
1267
    def run(self, topic=None, long=False):
3101
 
        import bzrlib.help
 
1268
        import help
3102
1269
        if topic is None and long:
3103
1270
            topic = "commands"
3104
 
        bzrlib.help.help(topic)
 
1271
        help.help(topic)
3105
1272
 
3106
1273
 
3107
1274
class cmd_shell_complete(Command):
3108
1275
    """Show appropriate completions for context.
3109
1276
 
3110
 
    For a list of all available commands, say 'bzr shell-complete'.
3111
 
    """
 
1277
    For a list of all available commands, say 'bzr shell-complete'."""
3112
1278
    takes_args = ['context?']
3113
1279
    aliases = ['s-c']
3114
1280
    hidden = True
3115
1281
    
3116
 
    @display_command
3117
1282
    def run(self, context=None):
3118
1283
        import shellcomplete
3119
1284
        shellcomplete.shellcomplete(context)
3122
1287
class cmd_fetch(Command):
3123
1288
    """Copy in history from another branch but don't merge it.
3124
1289
 
3125
 
    This is an internal method used for pull and merge.
3126
 
    """
 
1290
    This is an internal method used for pull and merge."""
3127
1291
    hidden = True
3128
1292
    takes_args = ['from_branch', 'to_branch']
3129
1293
    def run(self, from_branch, to_branch):
3130
1294
        from bzrlib.fetch import Fetcher
3131
 
        from_b = Branch.open(from_branch)
3132
 
        to_b = Branch.open(to_branch)
 
1295
        from bzrlib.branch import Branch
 
1296
        from_b = Branch(from_branch)
 
1297
        to_b = Branch(to_branch)
3133
1298
        Fetcher(to_b, from_b)
 
1299
        
3134
1300
 
3135
1301
 
3136
1302
class cmd_missing(Command):
3137
 
    """Show unmerged/unpulled revisions between two branches.
 
1303
    """What is missing in this branch relative to other branch.
 
1304
    """
 
1305
    # TODO: rewrite this in terms of ancestry so that it shows only
 
1306
    # unmerged things
3138
1307
    
3139
 
    OTHER_BRANCH may be local or remote.
3140
 
    """
3141
 
 
3142
 
    _see_also = ['merge', 'pull']
3143
 
    takes_args = ['other_branch?']
3144
 
    takes_options = [
3145
 
            Option('reverse', 'Reverse the order of revisions.'),
3146
 
            Option('mine-only',
3147
 
                   'Display changes in the local branch only.'),
3148
 
            Option('this' , 'Same as --mine-only.'),
3149
 
            Option('theirs-only',
3150
 
                   'Display changes in the remote branch only.'),
3151
 
            Option('other', 'Same as --theirs-only.'),
3152
 
            'log-format',
3153
 
            'show-ids',
3154
 
            'verbose'
3155
 
            ]
3156
 
    encoding_type = 'replace'
3157
 
 
3158
 
    @display_command
3159
 
    def run(self, other_branch=None, reverse=False, mine_only=False,
3160
 
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
3161
 
            show_ids=False, verbose=False, this=False, other=False):
3162
 
        from bzrlib.missing import find_unmerged, iter_log_revisions
3163
 
        from bzrlib.log import log_formatter
3164
 
 
3165
 
        if this:
3166
 
          mine_only = this
3167
 
        if other:
3168
 
          theirs_only = other
3169
 
 
3170
 
        local_branch = Branch.open_containing(u".")[0]
3171
 
        parent = local_branch.get_parent()
3172
 
        if other_branch is None:
3173
 
            other_branch = parent
3174
 
            if other_branch is None:
3175
 
                raise errors.BzrCommandError("No peer location known"
3176
 
                                             " or specified.")
3177
 
            display_url = urlutils.unescape_for_display(parent,
3178
 
                                                        self.outf.encoding)
3179
 
            self.outf.write("Using last location: " + display_url + "\n")
3180
 
 
3181
 
        remote_branch = Branch.open(other_branch)
3182
 
        if remote_branch.base == local_branch.base:
3183
 
            remote_branch = local_branch
3184
 
        local_branch.lock_read()
3185
 
        try:
3186
 
            remote_branch.lock_read()
3187
 
            try:
3188
 
                local_extra, remote_extra = find_unmerged(local_branch,
3189
 
                                                          remote_branch)
3190
 
                if log_format is None:
3191
 
                    registry = log.log_formatter_registry
3192
 
                    log_format = registry.get_default(local_branch)
3193
 
                lf = log_format(to_file=self.outf,
3194
 
                                show_ids=show_ids,
3195
 
                                show_timezone='original')
3196
 
                if reverse is False:
3197
 
                    local_extra.reverse()
3198
 
                    remote_extra.reverse()
3199
 
                if local_extra and not theirs_only:
3200
 
                    self.outf.write("You have %d extra revision(s):\n" %
3201
 
                                    len(local_extra))
3202
 
                    for revision in iter_log_revisions(local_extra,
3203
 
                                        local_branch.repository,
3204
 
                                        verbose):
3205
 
                        lf.log_revision(revision)
3206
 
                    printed_local = True
3207
 
                else:
3208
 
                    printed_local = False
3209
 
                if remote_extra and not mine_only:
3210
 
                    if printed_local is True:
3211
 
                        self.outf.write("\n\n\n")
3212
 
                    self.outf.write("You are missing %d revision(s):\n" %
3213
 
                                    len(remote_extra))
3214
 
                    for revision in iter_log_revisions(remote_extra,
3215
 
                                        remote_branch.repository,
3216
 
                                        verbose):
3217
 
                        lf.log_revision(revision)
3218
 
                if not remote_extra and not local_extra:
3219
 
                    status_code = 0
3220
 
                    self.outf.write("Branches are up to date.\n")
3221
 
                else:
3222
 
                    status_code = 1
3223
 
            finally:
3224
 
                remote_branch.unlock()
3225
 
        finally:
3226
 
            local_branch.unlock()
3227
 
        if not status_code and parent is None and other_branch is not None:
3228
 
            local_branch.lock_write()
3229
 
            try:
3230
 
                # handle race conditions - a parent might be set while we run.
3231
 
                if local_branch.get_parent() is None:
3232
 
                    local_branch.set_parent(remote_branch.base)
3233
 
            finally:
3234
 
                local_branch.unlock()
3235
 
        return status_code
3236
 
 
3237
 
 
3238
 
class cmd_pack(Command):
3239
 
    """Compress the data within a repository."""
3240
 
 
3241
 
    _see_also = ['repositories']
3242
 
    takes_args = ['branch_or_repo?']
3243
 
 
3244
 
    def run(self, branch_or_repo='.'):
3245
 
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
3246
 
        try:
3247
 
            branch = dir.open_branch()
3248
 
            repository = branch.repository
3249
 
        except errors.NotBranchError:
3250
 
            repository = dir.open_repository()
3251
 
        repository.pack()
 
1308
    takes_args = ['remote?']
 
1309
    aliases = ['mis', 'miss']
 
1310
    # We don't have to add quiet to the list, because 
 
1311
    # unknown options are parsed as booleans
 
1312
    takes_options = ['verbose', 'quiet']
 
1313
 
 
1314
    def run(self, remote=None, verbose=False, quiet=False):
 
1315
        from bzrlib.errors import BzrCommandError
 
1316
        from bzrlib.missing import show_missing
 
1317
 
 
1318
        if verbose and quiet:
 
1319
            raise BzrCommandError('Cannot pass both quiet and verbose')
 
1320
 
 
1321
        b = find_branch('.')
 
1322
        parent = b.get_parent()
 
1323
        if remote is None:
 
1324
            if parent is None:
 
1325
                raise BzrCommandError("No missing location known or specified.")
 
1326
            else:
 
1327
                if not quiet:
 
1328
                    print "Using last location: %s" % parent
 
1329
                remote = parent
 
1330
        elif parent is None:
 
1331
            # We only update x-pull if it did not exist, missing should not change the parent
 
1332
            b.controlfile('x-pull', 'wb').write(remote + '\n')
 
1333
        br_remote = find_branch(remote)
 
1334
 
 
1335
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
 
1336
 
3252
1337
 
3253
1338
 
3254
1339
class cmd_plugins(Command):
3255
 
    """List the installed plugins.
3256
 
    
3257
 
    This command displays the list of installed plugins including the
3258
 
    path where each one is located and a short description of each.
3259
 
 
3260
 
    A plugin is an external component for Bazaar that extends the
3261
 
    revision control system, by adding or replacing code in Bazaar.
3262
 
    Plugins can do a variety of things, including overriding commands,
3263
 
    adding new commands, providing additional network transports and
3264
 
    customizing log output.
3265
 
 
3266
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
3267
 
    information on plugins including where to find them and how to
3268
 
    install them. Instructions are also provided there on how to
3269
 
    write new plugins using the Python programming language.
3270
 
    """
3271
 
 
3272
 
    @display_command
 
1340
    """List plugins"""
 
1341
    hidden = True
3273
1342
    def run(self):
3274
1343
        import bzrlib.plugin
3275
1344
        from inspect import getdoc
3276
 
        for name, plugin in bzrlib.plugin.plugins().items():
3277
 
            print plugin.path(), "[%s]" % plugin.__version__
3278
 
            d = getdoc(plugin.module)
 
1345
        for plugin in bzrlib.plugin.all_plugins:
 
1346
            if hasattr(plugin, '__path__'):
 
1347
                print plugin.__path__[0]
 
1348
            elif hasattr(plugin, '__file__'):
 
1349
                print plugin.__file__
 
1350
            else:
 
1351
                print `plugin`
 
1352
                
 
1353
            d = getdoc(plugin)
3279
1354
            if d:
3280
1355
                print '\t', d.split('\n')[0]
3281
1356
 
3282
1357
 
3283
 
class cmd_testament(Command):
3284
 
    """Show testament (signing-form) of a revision."""
3285
 
    takes_options = [
3286
 
            'revision',
3287
 
            Option('long', help='Produce long-format testament.'),
3288
 
            Option('strict',
3289
 
                   help='Produce a strict-format testament.')]
3290
 
    takes_args = ['branch?']
3291
 
    @display_command
3292
 
    def run(self, branch=u'.', revision=None, long=False, strict=False):
3293
 
        from bzrlib.testament import Testament, StrictTestament
3294
 
        if strict is True:
3295
 
            testament_class = StrictTestament
3296
 
        else:
3297
 
            testament_class = Testament
3298
 
        b = WorkingTree.open_containing(branch)[0].branch
3299
 
        b.lock_read()
3300
 
        try:
3301
 
            if revision is None:
3302
 
                rev_id = b.last_revision()
3303
 
            else:
3304
 
                rev_id = revision[0].in_history(b).rev_id
3305
 
            t = testament_class.from_revision(b.repository, rev_id)
3306
 
            if long:
3307
 
                sys.stdout.writelines(t.as_text_lines())
3308
 
            else:
3309
 
                sys.stdout.write(t.as_short_text())
3310
 
        finally:
3311
 
            b.unlock()
3312
 
 
3313
 
 
3314
 
class cmd_annotate(Command):
3315
 
    """Show the origin of each line in a file.
3316
 
 
3317
 
    This prints out the given file with an annotation on the left side
3318
 
    indicating which revision, author and date introduced the change.
3319
 
 
3320
 
    If the origin is the same for a run of consecutive lines, it is 
3321
 
    shown only at the top, unless the --all option is given.
3322
 
    """
3323
 
    # TODO: annotate directories; showing when each file was last changed
3324
 
    # TODO: if the working copy is modified, show annotations on that 
3325
 
    #       with new uncommitted lines marked
3326
 
    aliases = ['ann', 'blame', 'praise']
3327
 
    takes_args = ['filename']
3328
 
    takes_options = [Option('all', help='Show annotations on all lines.'),
3329
 
                     Option('long', help='Show commit date in annotations.'),
3330
 
                     'revision',
3331
 
                     'show-ids',
3332
 
                     ]
3333
 
    encoding_type = 'exact'
3334
 
 
3335
 
    @display_command
3336
 
    def run(self, filename, all=False, long=False, revision=None,
3337
 
            show_ids=False):
3338
 
        from bzrlib.annotate import annotate_file
3339
 
        tree, relpath = WorkingTree.open_containing(filename)
3340
 
        branch = tree.branch
3341
 
        branch.lock_read()
3342
 
        try:
3343
 
            if revision is None:
3344
 
                revision_id = branch.last_revision()
3345
 
            elif len(revision) != 1:
3346
 
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3347
 
            else:
3348
 
                revision_id = revision[0].in_history(branch).rev_id
3349
 
            file_id = tree.path2id(relpath)
3350
 
            if file_id is None:
3351
 
                raise errors.NotVersionedError(filename)
3352
 
            tree = branch.repository.revision_tree(revision_id)
3353
 
            file_version = tree.inventory[file_id].revision
3354
 
            annotate_file(branch, file_version, file_id, long, all, self.outf,
3355
 
                          show_ids=show_ids)
3356
 
        finally:
3357
 
            branch.unlock()
3358
 
 
3359
 
 
3360
 
class cmd_re_sign(Command):
3361
 
    """Create a digital signature for an existing revision."""
3362
 
    # TODO be able to replace existing ones.
3363
 
 
3364
 
    hidden = True # is this right ?
3365
 
    takes_args = ['revision_id*']
3366
 
    takes_options = ['revision']
3367
 
    
3368
 
    def run(self, revision_id_list=None, revision=None):
3369
 
        import bzrlib.gpg as gpg
3370
 
        if revision_id_list is not None and revision is not None:
3371
 
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3372
 
        if revision_id_list is None and revision is None:
3373
 
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3374
 
        b = WorkingTree.open_containing(u'.')[0].branch
3375
 
        gpg_strategy = gpg.GPGStrategy(b.get_config())
3376
 
        if revision_id_list is not None:
3377
 
            for revision_id in revision_id_list:
3378
 
                b.repository.sign_revision(revision_id, gpg_strategy)
3379
 
        elif revision is not None:
3380
 
            if len(revision) == 1:
3381
 
                revno, rev_id = revision[0].in_history(b)
3382
 
                b.repository.sign_revision(rev_id, gpg_strategy)
3383
 
            elif len(revision) == 2:
3384
 
                # are they both on rh- if so we can walk between them
3385
 
                # might be nice to have a range helper for arbitrary
3386
 
                # revision paths. hmm.
3387
 
                from_revno, from_revid = revision[0].in_history(b)
3388
 
                to_revno, to_revid = revision[1].in_history(b)
3389
 
                if to_revid is None:
3390
 
                    to_revno = b.revno()
3391
 
                if from_revno is None or to_revno is None:
3392
 
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
3393
 
                for revno in range(from_revno, to_revno + 1):
3394
 
                    b.repository.sign_revision(b.get_rev_id(revno), 
3395
 
                                               gpg_strategy)
3396
 
            else:
3397
 
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
3398
 
 
3399
 
 
3400
 
class cmd_bind(Command):
3401
 
    """Convert the current branch into a checkout of the supplied branch.
3402
 
 
3403
 
    Once converted into a checkout, commits must succeed on the master branch
3404
 
    before they will be applied to the local branch.
3405
 
    """
3406
 
 
3407
 
    _see_also = ['checkouts', 'unbind']
3408
 
    takes_args = ['location?']
3409
 
    takes_options = []
3410
 
 
3411
 
    def run(self, location=None):
3412
 
        b, relpath = Branch.open_containing(u'.')
3413
 
        if location is None:
3414
 
            try:
3415
 
                location = b.get_old_bound_location()
3416
 
            except errors.UpgradeRequired:
3417
 
                raise errors.BzrCommandError('No location supplied.  '
3418
 
                    'This format does not remember old locations.')
3419
 
            else:
3420
 
                if location is None:
3421
 
                    raise errors.BzrCommandError('No location supplied and no '
3422
 
                        'previous location known')
3423
 
        b_other = Branch.open(location)
3424
 
        try:
3425
 
            b.bind(b_other)
3426
 
        except errors.DivergedBranches:
3427
 
            raise errors.BzrCommandError('These branches have diverged.'
3428
 
                                         ' Try merging, and then bind again.')
3429
 
 
3430
 
 
3431
 
class cmd_unbind(Command):
3432
 
    """Convert the current checkout into a regular branch.
3433
 
 
3434
 
    After unbinding, the local branch is considered independent and subsequent
3435
 
    commits will be local only.
3436
 
    """
3437
 
 
3438
 
    _see_also = ['checkouts', 'bind']
3439
 
    takes_args = []
3440
 
    takes_options = []
3441
 
 
3442
 
    def run(self):
3443
 
        b, relpath = Branch.open_containing(u'.')
3444
 
        if not b.unbind():
3445
 
            raise errors.BzrCommandError('Local branch is not bound')
3446
 
 
3447
 
 
3448
 
class cmd_uncommit(Command):
3449
 
    """Remove the last committed revision.
3450
 
 
3451
 
    --verbose will print out what is being removed.
3452
 
    --dry-run will go through all the motions, but not actually
3453
 
    remove anything.
3454
 
 
3455
 
    If --revision is specified, uncommit revisions to leave the branch at the
3456
 
    specified revision.  For example, "bzr uncommit -r 15" will leave the
3457
 
    branch at revision 15.
3458
 
 
3459
 
    In the future, uncommit will create a revision bundle, which can then
3460
 
    be re-applied.
3461
 
    """
3462
 
 
3463
 
    # TODO: jam 20060108 Add an option to allow uncommit to remove
3464
 
    # unreferenced information in 'branch-as-repository' branches.
3465
 
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
3466
 
    # information in shared branches as well.
3467
 
    _see_also = ['commit']
3468
 
    takes_options = ['verbose', 'revision',
3469
 
                    Option('dry-run', help='Don\'t actually make changes.'),
3470
 
                    Option('force', help='Say yes to all questions.')]
3471
 
    takes_args = ['location?']
3472
 
    aliases = []
3473
 
 
3474
 
    def run(self, location=None,
3475
 
            dry_run=False, verbose=False,
3476
 
            revision=None, force=False):
3477
 
        from bzrlib.log import log_formatter, show_log
3478
 
        import sys
3479
 
        from bzrlib.uncommit import uncommit
3480
 
 
3481
 
        if location is None:
3482
 
            location = u'.'
3483
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
3484
 
        try:
3485
 
            tree = control.open_workingtree()
3486
 
            b = tree.branch
3487
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
3488
 
            tree = None
3489
 
            b = control.open_branch()
3490
 
 
3491
 
        rev_id = None
3492
 
        if revision is None:
3493
 
            revno = b.revno()
3494
 
        else:
3495
 
            # 'bzr uncommit -r 10' actually means uncommit
3496
 
            # so that the final tree is at revno 10.
3497
 
            # but bzrlib.uncommit.uncommit() actually uncommits
3498
 
            # the revisions that are supplied.
3499
 
            # So we need to offset it by one
3500
 
            revno = revision[0].in_history(b).revno+1
3501
 
 
3502
 
        if revno <= b.revno():
3503
 
            rev_id = b.get_rev_id(revno)
3504
 
        if rev_id is None:
3505
 
            self.outf.write('No revisions to uncommit.\n')
3506
 
            return 1
3507
 
 
3508
 
        lf = log_formatter('short',
3509
 
                           to_file=self.outf,
3510
 
                           show_timezone='original')
3511
 
 
3512
 
        show_log(b,
3513
 
                 lf,
3514
 
                 verbose=False,
3515
 
                 direction='forward',
3516
 
                 start_revision=revno,
3517
 
                 end_revision=b.revno())
3518
 
 
3519
 
        if dry_run:
3520
 
            print 'Dry-run, pretending to remove the above revisions.'
3521
 
            if not force:
3522
 
                val = raw_input('Press <enter> to continue')
3523
 
        else:
3524
 
            print 'The above revision(s) will be removed.'
3525
 
            if not force:
3526
 
                val = raw_input('Are you sure [y/N]? ')
3527
 
                if val.lower() not in ('y', 'yes'):
3528
 
                    print 'Canceled'
3529
 
                    return 0
3530
 
 
3531
 
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3532
 
                revno=revno)
3533
 
 
3534
 
 
3535
 
class cmd_break_lock(Command):
3536
 
    """Break a dead lock on a repository, branch or working directory.
3537
 
 
3538
 
    CAUTION: Locks should only be broken when you are sure that the process
3539
 
    holding the lock has been stopped.
3540
 
 
3541
 
    You can get information on what locks are open via the 'bzr info' command.
3542
 
    
3543
 
    :Examples:
3544
 
        bzr break-lock
3545
 
    """
3546
 
    takes_args = ['location?']
3547
 
 
3548
 
    def run(self, location=None, show=False):
3549
 
        if location is None:
3550
 
            location = u'.'
3551
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
3552
 
        try:
3553
 
            control.break_lock()
3554
 
        except NotImplementedError:
3555
 
            pass
3556
 
        
3557
 
 
3558
 
class cmd_wait_until_signalled(Command):
3559
 
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
3560
 
 
3561
 
    This just prints a line to signal when it is ready, then blocks on stdin.
3562
 
    """
3563
 
 
3564
 
    hidden = True
3565
 
 
3566
 
    def run(self):
3567
 
        sys.stdout.write("running\n")
3568
 
        sys.stdout.flush()
3569
 
        sys.stdin.readline()
3570
 
 
3571
 
 
3572
 
class cmd_serve(Command):
3573
 
    """Run the bzr server."""
3574
 
 
3575
 
    aliases = ['server']
3576
 
 
3577
 
    takes_options = [
3578
 
        Option('inet',
3579
 
               help='Serve on stdin/out for use from inetd or sshd.'),
3580
 
        Option('port',
3581
 
               help='Listen for connections on nominated port of the form '
3582
 
                    '[hostname:]portnumber.  Passing 0 as the port number will '
3583
 
                    'result in a dynamically allocated port.  The default port is '
3584
 
                    '4155.',
3585
 
               type=str),
3586
 
        Option('directory',
3587
 
               help='Serve contents of this directory.',
3588
 
               type=unicode),
3589
 
        Option('allow-writes',
3590
 
               help='By default the server is a readonly server.  Supplying '
3591
 
                    '--allow-writes enables write access to the contents of '
3592
 
                    'the served directory and below.'
3593
 
                ),
3594
 
        ]
3595
 
 
3596
 
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
3597
 
        from bzrlib.smart import medium, server
3598
 
        from bzrlib.transport import get_transport
3599
 
        from bzrlib.transport.chroot import ChrootServer
3600
 
        from bzrlib.transport.remote import BZR_DEFAULT_PORT, BZR_DEFAULT_INTERFACE
3601
 
        if directory is None:
3602
 
            directory = os.getcwd()
3603
 
        url = urlutils.local_path_to_url(directory)
3604
 
        if not allow_writes:
3605
 
            url = 'readonly+' + url
3606
 
        chroot_server = ChrootServer(get_transport(url))
3607
 
        chroot_server.setUp()
3608
 
        t = get_transport(chroot_server.get_url())
3609
 
        if inet:
3610
 
            smart_server = medium.SmartServerPipeStreamMedium(
3611
 
                sys.stdin, sys.stdout, t)
3612
 
        else:
3613
 
            host = BZR_DEFAULT_INTERFACE
3614
 
            if port is None:
3615
 
                port = BZR_DEFAULT_PORT
3616
 
            else:
3617
 
                if ':' in port:
3618
 
                    host, port = port.split(':')
3619
 
                port = int(port)
3620
 
            smart_server = server.SmartTCPServer(t, host=host, port=port)
3621
 
            print 'listening on port: ', smart_server.port
3622
 
            sys.stdout.flush()
3623
 
        # for the duration of this server, no UI output is permitted.
3624
 
        # note that this may cause problems with blackbox tests. This should
3625
 
        # be changed with care though, as we dont want to use bandwidth sending
3626
 
        # progress over stderr to smart server clients!
3627
 
        old_factory = ui.ui_factory
3628
 
        try:
3629
 
            ui.ui_factory = ui.SilentUIFactory()
3630
 
            smart_server.serve()
3631
 
        finally:
3632
 
            ui.ui_factory = old_factory
3633
 
 
3634
 
 
3635
 
class cmd_join(Command):
3636
 
    """Combine a subtree into its containing tree.
3637
 
    
3638
 
    This command is for experimental use only.  It requires the target tree
3639
 
    to be in dirstate-with-subtree format, which cannot be converted into
3640
 
    earlier formats.
3641
 
 
3642
 
    The TREE argument should be an independent tree, inside another tree, but
3643
 
    not part of it.  (Such trees can be produced by "bzr split", but also by
3644
 
    running "bzr branch" with the target inside a tree.)
3645
 
 
3646
 
    The result is a combined tree, with the subtree no longer an independant
3647
 
    part.  This is marked as a merge of the subtree into the containing tree,
3648
 
    and all history is preserved.
3649
 
 
3650
 
    If --reference is specified, the subtree retains its independence.  It can
3651
 
    be branched by itself, and can be part of multiple projects at the same
3652
 
    time.  But operations performed in the containing tree, such as commit
3653
 
    and merge, will recurse into the subtree.
3654
 
    """
3655
 
 
3656
 
    _see_also = ['split']
3657
 
    takes_args = ['tree']
3658
 
    takes_options = [
3659
 
            Option('reference', help='Join by reference.'),
3660
 
            ]
3661
 
    hidden = True
3662
 
 
3663
 
    def run(self, tree, reference=False):
3664
 
        sub_tree = WorkingTree.open(tree)
3665
 
        parent_dir = osutils.dirname(sub_tree.basedir)
3666
 
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
3667
 
        repo = containing_tree.branch.repository
3668
 
        if not repo.supports_rich_root():
3669
 
            raise errors.BzrCommandError(
3670
 
                "Can't join trees because %s doesn't support rich root data.\n"
3671
 
                "You can use bzr upgrade on the repository."
3672
 
                % (repo,))
3673
 
        if reference:
3674
 
            try:
3675
 
                containing_tree.add_reference(sub_tree)
3676
 
            except errors.BadReferenceTarget, e:
3677
 
                # XXX: Would be better to just raise a nicely printable
3678
 
                # exception from the real origin.  Also below.  mbp 20070306
3679
 
                raise errors.BzrCommandError("Cannot join %s.  %s" %
3680
 
                                             (tree, e.reason))
3681
 
        else:
3682
 
            try:
3683
 
                containing_tree.subsume(sub_tree)
3684
 
            except errors.BadSubsumeSource, e:
3685
 
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
3686
 
                                             (tree, e.reason))
3687
 
 
3688
 
 
3689
 
class cmd_split(Command):
3690
 
    """Split a tree into two trees.
3691
 
 
3692
 
    This command is for experimental use only.  It requires the target tree
3693
 
    to be in dirstate-with-subtree format, which cannot be converted into
3694
 
    earlier formats.
3695
 
 
3696
 
    The TREE argument should be a subdirectory of a working tree.  That
3697
 
    subdirectory will be converted into an independent tree, with its own
3698
 
    branch.  Commits in the top-level tree will not apply to the new subtree.
3699
 
    If you want that behavior, do "bzr join --reference TREE".
3700
 
    """
3701
 
 
3702
 
    _see_also = ['join']
3703
 
    takes_args = ['tree']
3704
 
 
3705
 
    hidden = True
3706
 
 
3707
 
    def run(self, tree):
3708
 
        containing_tree, subdir = WorkingTree.open_containing(tree)
3709
 
        sub_id = containing_tree.path2id(subdir)
3710
 
        if sub_id is None:
3711
 
            raise errors.NotVersionedError(subdir)
3712
 
        try:
3713
 
            containing_tree.extract(sub_id)
3714
 
        except errors.RootNotRich:
3715
 
            raise errors.UpgradeRequired(containing_tree.branch.base)
3716
 
 
3717
 
 
3718
 
 
3719
 
class cmd_merge_directive(Command):
3720
 
    """Generate a merge directive for auto-merge tools.
3721
 
 
3722
 
    A directive requests a merge to be performed, and also provides all the
3723
 
    information necessary to do so.  This means it must either include a
3724
 
    revision bundle, or the location of a branch containing the desired
3725
 
    revision.
3726
 
 
3727
 
    A submit branch (the location to merge into) must be supplied the first
3728
 
    time the command is issued.  After it has been supplied once, it will
3729
 
    be remembered as the default.
3730
 
 
3731
 
    A public branch is optional if a revision bundle is supplied, but required
3732
 
    if --diff or --plain is specified.  It will be remembered as the default
3733
 
    after the first use.
3734
 
    """
3735
 
 
3736
 
    takes_args = ['submit_branch?', 'public_branch?']
3737
 
 
3738
 
    hidden = True
3739
 
 
3740
 
    _see_also = ['send']
3741
 
 
3742
 
    takes_options = [
3743
 
        RegistryOption.from_kwargs('patch-type',
3744
 
            'The type of patch to include in the directive.',
3745
 
            title='Patch type',
3746
 
            value_switches=True,
3747
 
            enum_switch=False,
3748
 
            bundle='Bazaar revision bundle (default).',
3749
 
            diff='Normal unified diff.',
3750
 
            plain='No patch, just directive.'),
3751
 
        Option('sign', help='GPG-sign the directive.'), 'revision',
3752
 
        Option('mail-to', type=str,
3753
 
            help='Instead of printing the directive, email to this address.'),
3754
 
        Option('message', type=str, short_name='m',
3755
 
            help='Message to use when committing this merge.')
3756
 
        ]
3757
 
 
3758
 
    encoding_type = 'exact'
3759
 
 
3760
 
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
3761
 
            sign=False, revision=None, mail_to=None, message=None):
3762
 
        from bzrlib.revision import ensure_null, NULL_REVISION
3763
 
        include_patch, include_bundle = {
3764
 
            'plain': (False, False),
3765
 
            'diff': (True, False),
3766
 
            'bundle': (True, True),
3767
 
            }[patch_type]
3768
 
        branch = Branch.open('.')
3769
 
        stored_submit_branch = branch.get_submit_branch()
3770
 
        if submit_branch is None:
3771
 
            submit_branch = stored_submit_branch
3772
 
        else:
3773
 
            if stored_submit_branch is None:
3774
 
                branch.set_submit_branch(submit_branch)
3775
 
        if submit_branch is None:
3776
 
            submit_branch = branch.get_parent()
3777
 
        if submit_branch is None:
3778
 
            raise errors.BzrCommandError('No submit branch specified or known')
3779
 
 
3780
 
        stored_public_branch = branch.get_public_branch()
3781
 
        if public_branch is None:
3782
 
            public_branch = stored_public_branch
3783
 
        elif stored_public_branch is None:
3784
 
            branch.set_public_branch(public_branch)
3785
 
        if not include_bundle and public_branch is None:
3786
 
            raise errors.BzrCommandError('No public branch specified or'
3787
 
                                         ' known')
3788
 
        base_revision_id = None
3789
 
        if revision is not None:
3790
 
            if len(revision) > 2:
3791
 
                raise errors.BzrCommandError('bzr merge-directive takes '
3792
 
                    'at most two one revision identifiers')
3793
 
            revision_id = revision[-1].in_history(branch).rev_id
3794
 
            if len(revision) == 2:
3795
 
                base_revision_id = revision[0].in_history(branch).rev_id
3796
 
                base_revision_id = ensure_null(base_revision_id)
3797
 
        else:
3798
 
            revision_id = branch.last_revision()
3799
 
        revision_id = ensure_null(revision_id)
3800
 
        if revision_id == NULL_REVISION:
3801
 
            raise errors.BzrCommandError('No revisions to bundle.')
3802
 
        directive = merge_directive.MergeDirective2.from_objects(
3803
 
            branch.repository, revision_id, time.time(),
3804
 
            osutils.local_time_offset(), submit_branch,
3805
 
            public_branch=public_branch, include_patch=include_patch,
3806
 
            include_bundle=include_bundle, message=message,
3807
 
            base_revision_id=base_revision_id)
3808
 
        if mail_to is None:
3809
 
            if sign:
3810
 
                self.outf.write(directive.to_signed(branch))
3811
 
            else:
3812
 
                self.outf.writelines(directive.to_lines())
3813
 
        else:
3814
 
            message = directive.to_email(mail_to, branch, sign)
3815
 
            s = SMTPConnection(branch.get_config())
3816
 
            s.send_email(message)
3817
 
 
3818
 
 
3819
 
class cmd_send(Command):
3820
 
    """Mail or create a merge-directive for submiting changes.
3821
 
 
3822
 
    A merge directive provides many things needed for requesting merges:
3823
 
 
3824
 
    * A machine-readable description of the merge to perform
3825
 
 
3826
 
    * An optional patch that is a preview of the changes requested
3827
 
 
3828
 
    * An optional bundle of revision data, so that the changes can be applied
3829
 
      directly from the merge directive, without retrieving data from a
3830
 
      branch.
3831
 
 
3832
 
    If --no-bundle is specified, then public_branch is needed (and must be
3833
 
    up-to-date), so that the receiver can perform the merge using the
3834
 
    public_branch.  The public_branch is always included if known, so that
3835
 
    people can check it later.
3836
 
 
3837
 
    The submit branch defaults to the parent, but can be overridden.  Both
3838
 
    submit branch and public branch will be remembered if supplied.
3839
 
 
3840
 
    If a public_branch is known for the submit_branch, that public submit
3841
 
    branch is used in the merge instructions.  This means that a local mirror
3842
 
    can be used as your actual submit branch, once you have set public_branch
3843
 
    for that mirror.
3844
 
 
3845
 
    Mail is sent using your preferred mail program.  This should be transparent
3846
 
    on Windows (it uses MAPI).  On *nix, it requires the xdg-email utility.  If
3847
 
    the preferred client can't be found (or used), your editor will be used.
3848
 
    
3849
 
    To use a specific mail program, set the mail_client configuration option.
3850
 
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
3851
 
    specific clients are "evolution", "kmail", "mutt", and "thunderbird";
3852
 
    generic options are "default", "editor", "mapi", and "xdg-email".
3853
 
 
3854
 
    If mail is being sent, a to address is required.  This can be supplied
3855
 
    either on the commandline, or by setting the submit_to configuration
3856
 
    option.
3857
 
 
3858
 
    Two formats are currently supported: "4" uses revision bundle format 4 and
3859
 
    merge directive format 2.  It is significantly faster and smaller than
3860
 
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
3861
 
    default.  "0.9" uses revision bundle format 0.9 and merge directive
3862
 
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
3863
 
    """
3864
 
 
3865
 
    encoding_type = 'exact'
3866
 
 
3867
 
    _see_also = ['merge']
3868
 
 
3869
 
    takes_args = ['submit_branch?', 'public_branch?']
3870
 
 
3871
 
    takes_options = [
3872
 
        Option('no-bundle',
3873
 
               help='Do not include a bundle in the merge directive.'),
3874
 
        Option('no-patch', help='Do not include a preview patch in the merge'
3875
 
               ' directive.'),
3876
 
        Option('remember',
3877
 
               help='Remember submit and public branch.'),
3878
 
        Option('from',
3879
 
               help='Branch to generate the submission from, '
3880
 
               'rather than the one containing the working directory.',
3881
 
               short_name='f',
3882
 
               type=unicode),
3883
 
        Option('output', short_name='o', help='Write directive to this file.',
3884
 
               type=unicode),
3885
 
        Option('mail-to', help='Mail the request to this address.',
3886
 
               type=unicode),
3887
 
        'revision',
3888
 
        'message',
3889
 
        RegistryOption.from_kwargs('format',
3890
 
        'Use the specified output format.',
3891
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
3892
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
3893
 
        ]
3894
 
 
3895
 
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
3896
 
            no_patch=False, revision=None, remember=False, output=None,
3897
 
            format='4', mail_to=None, message=None, **kwargs):
3898
 
        return self._run(submit_branch, revision, public_branch, remember,
3899
 
                         format, no_bundle, no_patch, output,
3900
 
                         kwargs.get('from', '.'), mail_to, message)
3901
 
 
3902
 
    def _run(self, submit_branch, revision, public_branch, remember, format,
3903
 
             no_bundle, no_patch, output, from_, mail_to, message):
3904
 
        from bzrlib.revision import ensure_null, NULL_REVISION
3905
 
        if output is None:
3906
 
            outfile = StringIO()
3907
 
        elif output == '-':
3908
 
            outfile = self.outf
3909
 
        else:
3910
 
            outfile = open(output, 'wb')
3911
 
        try:
3912
 
            branch = Branch.open_containing(from_)[0]
3913
 
            if output is None:
3914
 
                config = branch.get_config()
3915
 
                if mail_to is None:
3916
 
                    mail_to = config.get_user_option('submit_to')
3917
 
                if mail_to is None:
3918
 
                    raise errors.BzrCommandError('No mail-to address'
3919
 
                                                 ' specified')
3920
 
                mail_client = config.get_mail_client()
3921
 
            if remember and submit_branch is None:
3922
 
                raise errors.BzrCommandError(
3923
 
                    '--remember requires a branch to be specified.')
3924
 
            stored_submit_branch = branch.get_submit_branch()
3925
 
            remembered_submit_branch = False
3926
 
            if submit_branch is None:
3927
 
                submit_branch = stored_submit_branch
3928
 
                remembered_submit_branch = True
3929
 
            else:
3930
 
                if stored_submit_branch is None or remember:
3931
 
                    branch.set_submit_branch(submit_branch)
3932
 
            if submit_branch is None:
3933
 
                submit_branch = branch.get_parent()
3934
 
                remembered_submit_branch = True
3935
 
            if submit_branch is None:
3936
 
                raise errors.BzrCommandError('No submit branch known or'
3937
 
                                             ' specified')
3938
 
            if remembered_submit_branch:
3939
 
                note('Using saved location: %s', submit_branch)
3940
 
 
3941
 
            stored_public_branch = branch.get_public_branch()
3942
 
            if public_branch is None:
3943
 
                public_branch = stored_public_branch
3944
 
            elif stored_public_branch is None or remember:
3945
 
                branch.set_public_branch(public_branch)
3946
 
            if no_bundle and public_branch is None:
3947
 
                raise errors.BzrCommandError('No public branch specified or'
3948
 
                                             ' known')
3949
 
            base_revision_id = None
3950
 
            revision_id = None
3951
 
            if revision is not None:
3952
 
                if len(revision) > 2:
3953
 
                    raise errors.BzrCommandError('bzr send takes '
3954
 
                        'at most two one revision identifiers')
3955
 
                revision_id = revision[-1].in_history(branch).rev_id
3956
 
                if len(revision) == 2:
3957
 
                    base_revision_id = revision[0].in_history(branch).rev_id
3958
 
            if revision_id is None:
3959
 
                revision_id = branch.last_revision()
3960
 
            if revision_id == NULL_REVISION:
3961
 
                raise errors.BzrCommandError('No revisions to submit.')
3962
 
            if format == '4':
3963
 
                directive = merge_directive.MergeDirective2.from_objects(
3964
 
                    branch.repository, revision_id, time.time(),
3965
 
                    osutils.local_time_offset(), submit_branch,
3966
 
                    public_branch=public_branch, include_patch=not no_patch,
3967
 
                    include_bundle=not no_bundle, message=message,
3968
 
                    base_revision_id=base_revision_id)
3969
 
            elif format == '0.9':
3970
 
                if not no_bundle:
3971
 
                    if not no_patch:
3972
 
                        patch_type = 'bundle'
3973
 
                    else:
3974
 
                        raise errors.BzrCommandError('Format 0.9 does not'
3975
 
                            ' permit bundle with no patch')
3976
 
                else:
3977
 
                    if not no_patch:
3978
 
                        patch_type = 'diff'
3979
 
                    else:
3980
 
                        patch_type = None
3981
 
                directive = merge_directive.MergeDirective.from_objects(
3982
 
                    branch.repository, revision_id, time.time(),
3983
 
                    osutils.local_time_offset(), submit_branch,
3984
 
                    public_branch=public_branch, patch_type=patch_type,
3985
 
                    message=message)
3986
 
 
3987
 
            outfile.writelines(directive.to_lines())
3988
 
            if output is None:
3989
 
                subject = '[MERGE] '
3990
 
                if message is not None:
3991
 
                    subject += message
3992
 
                else:
3993
 
                    revision = branch.repository.get_revision(revision_id)
3994
 
                    subject += revision.get_summary()
3995
 
                mail_client.compose_merge_request(mail_to, subject,
3996
 
                                                  outfile.getvalue())
3997
 
        finally:
3998
 
            if output != '-':
3999
 
                outfile.close()
4000
 
 
4001
 
 
4002
 
class cmd_bundle_revisions(cmd_send):
4003
 
 
4004
 
    """Create a merge-directive for submiting changes.
4005
 
 
4006
 
    A merge directive provides many things needed for requesting merges:
4007
 
 
4008
 
    * A machine-readable description of the merge to perform
4009
 
 
4010
 
    * An optional patch that is a preview of the changes requested
4011
 
 
4012
 
    * An optional bundle of revision data, so that the changes can be applied
4013
 
      directly from the merge directive, without retrieving data from a
4014
 
      branch.
4015
 
 
4016
 
    If --no-bundle is specified, then public_branch is needed (and must be
4017
 
    up-to-date), so that the receiver can perform the merge using the
4018
 
    public_branch.  The public_branch is always included if known, so that
4019
 
    people can check it later.
4020
 
 
4021
 
    The submit branch defaults to the parent, but can be overridden.  Both
4022
 
    submit branch and public branch will be remembered if supplied.
4023
 
 
4024
 
    If a public_branch is known for the submit_branch, that public submit
4025
 
    branch is used in the merge instructions.  This means that a local mirror
4026
 
    can be used as your actual submit branch, once you have set public_branch
4027
 
    for that mirror.
4028
 
 
4029
 
    Two formats are currently supported: "4" uses revision bundle format 4 and
4030
 
    merge directive format 2.  It is significantly faster and smaller than
4031
 
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4032
 
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4033
 
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
4034
 
    """
4035
 
 
4036
 
    takes_options = [
4037
 
        Option('no-bundle',
4038
 
               help='Do not include a bundle in the merge directive.'),
4039
 
        Option('no-patch', help='Do not include a preview patch in the merge'
4040
 
               ' directive.'),
4041
 
        Option('remember',
4042
 
               help='Remember submit and public branch.'),
4043
 
        Option('from',
4044
 
               help='Branch to generate the submission from, '
4045
 
               'rather than the one containing the working directory.',
4046
 
               short_name='f',
4047
 
               type=unicode),
4048
 
        Option('output', short_name='o', help='Write directive to this file.',
4049
 
               type=unicode),
4050
 
        'revision',
4051
 
        RegistryOption.from_kwargs('format',
4052
 
        'Use the specified output format.',
4053
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4054
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
4055
 
        ]
4056
 
    aliases = ['bundle']
4057
 
 
4058
 
    _see_also = ['send', 'merge']
4059
 
 
4060
 
    hidden = True
4061
 
 
4062
 
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4063
 
            no_patch=False, revision=None, remember=False, output=None,
4064
 
            format='4', **kwargs):
4065
 
        if output is None:
4066
 
            output = '-'
4067
 
        return self._run(submit_branch, revision, public_branch, remember,
4068
 
                         format, no_bundle, no_patch, output,
4069
 
                         kwargs.get('from', '.'), None, None)
4070
 
 
4071
 
 
4072
 
class cmd_tag(Command):
4073
 
    """Create, remove or modify a tag naming a revision.
4074
 
    
4075
 
    Tags give human-meaningful names to revisions.  Commands that take a -r
4076
 
    (--revision) option can be given -rtag:X, where X is any previously
4077
 
    created tag.
4078
 
 
4079
 
    Tags are stored in the branch.  Tags are copied from one branch to another
4080
 
    along when you branch, push, pull or merge.
4081
 
 
4082
 
    It is an error to give a tag name that already exists unless you pass 
4083
 
    --force, in which case the tag is moved to point to the new revision.
4084
 
    """
4085
 
 
4086
 
    _see_also = ['commit', 'tags']
4087
 
    takes_args = ['tag_name']
4088
 
    takes_options = [
4089
 
        Option('delete',
4090
 
            help='Delete this tag rather than placing it.',
4091
 
            ),
4092
 
        Option('directory',
4093
 
            help='Branch in which to place the tag.',
4094
 
            short_name='d',
4095
 
            type=unicode,
4096
 
            ),
4097
 
        Option('force',
4098
 
            help='Replace existing tags.',
4099
 
            ),
4100
 
        'revision',
4101
 
        ]
4102
 
 
4103
 
    def run(self, tag_name,
4104
 
            delete=None,
4105
 
            directory='.',
4106
 
            force=None,
4107
 
            revision=None,
4108
 
            ):
4109
 
        branch, relpath = Branch.open_containing(directory)
4110
 
        branch.lock_write()
4111
 
        try:
4112
 
            if delete:
4113
 
                branch.tags.delete_tag(tag_name)
4114
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
4115
 
            else:
4116
 
                if revision:
4117
 
                    if len(revision) != 1:
4118
 
                        raise errors.BzrCommandError(
4119
 
                            "Tags can only be placed on a single revision, "
4120
 
                            "not on a range")
4121
 
                    revision_id = revision[0].in_history(branch).rev_id
4122
 
                else:
4123
 
                    revision_id = branch.last_revision()
4124
 
                if (not force) and branch.tags.has_tag(tag_name):
4125
 
                    raise errors.TagAlreadyExists(tag_name)
4126
 
                branch.tags.set_tag(tag_name, revision_id)
4127
 
                self.outf.write('Created tag %s.\n' % tag_name)
4128
 
        finally:
4129
 
            branch.unlock()
4130
 
 
4131
 
 
4132
 
class cmd_tags(Command):
4133
 
    """List tags.
4134
 
 
4135
 
    This tag shows a table of tag names and the revisions they reference.
4136
 
    """
4137
 
 
4138
 
    _see_also = ['tag']
4139
 
    takes_options = [
4140
 
        Option('directory',
4141
 
            help='Branch whose tags should be displayed.',
4142
 
            short_name='d',
4143
 
            type=unicode,
4144
 
            ),
4145
 
    ]
4146
 
 
4147
 
    @display_command
4148
 
    def run(self,
4149
 
            directory='.',
4150
 
            ):
4151
 
        branch, relpath = Branch.open_containing(directory)
4152
 
        for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
4153
 
            self.outf.write('%-20s %s\n' % (tag_name, target))
4154
 
 
4155
 
 
4156
 
class cmd_reconfigure(Command):
4157
 
    """Reconfigure the type of a bzr directory.
4158
 
 
4159
 
    A target configuration must be specified.
4160
 
 
4161
 
    For checkouts, the bind-to location will be auto-detected if not specified.
4162
 
    The order of preference is
4163
 
    1. For a lightweight checkout, the current bound location.
4164
 
    2. For branches that used to be checkouts, the previously-bound location.
4165
 
    3. The push location.
4166
 
    4. The parent location.
4167
 
    If none of these is available, --bind-to must be specified.
4168
 
    """
4169
 
 
4170
 
    takes_args = ['location?']
4171
 
    takes_options = [RegistryOption.from_kwargs('target_type',
4172
 
                     title='Target type',
4173
 
                     help='The type to reconfigure the directory to.',
4174
 
                     value_switches=True, enum_switch=False,
4175
 
                     branch='Reconfigure to a branch.',
4176
 
                     tree='Reconfigure to a tree.',
4177
 
                     checkout='Reconfigure to a checkout.'),
4178
 
                     Option('bind-to', help='Branch to bind checkout to.',
4179
 
                            type=str),
4180
 
                     Option('force',
4181
 
                        help='Perform reconfiguration even if local changes'
4182
 
                        ' will be lost.')
4183
 
                     ]
4184
 
 
4185
 
    def run(self, location=None, target_type=None, bind_to=None, force=False):
4186
 
        directory = bzrdir.BzrDir.open(location)
4187
 
        if target_type is None:
4188
 
            raise errors.BzrCommandError('No target configuration specified')
4189
 
        elif target_type == 'branch':
4190
 
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
4191
 
        elif target_type == 'tree':
4192
 
            reconfiguration = reconfigure.Reconfigure.to_tree(directory)
4193
 
        elif target_type == 'checkout':
4194
 
            reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4195
 
                                                                  bind_to)
4196
 
        reconfiguration.apply(force)
4197
 
 
4198
 
 
4199
 
def _create_prefix(cur_transport):
4200
 
    needed = [cur_transport]
4201
 
    # Recurse upwards until we can create a directory successfully
4202
 
    while True:
4203
 
        new_transport = cur_transport.clone('..')
4204
 
        if new_transport.base == cur_transport.base:
4205
 
            raise errors.BzrCommandError(
4206
 
                "Failed to create path prefix for %s."
4207
 
                % cur_transport.base)
4208
 
        try:
4209
 
            new_transport.mkdir('.')
4210
 
        except errors.NoSuchFile:
4211
 
            needed.append(new_transport)
4212
 
            cur_transport = new_transport
4213
 
        else:
4214
 
            break
4215
 
    # Now we only need to create child directories
4216
 
    while needed:
4217
 
        cur_transport = needed.pop()
4218
 
        cur_transport.ensure_base()
4219
 
 
4220
 
 
4221
 
def _get_mergeable_helper(location):
4222
 
    """Get a merge directive or bundle if 'location' points to one.
4223
 
 
4224
 
    Try try to identify a bundle and returns its mergeable form. If it's not,
4225
 
    we return the tried transport anyway so that it can reused to access the
4226
 
    branch
4227
 
 
4228
 
    :param location: can point to a bundle or a branch.
4229
 
 
4230
 
    :return: mergeable, transport
4231
 
    """
4232
 
    mergeable = None
4233
 
    url = urlutils.normalize_url(location)
4234
 
    url, filename = urlutils.split(url, exclude_trailing_slash=False)
4235
 
    location_transport = transport.get_transport(url)
4236
 
    if filename:
4237
 
        try:
4238
 
            # There may be redirections but we ignore the intermediate
4239
 
            # and final transports used
4240
 
            read = bundle.read_mergeable_from_transport
4241
 
            mergeable, t = read(location_transport, filename)
4242
 
        except errors.NotABundle:
4243
 
            # Continue on considering this url a Branch but adjust the
4244
 
            # location_transport
4245
 
            location_transport = location_transport.clone(filename)
4246
 
    return mergeable, location_transport
4247
 
 
4248
 
 
4249
 
# these get imported and then picked up by the scan for cmd_*
4250
 
# TODO: Some more consistent way to split command definitions across files;
4251
 
# we do need to load at least some information about them to know of 
4252
 
# aliases.  ideally we would avoid loading the implementation until the
4253
 
# details were needed.
4254
 
from bzrlib.cmd_version_info import cmd_version_info
4255
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
4256
 
from bzrlib.bundle.commands import (
4257
 
    cmd_bundle_info,
4258
 
    )
4259
 
from bzrlib.sign_my_commits import cmd_sign_my_commits
4260
 
from bzrlib.weave_commands import cmd_versionedfile_list, cmd_weave_join, \
4261
 
        cmd_weave_plan_merge, cmd_weave_merge_text