~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2007-03-08 04:06:06 UTC
  • mfrom: (2323.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 2442.
  • Revision ID: robertc@robertcollins.net-20070308040606-84gsniv56huiyjt4
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2004, 2005, 2006, 2007 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
17
"""builtin bzr commands"""
18
18
 
 
19
import os
19
20
 
 
21
from bzrlib.lazy_import import lazy_import
 
22
lazy_import(globals(), """
 
23
import codecs
20
24
import errno
21
 
import os
22
25
import sys
 
26
import tempfile
23
27
 
24
28
import bzrlib
25
 
import bzrlib.branch
 
29
from bzrlib import (
 
30
    branch,
 
31
    bundle,
 
32
    bzrdir,
 
33
    delta,
 
34
    config,
 
35
    errors,
 
36
    globbing,
 
37
    ignores,
 
38
    log,
 
39
    merge as _mod_merge,
 
40
    osutils,
 
41
    repository,
 
42
    symbol_versioning,
 
43
    transport,
 
44
    tree as _mod_tree,
 
45
    ui,
 
46
    urlutils,
 
47
    )
26
48
from bzrlib.branch import Branch
27
 
import bzrlib.bzrdir as bzrdir
28
 
from bzrlib.bundle.read_bundle import BundleReader
29
 
from bzrlib.bundle.apply_bundle import merge_bundle
30
 
from bzrlib.commands import Command, display_command
31
 
import bzrlib.errors as errors
32
 
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
33
 
                           NotBranchError, DivergedBranches, NotConflicted,
34
 
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
35
 
                           NotVersionedError, BadBundle)
36
 
from bzrlib.log import show_one_log
37
 
from bzrlib.merge import Merge3Merger
38
 
from bzrlib.option import Option
39
 
from bzrlib.progress import DummyProgress, ProgressPhase
 
49
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
 
50
from bzrlib.conflicts import ConflictList
40
51
from bzrlib.revision import common_ancestor
41
52
from bzrlib.revisionspec import RevisionSpec
42
 
import bzrlib.trace
43
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
44
 
from bzrlib.transport.local import LocalTransport
45
 
import bzrlib.ui
46
53
from bzrlib.workingtree import WorkingTree
 
54
""")
 
55
 
 
56
from bzrlib.commands import Command, display_command
 
57
from bzrlib.option import Option, RegistryOption
 
58
from bzrlib.progress import DummyProgress, ProgressPhase
 
59
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
47
60
 
48
61
 
49
62
def tree_files(file_list, default_branch=u'.'):
50
63
    try:
51
64
        return internal_tree_files(file_list, default_branch)
52
 
    except FileInWrongBranch, e:
53
 
        raise BzrCommandError("%s is not in the same branch as %s" %
54
 
                             (e.path, file_list[0]))
 
65
    except errors.FileInWrongBranch, e:
 
66
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
 
67
                                     (e.path, file_list[0]))
55
68
 
56
69
 
57
70
# XXX: Bad function name; should possibly also be a class method of
66
79
 
67
80
    :param file_list: Filenames to convert.  
68
81
 
69
 
    :param default_branch: Fallback tree path to use if file_list is empty or None.
 
82
    :param default_branch: Fallback tree path to use if file_list is empty or
 
83
        None.
70
84
 
71
85
    :return: workingtree, [relative_paths]
72
86
    """
73
87
    if file_list is None or len(file_list) == 0:
74
88
        return WorkingTree.open_containing(default_branch)[0], file_list
75
 
    tree = WorkingTree.open_containing(file_list[0])[0]
 
89
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
76
90
    new_list = []
77
91
    for filename in file_list:
78
92
        try:
79
 
            new_list.append(tree.relpath(filename))
 
93
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
80
94
        except errors.PathNotChild:
81
 
            raise FileInWrongBranch(tree.branch, filename)
 
95
            raise errors.FileInWrongBranch(tree.branch, filename)
82
96
    return tree, new_list
83
97
 
84
98
 
 
99
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
85
100
def get_format_type(typestring):
86
101
    """Parse and return a format specifier."""
87
 
    if typestring == "weave":
88
 
        return bzrdir.BzrDirFormat6()
 
102
    # Have to use BzrDirMetaFormat1 directly, so that
 
103
    # RepositoryFormat.set_default_format works
89
104
    if typestring == "default":
90
105
        return bzrdir.BzrDirMetaFormat1()
91
 
    if typestring == "metaweave":
92
 
        format = bzrdir.BzrDirMetaFormat1()
93
 
        format.repository_format = bzrlib.repository.RepositoryFormat7()
94
 
        return format
95
 
    if typestring == "knit":
96
 
        format = bzrdir.BzrDirMetaFormat1()
97
 
        format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
98
 
        return format
99
 
    msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
100
 
          "metaweave and weave" % typestring
101
 
    raise BzrCommandError(msg)
 
106
    try:
 
107
        return bzrdir.format_registry.make_bzrdir(typestring)
 
108
    except KeyError:
 
109
        msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
 
110
        raise errors.BzrCommandError(msg)
102
111
 
103
112
 
104
113
# TODO: Make sure no commands unconditionally use the working directory as a
128
137
    modified
129
138
        Text has changed since the previous revision.
130
139
 
131
 
    unchanged
132
 
        Nothing about this file has changed since the previous revision.
133
 
        Only shown with --all.
 
140
    kind changed
 
141
        File kind has been changed (e.g. from file to directory).
134
142
 
135
143
    unknown
136
144
        Not versioned and not matching an ignore pattern.
137
145
 
138
146
    To see ignored files use 'bzr ignored'.  For details in the
139
147
    changes to file texts, use 'bzr diff'.
 
148
    
 
149
    --short gives a status flags for each item, similar to the SVN's status
 
150
    command.
 
151
 
 
152
    Column 1: versioning / renames
 
153
      + File versioned
 
154
      - File unversioned
 
155
      R File renamed
 
156
      ? File unknown
 
157
      C File has conflicts
 
158
      P Entry for a pending merge (not a file)
 
159
 
 
160
    Column 2: Contents
 
161
      N File created
 
162
      D File deleted
 
163
      K File kind changed
 
164
      M File modified
 
165
 
 
166
    Column 3: Execute
 
167
      * The execute bit was changed
140
168
 
141
169
    If no arguments are specified, the status of the entire working
142
170
    directory is shown.  Otherwise, only the status of the specified
150
178
    # TODO: --no-recurse, --recurse options
151
179
    
152
180
    takes_args = ['file*']
153
 
    takes_options = ['all', 'show-ids', 'revision']
 
181
    takes_options = ['show-ids', 'revision', 'short']
154
182
    aliases = ['st', 'stat']
 
183
 
 
184
    encoding_type = 'replace'
155
185
    
156
186
    @display_command
157
 
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
158
 
        tree, file_list = tree_files(file_list)
159
 
            
 
187
    def run(self, show_ids=False, file_list=None, revision=None, short=False):
160
188
        from bzrlib.status import show_tree_status
161
 
        show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
162
 
                         specific_files=file_list, revision=revision)
 
189
 
 
190
        tree, file_list = tree_files(file_list)
 
191
            
 
192
        show_tree_status(tree, show_ids=show_ids,
 
193
                         specific_files=file_list, revision=revision,
 
194
                         to_file=self.outf,
 
195
                         short=short)
163
196
 
164
197
 
165
198
class cmd_cat_revision(Command):
172
205
    hidden = True
173
206
    takes_args = ['revision_id?']
174
207
    takes_options = ['revision']
 
208
    # cat-revision is more for frontends so should be exact
 
209
    encoding = 'strict'
175
210
    
176
211
    @display_command
177
212
    def run(self, revision_id=None, revision=None):
178
213
 
179
214
        if revision_id is not None and revision is not None:
180
 
            raise BzrCommandError('You can only supply one of revision_id or --revision')
 
215
            raise errors.BzrCommandError('You can only supply one of'
 
216
                                         ' revision_id or --revision')
181
217
        if revision_id is None and revision is None:
182
 
            raise BzrCommandError('You must supply either --revision or a revision_id')
 
218
            raise errors.BzrCommandError('You must supply either'
 
219
                                         ' --revision or a revision_id')
183
220
        b = WorkingTree.open_containing(u'.')[0].branch
 
221
 
 
222
        # TODO: jam 20060112 should cat-revision always output utf-8?
184
223
        if revision_id is not None:
185
 
            sys.stdout.write(b.repository.get_revision_xml(revision_id))
 
224
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
186
225
        elif revision is not None:
187
226
            for rev in revision:
188
227
                if rev is None:
189
 
                    raise BzrCommandError('You cannot specify a NULL revision.')
 
228
                    raise errors.BzrCommandError('You cannot specify a NULL'
 
229
                                                 ' revision.')
190
230
                revno, rev_id = rev.in_history(b)
191
 
                sys.stdout.write(b.repository.get_revision_xml(rev_id))
 
231
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
192
232
    
193
233
 
 
234
class cmd_remove_tree(Command):
 
235
    """Remove the working tree from a given branch/checkout.
 
236
 
 
237
    Since a lightweight checkout is little more than a working tree
 
238
    this will refuse to run against one.
 
239
    """
 
240
 
 
241
    takes_args = ['location?']
 
242
 
 
243
    def run(self, location='.'):
 
244
        d = bzrdir.BzrDir.open(location)
 
245
        
 
246
        try:
 
247
            working = d.open_workingtree()
 
248
        except errors.NoWorkingTree:
 
249
            raise errors.BzrCommandError("No working tree to remove")
 
250
        except errors.NotLocalUrl:
 
251
            raise errors.BzrCommandError("You cannot remove the working tree of a "
 
252
                                         "remote path")
 
253
        
 
254
        working_path = working.bzrdir.root_transport.base
 
255
        branch_path = working.branch.bzrdir.root_transport.base
 
256
        if working_path != branch_path:
 
257
            raise errors.BzrCommandError("You cannot remove the working tree from "
 
258
                                         "a lightweight checkout")
 
259
        
 
260
        d.destroy_workingtree()
 
261
        
 
262
 
194
263
class cmd_revno(Command):
195
264
    """Show current revision number.
196
265
 
197
 
    This is equal to the number of revisions on this branch."""
 
266
    This is equal to the number of revisions on this branch.
 
267
    """
 
268
 
198
269
    takes_args = ['location?']
 
270
 
199
271
    @display_command
200
272
    def run(self, location=u'.'):
201
 
        print Branch.open_containing(location)[0].revno()
 
273
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
 
274
        self.outf.write('\n')
202
275
 
203
276
 
204
277
class cmd_revision_info(Command):
207
280
    hidden = True
208
281
    takes_args = ['revision_info*']
209
282
    takes_options = ['revision']
 
283
 
210
284
    @display_command
211
285
    def run(self, revision=None, revision_info_list=[]):
212
286
 
215
289
            revs.extend(revision)
216
290
        if revision_info_list is not None:
217
291
            for rev in revision_info_list:
218
 
                revs.append(RevisionSpec(rev))
 
292
                revs.append(RevisionSpec.from_string(rev))
219
293
        if len(revs) == 0:
220
 
            raise BzrCommandError('You must supply a revision identifier')
 
294
            raise errors.BzrCommandError('You must supply a revision identifier')
221
295
 
222
296
        b = WorkingTree.open_containing(u'.')[0].branch
223
297
 
249
323
 
250
324
    Adding a file whose parent directory is not versioned will
251
325
    implicitly add the parent, and so on up to the root. This means
252
 
    you should never need to explictly add a directory, they'll just
 
326
    you should never need to explicitly add a directory, they'll just
253
327
    get added when you add a file in the directory.
254
328
 
255
329
    --dry-run will show which files would be added, but not actually 
256
330
    add them.
 
331
 
 
332
    --file-ids-from will try to use the file ids from the supplied path.
 
333
    It looks up ids trying to find a matching parent directory with the
 
334
    same filename, and then by pure path.
257
335
    """
258
336
    takes_args = ['file*']
259
 
    takes_options = ['no-recurse', 'dry-run', 'verbose']
 
337
    takes_options = ['no-recurse', 'dry-run', 'verbose',
 
338
                     Option('file-ids-from', type=unicode,
 
339
                            help='Lookup file ids from here')]
 
340
    encoding_type = 'replace'
260
341
 
261
 
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
 
342
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
 
343
            file_ids_from=None):
262
344
        import bzrlib.add
263
345
 
264
 
        if dry_run:
265
 
            if is_quiet():
266
 
                # This is pointless, but I'd rather not raise an error
267
 
                action = bzrlib.add.add_action_null
268
 
            else:
269
 
                action = bzrlib.add.add_action_print
270
 
        elif is_quiet():
271
 
            action = bzrlib.add.add_action_add
 
346
        base_tree = None
 
347
        if file_ids_from is not None:
 
348
            try:
 
349
                base_tree, base_path = WorkingTree.open_containing(
 
350
                                            file_ids_from)
 
351
            except errors.NoWorkingTree:
 
352
                base_branch, base_path = Branch.open_containing(
 
353
                                            file_ids_from)
 
354
                base_tree = base_branch.basis_tree()
 
355
 
 
356
            action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
 
357
                          to_file=self.outf, should_print=(not is_quiet()))
272
358
        else:
273
 
            action = bzrlib.add.add_action_add_and_print
 
359
            action = bzrlib.add.AddAction(to_file=self.outf,
 
360
                should_print=(not is_quiet()))
274
361
 
275
 
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
276
 
                                              action)
 
362
        if base_tree:
 
363
            base_tree.lock_read()
 
364
        try:
 
365
            added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
 
366
                action=action, save=not dry_run)
 
367
        finally:
 
368
            if base_tree is not None:
 
369
                base_tree.unlock()
277
370
        if len(ignored) > 0:
278
371
            if verbose:
279
372
                for glob in sorted(ignored.keys()):
280
373
                    for path in ignored[glob]:
281
 
                        print "ignored %s matching \"%s\"" % (path, glob)
 
374
                        self.outf.write("ignored %s matching \"%s\"\n" 
 
375
                                        % (path, glob))
282
376
            else:
283
377
                match_len = 0
284
378
                for glob, paths in ignored.items():
285
379
                    match_len += len(paths)
286
 
                print "ignored %d file(s)." % match_len
287
 
            print "If you wish to add some of these files, please add them"\
288
 
                " by name."
 
380
                self.outf.write("ignored %d file(s).\n" % match_len)
 
381
            self.outf.write("If you wish to add some of these files,"
 
382
                            " please add them by name.\n")
289
383
 
290
384
 
291
385
class cmd_mkdir(Command):
293
387
 
294
388
    This is equivalent to creating the directory and then adding it.
295
389
    """
 
390
 
296
391
    takes_args = ['dir+']
 
392
    encoding_type = 'replace'
297
393
 
298
394
    def run(self, dir_list):
299
395
        for d in dir_list:
300
396
            os.mkdir(d)
301
397
            wt, dd = WorkingTree.open_containing(d)
302
398
            wt.add([dd])
303
 
            print 'added', d
 
399
            self.outf.write('added %s\n' % d)
304
400
 
305
401
 
306
402
class cmd_relpath(Command):
307
403
    """Show path of a file relative to root"""
 
404
 
308
405
    takes_args = ['filename']
309
406
    hidden = True
310
407
    
311
408
    @display_command
312
409
    def run(self, filename):
 
410
        # TODO: jam 20050106 Can relpath return a munged path if
 
411
        #       sys.stdout encoding cannot represent it?
313
412
        tree, relpath = WorkingTree.open_containing(filename)
314
 
        print relpath
 
413
        self.outf.write(relpath)
 
414
        self.outf.write('\n')
315
415
 
316
416
 
317
417
class cmd_inventory(Command):
318
418
    """Show inventory of the current working copy or a revision.
319
419
 
320
420
    It is possible to limit the output to a particular entry
321
 
    type using the --kind option.  For example; --kind file.
 
421
    type using the --kind option.  For example: --kind file.
 
422
 
 
423
    It is also possible to restrict the list of files to a specific
 
424
    set. For example: bzr inventory --show-ids this/file
 
425
 
 
426
    See also: bzr ls
322
427
    """
 
428
 
 
429
    hidden = True
 
430
 
323
431
    takes_options = ['revision', 'show-ids', 'kind']
324
 
    
 
432
 
 
433
    takes_args = ['file*']
 
434
 
325
435
    @display_command
326
 
    def run(self, revision=None, show_ids=False, kind=None):
 
436
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
327
437
        if kind and kind not in ['file', 'directory', 'symlink']:
328
 
            raise BzrCommandError('invalid kind specified')
329
 
        tree = WorkingTree.open_containing(u'.')[0]
330
 
        if revision is None:
331
 
            inv = tree.read_working_inventory()
332
 
        else:
333
 
            if len(revision) > 1:
334
 
                raise BzrCommandError('bzr inventory --revision takes'
335
 
                    ' exactly one revision identifier')
336
 
            inv = tree.branch.repository.get_revision_inventory(
337
 
                revision[0].in_history(tree.branch).rev_id)
338
 
 
339
 
        for path, entry in inv.entries():
 
438
            raise errors.BzrCommandError('invalid kind specified')
 
439
 
 
440
        work_tree, file_list = tree_files(file_list)
 
441
        work_tree.lock_read()
 
442
        try:
 
443
            if revision is not None:
 
444
                if len(revision) > 1:
 
445
                    raise errors.BzrCommandError(
 
446
                        'bzr inventory --revision takes exactly one revision'
 
447
                        ' identifier')
 
448
                revision_id = revision[0].in_history(work_tree.branch).rev_id
 
449
                tree = work_tree.branch.repository.revision_tree(revision_id)
 
450
 
 
451
                extra_trees = [work_tree]
 
452
                tree.lock_read()
 
453
            else:
 
454
                tree = work_tree
 
455
                extra_trees = []
 
456
 
 
457
            if file_list is not None:
 
458
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
459
                                          require_versioned=True)
 
460
                # find_ids_across_trees may include some paths that don't
 
461
                # exist in 'tree'.
 
462
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
463
                                 for file_id in file_ids if file_id in tree)
 
464
            else:
 
465
                entries = tree.inventory.entries()
 
466
        finally:
 
467
            tree.unlock()
 
468
            if tree is not work_tree:
 
469
                work_tree.unlock()
 
470
 
 
471
        for path, entry in entries:
340
472
            if kind and kind != entry.kind:
341
473
                continue
342
474
            if show_ids:
343
 
                print '%-50s %s' % (path, entry.file_id)
 
475
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
344
476
            else:
345
 
                print path
 
477
                self.outf.write(path)
 
478
                self.outf.write('\n')
346
479
 
347
480
 
348
481
class cmd_mv(Command):
354
487
 
355
488
    If the last argument is a versioned directory, all the other names
356
489
    are moved into it.  Otherwise, there must be exactly two arguments
357
 
    and the file is changed to a new name, which must not already exist.
 
490
    and the file is changed to a new name.
 
491
 
 
492
    If OLDNAME does not exist on the filesystem but is versioned and
 
493
    NEWNAME does exist on the filesystem but is not versioned, mv
 
494
    assumes that the file has been manually moved and only updates
 
495
    its internal inventory to reflect that change.
 
496
    The same is valid when moving many SOURCE files to a DESTINATION.
358
497
 
359
498
    Files cannot be moved between branches.
360
499
    """
 
500
 
361
501
    takes_args = ['names*']
 
502
    takes_options = [Option("after", help="move only the bzr identifier"
 
503
        " of the file (file has already been moved). Use this flag if"
 
504
        " bzr is not able to detect this itself.")]
362
505
    aliases = ['move', 'rename']
363
 
 
364
 
    def run(self, names_list):
 
506
    encoding_type = 'replace'
 
507
 
 
508
    def run(self, names_list, after=False):
 
509
        if names_list is None:
 
510
            names_list = []
 
511
 
365
512
        if len(names_list) < 2:
366
 
            raise BzrCommandError("missing file argument")
 
513
            raise errors.BzrCommandError("missing file argument")
367
514
        tree, rel_names = tree_files(names_list)
368
515
        
369
516
        if os.path.isdir(names_list[-1]):
370
517
            # move into existing directory
371
 
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
372
 
                print "%s => %s" % pair
 
518
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
519
                self.outf.write("%s => %s\n" % pair)
373
520
        else:
374
521
            if len(names_list) != 2:
375
 
                raise BzrCommandError('to mv multiple files the destination '
376
 
                                      'must be a versioned directory')
377
 
            tree.rename_one(rel_names[0], rel_names[1])
378
 
            print "%s => %s" % (rel_names[0], rel_names[1])
 
522
                raise errors.BzrCommandError('to mv multiple files the'
 
523
                                             ' destination must be a versioned'
 
524
                                             ' directory')
 
525
            tree.rename_one(rel_names[0], rel_names[1], after=after)
 
526
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
379
527
            
380
528
    
381
529
class cmd_pull(Command):
389
537
    from one into the other.  Once one branch has merged, the other should
390
538
    be able to pull it again.
391
539
 
392
 
    If branches have diverged, you can use 'bzr merge' to pull the text changes
393
 
    from one into the other.  Once one branch has merged, the other should
394
 
    be able to pull it again.
395
 
 
396
540
    If you want to forget your local changes and just update your branch to
397
541
    match the remote one, use pull --overwrite.
398
542
 
399
543
    If there is no default location set, the first pull will set it.  After
400
544
    that, you can omit the location to use the default.  To change the
401
 
    default, use --remember.
 
545
    default, use --remember. The value will only be saved if the remote
 
546
    location can be accessed.
402
547
    """
403
 
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
 
548
 
 
549
    takes_options = ['remember', 'overwrite', 'revision', 'verbose',
 
550
        Option('directory',
 
551
            help='branch to pull into, '
 
552
                 'rather than the one containing the working directory',
 
553
            short_name='d',
 
554
            type=unicode,
 
555
            ),
 
556
        ]
404
557
    takes_args = ['location?']
 
558
    encoding_type = 'replace'
405
559
 
406
 
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
 
560
    def run(self, location=None, remember=False, overwrite=False,
 
561
            revision=None, verbose=False,
 
562
            directory=None):
 
563
        from bzrlib.tag import _merge_tags_if_possible
407
564
        # FIXME: too much stuff is in the command class
 
565
        if directory is None:
 
566
            directory = u'.'
408
567
        try:
409
 
            tree_to = WorkingTree.open_containing(u'.')[0]
 
568
            tree_to = WorkingTree.open_containing(directory)[0]
410
569
            branch_to = tree_to.branch
411
 
        except NoWorkingTree:
 
570
        except errors.NoWorkingTree:
412
571
            tree_to = None
413
 
            branch_to = Branch.open_containing(u'.')[0] 
 
572
            branch_to = Branch.open_containing(directory)[0]
 
573
 
 
574
        reader = None
 
575
        if location is not None:
 
576
            try:
 
577
                reader = bundle.read_bundle_from_url(location)
 
578
            except errors.NotABundle:
 
579
                pass # Continue on considering this url a Branch
 
580
 
414
581
        stored_loc = branch_to.get_parent()
415
582
        if location is None:
416
583
            if stored_loc is None:
417
 
                raise BzrCommandError("No pull location known or specified.")
 
584
                raise errors.BzrCommandError("No pull location known or"
 
585
                                             " specified.")
418
586
            else:
419
 
                print "Using saved location: %s" % stored_loc
 
587
                display_url = urlutils.unescape_for_display(stored_loc,
 
588
                        self.outf.encoding)
 
589
                self.outf.write("Using saved location: %s\n" % display_url)
420
590
                location = stored_loc
421
591
 
422
 
        if branch_to.get_parent() is None or remember:
423
 
            branch_to.set_parent(location)
424
 
 
425
 
        branch_from = Branch.open(location)
426
 
 
 
592
        if reader is not None:
 
593
            install_bundle(branch_to.repository, reader)
 
594
            branch_from = branch_to
 
595
        else:
 
596
            branch_from = Branch.open(location)
 
597
 
 
598
            if branch_to.get_parent() is None or remember:
 
599
                branch_to.set_parent(branch_from.base)
 
600
 
 
601
        rev_id = None
427
602
        if revision is None:
428
 
            rev_id = None
 
603
            if reader is not None:
 
604
                rev_id = reader.target
429
605
        elif len(revision) == 1:
430
606
            rev_id = revision[0].in_history(branch_from).rev_id
431
607
        else:
432
 
            raise BzrCommandError('bzr pull --revision takes one value.')
 
608
            raise errors.BzrCommandError('bzr pull --revision takes one value.')
433
609
 
434
610
        old_rh = branch_to.revision_history()
435
611
        if tree_to is not None:
436
 
            count = tree_to.pull(branch_from, overwrite, rev_id)
 
612
            result = tree_to.pull(branch_from, overwrite, rev_id,
 
613
                delta.ChangeReporter(unversioned_filter=tree_to.is_ignored))
437
614
        else:
438
 
            count = branch_to.pull(branch_from, overwrite, rev_id)
439
 
        note('%d revision(s) pulled.' % (count,))
 
615
            result = branch_to.pull(branch_from, overwrite, rev_id)
440
616
 
 
617
        result.report(self.outf)
441
618
        if verbose:
 
619
            from bzrlib.log import show_changed_revisions
442
620
            new_rh = branch_to.revision_history()
443
 
            if old_rh != new_rh:
444
 
                # Something changed
445
 
                from bzrlib.log import show_changed_revisions
446
 
                show_changed_revisions(branch_to, old_rh, new_rh)
 
621
            show_changed_revisions(branch_to, old_rh, new_rh, to_file=self.outf)
447
622
 
448
623
 
449
624
class cmd_push(Command):
468
643
 
469
644
    If there is no default push location set, the first push will set it.
470
645
    After that, you can omit the location to use the default.  To change the
471
 
    default, use --remember.
 
646
    default, use --remember. The value will only be saved if the remote
 
647
    location can be accessed.
472
648
    """
473
 
    takes_options = ['remember', 'overwrite', 
474
 
                     Option('create-prefix', 
475
 
                            help='Create the path leading up to the branch '
476
 
                                 'if it does not already exist')]
 
649
 
 
650
    takes_options = ['remember', 'overwrite', 'verbose',
 
651
        Option('create-prefix',
 
652
               help='Create the path leading up to the branch '
 
653
                    'if it does not already exist'),
 
654
        Option('directory',
 
655
            help='branch to push from, '
 
656
                 'rather than the one containing the working directory',
 
657
            short_name='d',
 
658
            type=unicode,
 
659
            ),
 
660
        Option('use-existing-dir',
 
661
               help='By default push will fail if the target'
 
662
                    ' directory exists, but does not already'
 
663
                    ' have a control directory. This flag will'
 
664
                    ' allow push to proceed.'),
 
665
        ]
477
666
    takes_args = ['location?']
 
667
    encoding_type = 'replace'
478
668
 
479
669
    def run(self, location=None, remember=False, overwrite=False,
480
 
            create_prefix=False, verbose=False):
 
670
            create_prefix=False, verbose=False,
 
671
            use_existing_dir=False,
 
672
            directory=None):
481
673
        # FIXME: Way too big!  Put this into a function called from the
482
674
        # command.
483
 
        from bzrlib.transport import get_transport
484
 
        
485
 
        br_from = Branch.open_containing('.')[0]
 
675
        if directory is None:
 
676
            directory = '.'
 
677
        br_from = Branch.open_containing(directory)[0]
486
678
        stored_loc = br_from.get_push_location()
487
679
        if location is None:
488
680
            if stored_loc is None:
489
 
                raise BzrCommandError("No push location known or specified.")
 
681
                raise errors.BzrCommandError("No push location known or specified.")
490
682
            else:
491
 
                print "Using saved location: %s" % stored_loc
 
683
                display_url = urlutils.unescape_for_display(stored_loc,
 
684
                        self.outf.encoding)
 
685
                self.outf.write("Using saved location: %s\n" % display_url)
492
686
                location = stored_loc
493
 
        if br_from.get_push_location() is None or remember:
494
 
            br_from.set_push_location(location)
 
687
 
 
688
        to_transport = transport.get_transport(location)
 
689
        location_url = to_transport.base
 
690
 
 
691
        br_to = repository_to = dir_to = None
495
692
        try:
496
 
            dir_to = bzrlib.bzrdir.BzrDir.open(location)
497
 
            br_to = dir_to.open_branch()
498
 
        except NotBranchError:
499
 
            # create a branch.
500
 
            transport = get_transport(location).clone('..')
501
 
            if not create_prefix:
 
693
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
 
694
        except errors.NotBranchError:
 
695
            pass # Didn't find anything
 
696
        else:
 
697
            # If we can open a branch, use its direct repository, otherwise see
 
698
            # if there is a repository without a branch.
 
699
            try:
 
700
                br_to = dir_to.open_branch()
 
701
            except errors.NotBranchError:
 
702
                # Didn't find a branch, can we find a repository?
502
703
                try:
503
 
                    transport.mkdir(transport.relpath(location))
504
 
                except NoSuchFile:
505
 
                    raise BzrCommandError("Parent directory of %s "
506
 
                                          "does not exist." % location)
 
704
                    repository_to = dir_to.find_repository()
 
705
                except errors.NoRepositoryPresent:
 
706
                    pass
507
707
            else:
508
 
                current = transport.base
509
 
                needed = [(transport, transport.relpath(location))]
 
708
                # Found a branch, so we must have found a repository
 
709
                repository_to = br_to.repository
 
710
        push_result = None
 
711
        old_rh = []
 
712
        if dir_to is None:
 
713
            # The destination doesn't exist; create it.
 
714
            # XXX: Refactor the create_prefix/no_create_prefix code into a
 
715
            #      common helper function
 
716
            try:
 
717
                to_transport.mkdir('.')
 
718
            except errors.FileExists:
 
719
                if not use_existing_dir:
 
720
                    raise errors.BzrCommandError("Target directory %s"
 
721
                         " already exists, but does not have a valid .bzr"
 
722
                         " directory. Supply --use-existing-dir to push"
 
723
                         " there anyway." % location)
 
724
            except errors.NoSuchFile:
 
725
                if not create_prefix:
 
726
                    raise errors.BzrCommandError("Parent directory of %s"
 
727
                        " does not exist."
 
728
                        "\nYou may supply --create-prefix to create all"
 
729
                        " leading parent directories."
 
730
                        % location)
 
731
 
 
732
                cur_transport = to_transport
 
733
                needed = [cur_transport]
 
734
                # Recurse upwards until we can create a directory successfully
 
735
                while True:
 
736
                    new_transport = cur_transport.clone('..')
 
737
                    if new_transport.base == cur_transport.base:
 
738
                        raise errors.BzrCommandError("Failed to create path"
 
739
                                                     " prefix for %s."
 
740
                                                     % location)
 
741
                    try:
 
742
                        new_transport.mkdir('.')
 
743
                    except errors.NoSuchFile:
 
744
                        needed.append(new_transport)
 
745
                        cur_transport = new_transport
 
746
                    else:
 
747
                        break
 
748
 
 
749
                # Now we only need to create child directories
510
750
                while needed:
511
 
                    try:
512
 
                        transport, relpath = needed[-1]
513
 
                        transport.mkdir(relpath)
514
 
                        needed.pop()
515
 
                    except NoSuchFile:
516
 
                        new_transport = transport.clone('..')
517
 
                        needed.append((new_transport,
518
 
                                       new_transport.relpath(transport.base)))
519
 
                        if new_transport.base == transport.base:
520
 
                            raise BzrCommandError("Could not create "
521
 
                                                  "path prefix.")
522
 
            dir_to = br_from.bzrdir.clone(location,
 
751
                    cur_transport = needed.pop()
 
752
                    cur_transport.mkdir('.')
 
753
            
 
754
            # Now the target directory exists, but doesn't have a .bzr
 
755
            # directory. So we need to create it, along with any work to create
 
756
            # all of the dependent branches, etc.
 
757
            dir_to = br_from.bzrdir.clone(location_url,
523
758
                revision_id=br_from.last_revision())
524
759
            br_to = dir_to.open_branch()
525
 
            count = len(br_to.revision_history())
526
 
        else:
 
760
            # TODO: Some more useful message about what was copied
 
761
            note('Created new branch.')
 
762
            # We successfully created the target, remember it
 
763
            if br_from.get_push_location() is None or remember:
 
764
                br_from.set_push_location(br_to.base)
 
765
        elif repository_to is None:
 
766
            # we have a bzrdir but no branch or repository
 
767
            # XXX: Figure out what to do other than complain.
 
768
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
 
769
                " directory, but not a branch or repository. This is an"
 
770
                " unsupported configuration. Please move the target directory"
 
771
                " out of the way and try again."
 
772
                % location)
 
773
        elif br_to is None:
 
774
            # We have a repository but no branch, copy the revisions, and then
 
775
            # create a branch.
 
776
            last_revision_id = br_from.last_revision()
 
777
            repository_to.fetch(br_from.repository,
 
778
                                revision_id=last_revision_id)
 
779
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
 
780
            note('Created new branch.')
 
781
            if br_from.get_push_location() is None or remember:
 
782
                br_from.set_push_location(br_to.base)
 
783
        else: # We have a valid to branch
 
784
            # We were able to connect to the remote location, so remember it
 
785
            # we don't need to successfully push because of possible divergence.
 
786
            if br_from.get_push_location() is None or remember:
 
787
                br_from.set_push_location(br_to.base)
527
788
            old_rh = br_to.revision_history()
528
789
            try:
529
790
                try:
531
792
                except errors.NotLocalUrl:
532
793
                    warning('This transport does not update the working '
533
794
                            'tree of: %s' % (br_to.base,))
534
 
                    count = br_to.pull(br_from, overwrite)
535
 
                except NoWorkingTree:
536
 
                    count = br_to.pull(br_from, overwrite)
 
795
                    push_result = br_from.push(br_to, overwrite)
 
796
                except errors.NoWorkingTree:
 
797
                    push_result = br_from.push(br_to, overwrite)
537
798
                else:
538
 
                    count = tree_to.pull(br_from, overwrite)
539
 
            except DivergedBranches:
540
 
                raise BzrCommandError("These branches have diverged."
541
 
                                      "  Try a merge then push with overwrite.")
542
 
        note('%d revision(s) pushed.' % (count,))
543
 
 
544
 
        if verbose:
 
799
                    tree_to.lock_write()
 
800
                    try:
 
801
                        push_result = br_from.push(tree_to.branch, overwrite)
 
802
                        tree_to.update()
 
803
                    finally:
 
804
                        tree_to.unlock()
 
805
            except errors.DivergedBranches:
 
806
                raise errors.BzrCommandError('These branches have diverged.'
 
807
                                        '  Try using "merge" and then "push".')
 
808
        if push_result is not None:
 
809
            push_result.report(self.outf)
 
810
        elif verbose:
545
811
            new_rh = br_to.revision_history()
546
812
            if old_rh != new_rh:
547
813
                # Something changed
548
814
                from bzrlib.log import show_changed_revisions
549
 
                show_changed_revisions(br_to, old_rh, new_rh)
 
815
                show_changed_revisions(br_to, old_rh, new_rh,
 
816
                                       to_file=self.outf)
 
817
        else:
 
818
            # we probably did a clone rather than a push, so a message was
 
819
            # emitted above
 
820
            pass
550
821
 
551
822
 
552
823
class cmd_branch(Command):
567
838
    aliases = ['get', 'clone']
568
839
 
569
840
    def run(self, from_location, to_location=None, revision=None, basis=None):
570
 
        from bzrlib.osutils import rmtree
 
841
        from bzrlib.tag import _merge_tags_if_possible
571
842
        if revision is None:
572
843
            revision = [None]
573
844
        elif len(revision) > 1:
574
 
            raise BzrCommandError(
 
845
            raise errors.BzrCommandError(
575
846
                'bzr branch --revision takes exactly 1 revision value')
576
 
        try:
577
 
            br_from = Branch.open(from_location)
578
 
        except OSError, e:
579
 
            if e.errno == errno.ENOENT:
580
 
                raise BzrCommandError('Source location "%s" does not'
581
 
                                      ' exist.' % to_location)
582
 
            else:
583
 
                raise
 
847
 
 
848
        br_from = Branch.open(from_location)
584
849
        br_from.lock_read()
585
850
        try:
586
851
            if basis is not None:
599
864
                name = None
600
865
            else:
601
866
                name = os.path.basename(to_location) + '\n'
 
867
 
 
868
            to_transport = transport.get_transport(to_location)
602
869
            try:
603
 
                os.mkdir(to_location)
604
 
            except OSError, e:
605
 
                if e.errno == errno.EEXIST:
606
 
                    raise BzrCommandError('Target directory "%s" already'
607
 
                                          ' exists.' % to_location)
608
 
                if e.errno == errno.ENOENT:
609
 
                    raise BzrCommandError('Parent of "%s" does not exist.' %
610
 
                                          to_location)
611
 
                else:
612
 
                    raise
 
870
                to_transport.mkdir('.')
 
871
            except errors.FileExists:
 
872
                raise errors.BzrCommandError('Target directory "%s" already'
 
873
                                             ' exists.' % to_location)
 
874
            except errors.NoSuchFile:
 
875
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
876
                                             % to_location)
613
877
            try:
614
878
                # preserve whatever source format we have.
615
 
                dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
 
879
                dir = br_from.bzrdir.sprout(to_transport.base,
 
880
                        revision_id, basis_dir)
616
881
                branch = dir.open_branch()
617
 
            except bzrlib.errors.NoSuchRevision:
618
 
                rmtree(to_location)
 
882
            except errors.NoSuchRevision:
 
883
                to_transport.delete_tree('.')
619
884
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
620
 
                raise BzrCommandError(msg)
621
 
            except bzrlib.errors.UnlistableBranch:
622
 
                rmtree(to_location)
 
885
                raise errors.BzrCommandError(msg)
 
886
            except errors.UnlistableBranch:
 
887
                osutils.rmtree(to_location)
623
888
                msg = "The branch %s cannot be used as a --basis" % (basis,)
624
 
                raise BzrCommandError(msg)
 
889
                raise errors.BzrCommandError(msg)
625
890
            if name:
626
891
                branch.control_files.put_utf8('branch-name', name)
627
 
 
 
892
            _merge_tags_if_possible(br_from, branch)
628
893
            note('Branched %d revision(s).' % branch.revno())
629
894
        finally:
630
895
            br_from.unlock()
649
914
    --basis is to speed up checking out from remote branches.  When specified, it
650
915
    uses the inventory and file contents from the basis branch in preference to the
651
916
    branch being checked out.
 
917
 
 
918
    See "help checkouts" for more information on checkouts.
652
919
    """
653
920
    takes_args = ['branch_location?', 'to_location?']
654
921
    takes_options = ['revision', # , 'basis']
660
927
                                 "such access, and also support local commits."
661
928
                            ),
662
929
                     ]
 
930
    aliases = ['co']
663
931
 
664
932
    def run(self, branch_location=None, to_location=None, revision=None, basis=None,
665
933
            lightweight=False):
666
934
        if revision is None:
667
935
            revision = [None]
668
936
        elif len(revision) > 1:
669
 
            raise BzrCommandError(
 
937
            raise errors.BzrCommandError(
670
938
                'bzr checkout --revision takes exactly 1 revision value')
671
939
        if branch_location is None:
672
 
            branch_location = bzrlib.osutils.getcwd()
 
940
            branch_location = osutils.getcwd()
673
941
            to_location = branch_location
674
942
        source = Branch.open(branch_location)
675
943
        if len(revision) == 1 and revision[0] is not None:
681
949
        # if the source and to_location are the same, 
682
950
        # and there is no working tree,
683
951
        # then reconstitute a branch
684
 
        if (bzrlib.osutils.abspath(to_location) == 
685
 
            bzrlib.osutils.abspath(branch_location)):
 
952
        if (osutils.abspath(to_location) ==
 
953
            osutils.abspath(branch_location)):
686
954
            try:
687
955
                source.bzrdir.open_workingtree()
688
956
            except errors.NoWorkingTree:
692
960
            os.mkdir(to_location)
693
961
        except OSError, e:
694
962
            if e.errno == errno.EEXIST:
695
 
                raise BzrCommandError('Target directory "%s" already'
696
 
                                      ' exists.' % to_location)
 
963
                raise errors.BzrCommandError('Target directory "%s" already'
 
964
                                             ' exists.' % to_location)
697
965
            if e.errno == errno.ENOENT:
698
 
                raise BzrCommandError('Parent of "%s" does not exist.' %
699
 
                                      to_location)
 
966
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
967
                                             % to_location)
700
968
            else:
701
969
                raise
702
 
        old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
703
 
        bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
704
 
        try:
705
 
            if lightweight:
706
 
                checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
707
 
                bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
708
 
            else:
709
 
                checkout_branch =  bzrlib.bzrdir.BzrDir.create_branch_convenience(
710
 
                    to_location, force_new_tree=False)
711
 
                checkout = checkout_branch.bzrdir
712
 
                checkout_branch.bind(source)
713
 
                if revision_id is not None:
714
 
                    rh = checkout_branch.revision_history()
715
 
                    checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
716
 
            checkout.create_workingtree(revision_id)
717
 
        finally:
718
 
            bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
 
970
        source.create_checkout(to_location, revision_id, lightweight)
719
971
 
720
972
 
721
973
class cmd_renames(Command):
729
981
    @display_command
730
982
    def run(self, dir=u'.'):
731
983
        tree = WorkingTree.open_containing(dir)[0]
732
 
        old_inv = tree.basis_tree().inventory
733
 
        new_inv = tree.read_working_inventory()
734
 
 
735
 
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
736
 
        renames.sort()
737
 
        for old_name, new_name in renames:
738
 
            print "%s => %s" % (old_name, new_name)        
 
984
        tree.lock_read()
 
985
        try:
 
986
            new_inv = tree.inventory
 
987
            old_tree = tree.basis_tree()
 
988
            old_tree.lock_read()
 
989
            try:
 
990
                old_inv = old_tree.inventory
 
991
                renames = list(_mod_tree.find_renames(old_inv, new_inv))
 
992
                renames.sort()
 
993
                for old_name, new_name in renames:
 
994
                    self.outf.write("%s => %s\n" % (old_name, new_name))
 
995
            finally:
 
996
                old_tree.unlock()
 
997
        finally:
 
998
            tree.unlock()
739
999
 
740
1000
 
741
1001
class cmd_update(Command):
749
1009
    'bzr revert' instead of 'bzr commit' after the update.
750
1010
    """
751
1011
    takes_args = ['dir?']
 
1012
    aliases = ['up']
752
1013
 
753
1014
    def run(self, dir='.'):
754
1015
        tree = WorkingTree.open_containing(dir)[0]
755
 
        tree.lock_write()
 
1016
        master = tree.branch.get_master_branch()
 
1017
        if master is not None:
 
1018
            tree.lock_write()
 
1019
        else:
 
1020
            tree.lock_tree_write()
756
1021
        try:
757
 
            if tree.last_revision() == tree.branch.last_revision():
 
1022
            existing_pending_merges = tree.get_parent_ids()[1:]
 
1023
            last_rev = tree.last_revision()
 
1024
            if last_rev == tree.branch.last_revision():
758
1025
                # may be up to date, check master too.
759
1026
                master = tree.branch.get_master_branch()
760
 
                if master is None or master.last_revision == tree.last_revision():
761
 
                    note("Tree is up to date.")
762
 
                    return
 
1027
                if master is None or last_rev == master.last_revision():
 
1028
                    revno = tree.branch.revision_id_to_revno(last_rev)
 
1029
                    note("Tree is up to date at revision %d." % (revno,))
 
1030
                    return 0
763
1031
            conflicts = tree.update()
764
 
            note('Updated to revision %d.' %
765
 
                 (tree.branch.revision_id_to_revno(tree.last_revision()),))
 
1032
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
 
1033
            note('Updated to revision %d.' % (revno,))
 
1034
            if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1035
                note('Your local commits will now show as pending merges with '
 
1036
                     "'bzr status', and can be committed with 'bzr commit'.")
766
1037
            if conflicts != 0:
767
1038
                return 1
768
1039
            else:
804
1075
    takes_args = ['file*']
805
1076
    takes_options = ['verbose', Option('new', help='remove newly-added files')]
806
1077
    aliases = ['rm']
 
1078
    encoding_type = 'replace'
807
1079
    
808
1080
    def run(self, file_list, verbose=False, new=False):
809
1081
        tree, file_list = tree_files(file_list)
810
1082
        if new is False:
811
1083
            if file_list is None:
812
 
                raise BzrCommandError('Specify one or more files to remove, or'
813
 
                                      ' use --new.')
 
1084
                raise errors.BzrCommandError('Specify one or more files to'
 
1085
                                             ' remove, or use --new.')
814
1086
        else:
815
 
            from bzrlib.delta import compare_trees
816
 
            added = [compare_trees(tree.basis_tree(), tree,
817
 
                                   specific_files=file_list).added]
818
 
            file_list = sorted([f[0] for f in added[0]], reverse=True)
 
1087
            added = tree.changes_from(tree.basis_tree(),
 
1088
                specific_files=file_list).added
 
1089
            file_list = sorted([f[0] for f in added], reverse=True)
819
1090
            if len(file_list) == 0:
820
 
                raise BzrCommandError('No matching files.')
821
 
        tree.remove(file_list, verbose=verbose)
 
1091
                raise errors.BzrCommandError('No matching files.')
 
1092
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
822
1093
 
823
1094
 
824
1095
class cmd_file_id(Command):
828
1099
    same through all revisions where the file exists, even when it is
829
1100
    moved or renamed.
830
1101
    """
 
1102
 
831
1103
    hidden = True
832
1104
    takes_args = ['filename']
 
1105
 
833
1106
    @display_command
834
1107
    def run(self, filename):
835
1108
        tree, relpath = WorkingTree.open_containing(filename)
836
 
        i = tree.inventory.path2id(relpath)
837
 
        if i == None:
838
 
            raise BzrError("%r is not a versioned file" % filename)
 
1109
        i = tree.path2id(relpath)
 
1110
        if i is None:
 
1111
            raise errors.NotVersionedError(filename)
839
1112
        else:
840
 
            print i
 
1113
            self.outf.write(i + '\n')
841
1114
 
842
1115
 
843
1116
class cmd_file_path(Command):
844
1117
    """Print path of file_ids to a file or directory.
845
1118
 
846
1119
    This prints one line for each directory down to the target,
847
 
    starting at the branch root."""
 
1120
    starting at the branch root.
 
1121
    """
 
1122
 
848
1123
    hidden = True
849
1124
    takes_args = ['filename']
 
1125
 
850
1126
    @display_command
851
1127
    def run(self, filename):
852
1128
        tree, relpath = WorkingTree.open_containing(filename)
853
 
        inv = tree.inventory
854
 
        fid = inv.path2id(relpath)
855
 
        if fid == None:
856
 
            raise BzrError("%r is not a versioned file" % filename)
857
 
        for fip in inv.get_idpath(fid):
858
 
            print fip
 
1129
        fid = tree.path2id(relpath)
 
1130
        if fid is None:
 
1131
            raise errors.NotVersionedError(filename)
 
1132
        segments = osutils.splitpath(relpath)
 
1133
        for pos in range(1, len(segments) + 1):
 
1134
            path = osutils.joinpath(segments[:pos])
 
1135
            self.outf.write("%s\n" % tree.path2id(path))
859
1136
 
860
1137
 
861
1138
class cmd_reconcile(Command):
880
1157
 
881
1158
    def run(self, branch="."):
882
1159
        from bzrlib.reconcile import reconcile
883
 
        dir = bzrlib.bzrdir.BzrDir.open(branch)
 
1160
        dir = bzrdir.BzrDir.open(branch)
884
1161
        reconcile(dir)
885
1162
 
886
1163
 
887
1164
class cmd_revision_history(Command):
888
 
    """Display list of revision ids on this branch."""
 
1165
    """Display the list of revision ids on a branch."""
 
1166
    takes_args = ['location?']
 
1167
 
889
1168
    hidden = True
 
1169
 
890
1170
    @display_command
891
 
    def run(self):
892
 
        branch = WorkingTree.open_containing(u'.')[0].branch
893
 
        for patchid in branch.revision_history():
894
 
            print patchid
 
1171
    def run(self, location="."):
 
1172
        branch = Branch.open_containing(location)[0]
 
1173
        for revid in branch.revision_history():
 
1174
            self.outf.write(revid)
 
1175
            self.outf.write('\n')
895
1176
 
896
1177
 
897
1178
class cmd_ancestry(Command):
898
1179
    """List all revisions merged into this branch."""
 
1180
    takes_args = ['location?']
 
1181
 
899
1182
    hidden = True
 
1183
 
900
1184
    @display_command
901
 
    def run(self):
902
 
        tree = WorkingTree.open_containing(u'.')[0]
903
 
        b = tree.branch
904
 
        # FIXME. should be tree.last_revision
905
 
        revision_ids = b.repository.get_ancestry(b.last_revision())
906
 
        assert revision_ids[0] == None
 
1185
    def run(self, location="."):
 
1186
        try:
 
1187
            wt = WorkingTree.open_containing(location)[0]
 
1188
        except errors.NoWorkingTree:
 
1189
            b = Branch.open(location)
 
1190
            last_revision = b.last_revision()
 
1191
        else:
 
1192
            b = wt.branch
 
1193
            last_revision = wt.last_revision()
 
1194
 
 
1195
        revision_ids = b.repository.get_ancestry(last_revision)
 
1196
        assert revision_ids[0] is None
907
1197
        revision_ids.pop(0)
908
1198
        for revision_id in revision_ids:
909
 
            print revision_id
 
1199
            self.outf.write(revision_id + '\n')
910
1200
 
911
1201
 
912
1202
class cmd_init(Command):
932
1222
    """
933
1223
    takes_args = ['location?']
934
1224
    takes_options = [
935
 
                     Option('format', 
936
 
                            help='Specify a format for this branch. Current'
937
 
                                 ' formats are: default, knit, metaweave and'
938
 
                                 ' weave. Default is knit; metaweave and'
939
 
                                 ' weave are deprecated',
940
 
                            type=get_format_type),
941
 
                     ]
942
 
    def run(self, location=None, format=None):
943
 
        from bzrlib.branch import Branch
 
1225
         RegistryOption('format',
 
1226
                help='Specify a format for this branch. '
 
1227
                'See "help formats".',
 
1228
                registry=bzrdir.format_registry,
 
1229
                converter=bzrdir.format_registry.make_bzrdir,
 
1230
                value_switches=True,
 
1231
                title="Branch Format",
 
1232
                ),
 
1233
         Option('append-revisions-only',
 
1234
                help='Never change revnos or the existing log.'
 
1235
                '  Append revisions to it only.')
 
1236
         ]
 
1237
    def run(self, location=None, format=None, append_revisions_only=False):
944
1238
        if format is None:
945
 
            format = get_format_type('default')
 
1239
            format = bzrdir.format_registry.make_bzrdir('default')
946
1240
        if location is None:
947
1241
            location = u'.'
948
 
        else:
949
 
            # The path has to exist to initialize a
950
 
            # branch inside of it.
951
 
            # Just using os.mkdir, since I don't
952
 
            # believe that we want to create a bunch of
953
 
            # locations if the user supplies an extended path
954
 
            if not os.path.exists(location):
955
 
                os.mkdir(location)
 
1242
 
 
1243
        to_transport = transport.get_transport(location)
 
1244
 
 
1245
        # The path has to exist to initialize a
 
1246
        # branch inside of it.
 
1247
        # Just using os.mkdir, since I don't
 
1248
        # believe that we want to create a bunch of
 
1249
        # locations if the user supplies an extended path
 
1250
        # TODO: create-prefix
 
1251
        try:
 
1252
            to_transport.mkdir('.')
 
1253
        except errors.FileExists:
 
1254
            pass
 
1255
                    
956
1256
        try:
957
1257
            existing_bzrdir = bzrdir.BzrDir.open(location)
958
 
        except NotBranchError:
 
1258
        except errors.NotBranchError:
959
1259
            # really a NotBzrDir error...
960
 
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
 
1260
            branch = bzrdir.BzrDir.create_branch_convenience(to_transport.base,
 
1261
                                                             format=format)
961
1262
        else:
 
1263
            from bzrlib.transport.local import LocalTransport
962
1264
            if existing_bzrdir.has_branch():
963
 
                if existing_bzrdir.has_workingtree():
964
 
                    raise errors.AlreadyBranchError(location)
965
 
                else:
966
 
                    raise errors.BranchExistsWithoutWorkingTree(location)
 
1265
                if (isinstance(to_transport, LocalTransport)
 
1266
                    and not existing_bzrdir.has_workingtree()):
 
1267
                        raise errors.BranchExistsWithoutWorkingTree(location)
 
1268
                raise errors.AlreadyBranchError(location)
967
1269
            else:
968
 
                existing_bzrdir.create_branch()
 
1270
                branch = existing_bzrdir.create_branch()
969
1271
                existing_bzrdir.create_workingtree()
 
1272
        if append_revisions_only:
 
1273
            try:
 
1274
                branch.set_append_revisions_only(True)
 
1275
            except errors.UpgradeRequired:
 
1276
                raise errors.BzrCommandError('This branch format cannot be set'
 
1277
                    ' to append-revisions-only.  Try --experimental-branch6')
970
1278
 
971
1279
 
972
1280
class cmd_init_repository(Command):
983
1291
        cd trunk-checkout
984
1292
        (add files here)
985
1293
    """
986
 
    takes_args = ["location"] 
987
 
    takes_options = [Option('format', 
988
 
                            help='Specify a format for this repository.'
989
 
                                 ' Current formats are: default, knit,'
990
 
                                 ' metaweave and weave. Default is knit;'
991
 
                                 ' metaweave and weave are deprecated',
992
 
                            type=get_format_type),
 
1294
    takes_args = ["location"]
 
1295
    takes_options = [RegistryOption('format',
 
1296
                            help='Specify a format for this repository. See'
 
1297
                                 ' "bzr help formats" for details',
 
1298
                            registry=bzrdir.format_registry,
 
1299
                            converter=bzrdir.format_registry.make_bzrdir,
 
1300
                            value_switches=True, title='Repository format'),
993
1301
                     Option('trees',
994
1302
                             help='Allows branches in repository to have'
995
1303
                             ' a working tree')]
996
1304
    aliases = ["init-repo"]
997
1305
    def run(self, location, format=None, trees=False):
998
 
        from bzrlib.transport import get_transport
999
1306
        if format is None:
1000
 
            format = get_format_type('default')
1001
 
        transport = get_transport(location)
1002
 
        if not transport.has('.'):
1003
 
            transport.mkdir('')
1004
 
        newdir = format.initialize_on_transport(transport)
 
1307
            format = bzrdir.format_registry.make_bzrdir('default')
 
1308
 
 
1309
        if location is None:
 
1310
            location = '.'
 
1311
 
 
1312
        to_transport = transport.get_transport(location)
 
1313
        try:
 
1314
            to_transport.mkdir('.')
 
1315
        except errors.FileExists:
 
1316
            pass
 
1317
 
 
1318
        newdir = format.initialize_on_transport(to_transport)
1005
1319
        repo = newdir.create_repository(shared=True)
1006
1320
        repo.set_make_working_trees(trees)
1007
1321
 
1008
1322
 
1009
1323
class cmd_diff(Command):
1010
 
    """Show differences in working tree.
 
1324
    """Show differences in the working tree or between revisions.
1011
1325
    
1012
1326
    If files are listed, only the changes in those files are listed.
1013
1327
    Otherwise, all changes for the tree are listed.
1017
1331
 
1018
1332
    examples:
1019
1333
        bzr diff
 
1334
            Shows the difference in the working tree versus the last commit
1020
1335
        bzr diff -r1
 
1336
            Difference between the working tree and revision 1
1021
1337
        bzr diff -r1..2
 
1338
            Difference between revision 2 and revision 1
1022
1339
        bzr diff --diff-prefix old/:new/
 
1340
            Same as 'bzr diff' but prefix paths with old/ and new/
1023
1341
        bzr diff bzr.mine bzr.dev
 
1342
            Show the differences between the two working trees
1024
1343
        bzr diff foo.c
 
1344
            Show just the differences for 'foo.c'
1025
1345
    """
1026
1346
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
1027
1347
    #       or a graphical diff.
1033
1353
    #       deleted files.
1034
1354
 
1035
1355
    # TODO: This probably handles non-Unix newlines poorly.
1036
 
    
 
1356
 
1037
1357
    takes_args = ['file*']
1038
 
    takes_options = ['revision', 'diff-options', 'prefix']
 
1358
    takes_options = ['revision', 'diff-options',
 
1359
        Option('prefix', type=str,
 
1360
               short_name='p',
 
1361
               help='Set prefixes to added to old and new filenames, as '
 
1362
                    'two values separated by a colon.'),
 
1363
        ]
1039
1364
    aliases = ['di', 'dif']
 
1365
    encoding_type = 'exact'
1040
1366
 
1041
1367
    @display_command
1042
1368
    def run(self, revision=None, file_list=None, diff_options=None,
1050
1376
        elif prefix == '1':
1051
1377
            old_label = 'old/'
1052
1378
            new_label = 'new/'
1053
 
        else:
1054
 
            if not ':' in prefix:
1055
 
                 raise BzrError("--diff-prefix expects two values separated by a colon")
 
1379
        elif ':' in prefix:
1056
1380
            old_label, new_label = prefix.split(":")
 
1381
        else:
 
1382
            raise BzrCommandError(
 
1383
                "--prefix expects two values separated by a colon")
 
1384
 
 
1385
        if revision and len(revision) > 2:
 
1386
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
 
1387
                                         ' one or two revision specifiers')
1057
1388
        
1058
1389
        try:
1059
1390
            tree1, file_list = internal_tree_files(file_list)
1060
1391
            tree2 = None
1061
1392
            b = None
1062
1393
            b2 = None
1063
 
        except FileInWrongBranch:
 
1394
        except errors.FileInWrongBranch:
1064
1395
            if len(file_list) != 2:
1065
 
                raise BzrCommandError("Files are in different branches")
 
1396
                raise errors.BzrCommandError("Files are in different branches")
1066
1397
 
1067
1398
            tree1, file1 = WorkingTree.open_containing(file_list[0])
1068
1399
            tree2, file2 = WorkingTree.open_containing(file_list[1])
1069
1400
            if file1 != "" or file2 != "":
1070
1401
                # FIXME diff those two files. rbc 20051123
1071
 
                raise BzrCommandError("Files are in different branches")
 
1402
                raise errors.BzrCommandError("Files are in different branches")
1072
1403
            file_list = None
1073
 
        if revision is not None:
1074
 
            if tree2 is not None:
1075
 
                raise BzrCommandError("Can't specify -r with two branches")
1076
 
            if (len(revision) == 1) or (revision[1].spec is None):
1077
 
                return diff_cmd_helper(tree1, file_list, diff_options,
1078
 
                                       revision[0], 
1079
 
                                       old_label=old_label, new_label=new_label)
1080
 
            elif len(revision) == 2:
1081
 
                return diff_cmd_helper(tree1, file_list, diff_options,
1082
 
                                       revision[0], revision[1],
1083
 
                                       old_label=old_label, new_label=new_label)
1084
 
            else:
1085
 
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
1086
 
        else:
1087
 
            if tree2 is not None:
1088
 
                return show_diff_trees(tree1, tree2, sys.stdout, 
1089
 
                                       specific_files=file_list,
1090
 
                                       external_diff_options=diff_options,
1091
 
                                       old_label=old_label, new_label=new_label)
1092
 
            else:
1093
 
                return diff_cmd_helper(tree1, file_list, diff_options,
1094
 
                                       old_label=old_label, new_label=new_label)
 
1404
        except errors.NotBranchError:
 
1405
            if (revision is not None and len(revision) == 2
 
1406
                and not revision[0].needs_branch()
 
1407
                and not revision[1].needs_branch()):
 
1408
                # If both revision specs include a branch, we can
 
1409
                # diff them without needing a local working tree
 
1410
                tree1, tree2 = None, None
 
1411
            else:
 
1412
                raise
 
1413
 
 
1414
        if tree2 is not None:
 
1415
            if revision is not None:
 
1416
                # FIXME: but there should be a clean way to diff between
 
1417
                # non-default versions of two trees, it's not hard to do
 
1418
                # internally...
 
1419
                raise errors.BzrCommandError(
 
1420
                        "Sorry, diffing arbitrary revisions across branches "
 
1421
                        "is not implemented yet")
 
1422
            return show_diff_trees(tree1, tree2, sys.stdout, 
 
1423
                                   specific_files=file_list,
 
1424
                                   external_diff_options=diff_options,
 
1425
                                   old_label=old_label, new_label=new_label)
 
1426
 
 
1427
        return diff_cmd_helper(tree1, file_list, diff_options,
 
1428
                               revision_specs=revision,
 
1429
                               old_label=old_label, new_label=new_label)
1095
1430
 
1096
1431
 
1097
1432
class cmd_deleted(Command):
1103
1438
    # directories with readdir, rather than stating each one.  Same
1104
1439
    # level of effort but possibly much less IO.  (Or possibly not,
1105
1440
    # if the directories are very large...)
 
1441
    takes_options = ['show-ids']
 
1442
 
1106
1443
    @display_command
1107
1444
    def run(self, show_ids=False):
1108
1445
        tree = WorkingTree.open_containing(u'.')[0]
1109
 
        old = tree.basis_tree()
1110
 
        for path, ie in old.inventory.iter_entries():
1111
 
            if not tree.has_id(ie.file_id):
1112
 
                if show_ids:
1113
 
                    print '%-50s %s' % (path, ie.file_id)
1114
 
                else:
1115
 
                    print path
 
1446
        tree.lock_read()
 
1447
        try:
 
1448
            old = tree.basis_tree()
 
1449
            old.lock_read()
 
1450
            try:
 
1451
                for path, ie in old.inventory.iter_entries():
 
1452
                    if not tree.has_id(ie.file_id):
 
1453
                        self.outf.write(path)
 
1454
                        if show_ids:
 
1455
                            self.outf.write(' ')
 
1456
                            self.outf.write(ie.file_id)
 
1457
                        self.outf.write('\n')
 
1458
            finally:
 
1459
                old.unlock()
 
1460
        finally:
 
1461
            tree.unlock()
1116
1462
 
1117
1463
 
1118
1464
class cmd_modified(Command):
1119
 
    """List files modified in working tree."""
 
1465
    """List files modified in working tree.
 
1466
 
 
1467
    See also: "bzr status".
 
1468
    """
 
1469
 
1120
1470
    hidden = True
 
1471
 
1121
1472
    @display_command
1122
1473
    def run(self):
1123
 
        from bzrlib.delta import compare_trees
1124
 
 
1125
1474
        tree = WorkingTree.open_containing(u'.')[0]
1126
 
        td = compare_trees(tree.basis_tree(), tree)
1127
 
 
 
1475
        td = tree.changes_from(tree.basis_tree())
1128
1476
        for path, id, kind, text_modified, meta_modified in td.modified:
1129
 
            print path
1130
 
 
 
1477
            self.outf.write(path + '\n')
1131
1478
 
1132
1479
 
1133
1480
class cmd_added(Command):
1134
 
    """List files added in working tree."""
 
1481
    """List files added in working tree.
 
1482
 
 
1483
    See also: "bzr status".
 
1484
    """
 
1485
 
1135
1486
    hidden = True
 
1487
 
1136
1488
    @display_command
1137
1489
    def run(self):
1138
1490
        wt = WorkingTree.open_containing(u'.')[0]
1139
 
        basis_inv = wt.basis_tree().inventory
1140
 
        inv = wt.inventory
1141
 
        for file_id in inv:
1142
 
            if file_id in basis_inv:
1143
 
                continue
1144
 
            path = inv.id2path(file_id)
1145
 
            if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
1146
 
                continue
1147
 
            print path
1148
 
                
1149
 
        
 
1491
        wt.lock_read()
 
1492
        try:
 
1493
            basis = wt.basis_tree()
 
1494
            basis.lock_read()
 
1495
            try:
 
1496
                basis_inv = basis.inventory
 
1497
                inv = wt.inventory
 
1498
                for file_id in inv:
 
1499
                    if file_id in basis_inv:
 
1500
                        continue
 
1501
                    if inv.is_root(file_id) and len(basis_inv) == 0:
 
1502
                        continue
 
1503
                    path = inv.id2path(file_id)
 
1504
                    if not os.access(osutils.abspath(path), os.F_OK):
 
1505
                        continue
 
1506
                    self.outf.write(path + '\n')
 
1507
            finally:
 
1508
                basis.unlock()
 
1509
        finally:
 
1510
            wt.unlock()
 
1511
 
1150
1512
 
1151
1513
class cmd_root(Command):
1152
1514
    """Show the tree root directory.
1158
1520
    def run(self, filename=None):
1159
1521
        """Print the branch root."""
1160
1522
        tree = WorkingTree.open_containing(filename)[0]
1161
 
        print tree.basedir
 
1523
        self.outf.write(tree.basedir + '\n')
1162
1524
 
1163
1525
 
1164
1526
class cmd_log(Command):
1183
1545
                            help='show from oldest to newest'),
1184
1546
                     'timezone', 
1185
1547
                     Option('verbose', 
 
1548
                             short_name='v',
1186
1549
                             help='show files changed in each revision'),
1187
1550
                     'show-ids', 'revision',
1188
1551
                     'log-format',
1189
 
                     'line', 'long', 
1190
1552
                     Option('message',
 
1553
                            short_name='m',
1191
1554
                            help='show revisions whose message matches this regexp',
1192
1555
                            type=str),
1193
 
                     'short',
1194
1556
                     ]
 
1557
    encoding_type = 'replace'
 
1558
 
1195
1559
    @display_command
1196
1560
    def run(self, location=None, timezone='original',
1197
1561
            verbose=False,
1199
1563
            forward=False,
1200
1564
            revision=None,
1201
1565
            log_format=None,
1202
 
            message=None,
1203
 
            long=False,
1204
 
            short=False,
1205
 
            line=False):
1206
 
        from bzrlib.log import log_formatter, show_log
1207
 
        import codecs
 
1566
            message=None):
 
1567
        from bzrlib.log import show_log
1208
1568
        assert message is None or isinstance(message, basestring), \
1209
1569
            "invalid message argument %r" % message
1210
1570
        direction = (forward and 'forward') or 'reverse'
1214
1574
        if location:
1215
1575
            # find the file id to log:
1216
1576
 
1217
 
            dir, fp = bzrdir.BzrDir.open_containing(location)
1218
 
            b = dir.open_branch()
 
1577
            tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
 
1578
                location)
1219
1579
            if fp != '':
1220
 
                try:
1221
 
                    # might be a tree:
1222
 
                    inv = dir.open_workingtree().inventory
1223
 
                except (errors.NotBranchError, errors.NotLocalUrl):
1224
 
                    # either no tree, or is remote.
1225
 
                    inv = b.basis_tree().inventory
1226
 
                file_id = inv.path2id(fp)
 
1580
                if tree is None:
 
1581
                    tree = b.basis_tree()
 
1582
                file_id = tree.path2id(fp)
 
1583
                if file_id is None:
 
1584
                    raise errors.BzrCommandError(
 
1585
                        "Path does not have any revision history: %s" %
 
1586
                        location)
1227
1587
        else:
1228
1588
            # local dir only
1229
1589
            # FIXME ? log the current subdir only RBC 20060203 
1230
 
            dir, relpath = bzrdir.BzrDir.open_containing('.')
 
1590
            if revision is not None \
 
1591
                    and len(revision) > 0 and revision[0].get_branch():
 
1592
                location = revision[0].get_branch()
 
1593
            else:
 
1594
                location = '.'
 
1595
            dir, relpath = bzrdir.BzrDir.open_containing(location)
1231
1596
            b = dir.open_branch()
1232
1597
 
1233
 
        if revision is None:
1234
 
            rev1 = None
1235
 
            rev2 = None
1236
 
        elif len(revision) == 1:
1237
 
            rev1 = rev2 = revision[0].in_history(b).revno
1238
 
        elif len(revision) == 2:
1239
 
            if revision[0].spec is None:
1240
 
                # missing begin-range means first revision
1241
 
                rev1 = 1
1242
 
            else:
1243
 
                rev1 = revision[0].in_history(b).revno
1244
 
 
1245
 
            if revision[1].spec is None:
1246
 
                # missing end-range means last known revision
1247
 
                rev2 = b.revno()
1248
 
            else:
1249
 
                rev2 = revision[1].in_history(b).revno
1250
 
        else:
1251
 
            raise BzrCommandError('bzr log --revision takes one or two values.')
1252
 
 
1253
 
        # By this point, the revision numbers are converted to the +ve
1254
 
        # form if they were supplied in the -ve form, so we can do
1255
 
        # this comparison in relative safety
1256
 
        if rev1 > rev2:
1257
 
            (rev2, rev1) = (rev1, rev2)
1258
 
 
1259
 
        mutter('encoding log as %r', bzrlib.user_encoding)
1260
 
 
1261
 
        # use 'replace' so that we don't abort if trying to write out
1262
 
        # in e.g. the default C locale.
1263
 
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1264
 
 
1265
 
        if (log_format == None):
1266
 
            default = bzrlib.config.BranchConfig(b).log_format()
1267
 
            log_format = get_log_format(long=long, short=short, line=line, default=default)
1268
 
 
1269
 
        lf = log_formatter(log_format,
1270
 
                           show_ids=show_ids,
1271
 
                           to_file=outf,
1272
 
                           show_timezone=timezone)
1273
 
 
1274
 
        show_log(b,
1275
 
                 lf,
1276
 
                 file_id,
1277
 
                 verbose=verbose,
1278
 
                 direction=direction,
1279
 
                 start_revision=rev1,
1280
 
                 end_revision=rev2,
1281
 
                 search=message)
 
1598
        b.lock_read()
 
1599
        try:
 
1600
            if revision is None:
 
1601
                rev1 = None
 
1602
                rev2 = None
 
1603
            elif len(revision) == 1:
 
1604
                rev1 = rev2 = revision[0].in_history(b).revno
 
1605
            elif len(revision) == 2:
 
1606
                if revision[1].get_branch() != revision[0].get_branch():
 
1607
                    # b is taken from revision[0].get_branch(), and
 
1608
                    # show_log will use its revision_history. Having
 
1609
                    # different branches will lead to weird behaviors.
 
1610
                    raise errors.BzrCommandError(
 
1611
                        "Log doesn't accept two revisions in different"
 
1612
                        " branches.")
 
1613
                if revision[0].spec is None:
 
1614
                    # missing begin-range means first revision
 
1615
                    rev1 = 1
 
1616
                else:
 
1617
                    rev1 = revision[0].in_history(b).revno
 
1618
 
 
1619
                if revision[1].spec is None:
 
1620
                    # missing end-range means last known revision
 
1621
                    rev2 = b.revno()
 
1622
                else:
 
1623
                    rev2 = revision[1].in_history(b).revno
 
1624
            else:
 
1625
                raise errors.BzrCommandError(
 
1626
                    'bzr log --revision takes one or two values.')
 
1627
 
 
1628
            # By this point, the revision numbers are converted to the +ve
 
1629
            # form if they were supplied in the -ve form, so we can do
 
1630
            # this comparison in relative safety
 
1631
            if rev1 > rev2:
 
1632
                (rev2, rev1) = (rev1, rev2)
 
1633
 
 
1634
            if log_format is None:
 
1635
                log_format = log.log_formatter_registry.get_default(b)
 
1636
 
 
1637
            lf = log_format(show_ids=show_ids, to_file=self.outf,
 
1638
                            show_timezone=timezone)
 
1639
 
 
1640
            show_log(b,
 
1641
                     lf,
 
1642
                     file_id,
 
1643
                     verbose=verbose,
 
1644
                     direction=direction,
 
1645
                     start_revision=rev1,
 
1646
                     end_revision=rev2,
 
1647
                     search=message)
 
1648
        finally:
 
1649
            b.unlock()
1282
1650
 
1283
1651
 
1284
1652
def get_log_format(long=False, short=False, line=False, default='long'):
1295
1663
class cmd_touching_revisions(Command):
1296
1664
    """Return revision-ids which affected a particular file.
1297
1665
 
1298
 
    A more user-friendly interface is "bzr log FILE"."""
 
1666
    A more user-friendly interface is "bzr log FILE".
 
1667
    """
 
1668
 
1299
1669
    hidden = True
1300
1670
    takes_args = ["filename"]
 
1671
 
1301
1672
    @display_command
1302
1673
    def run(self, filename):
1303
1674
        tree, relpath = WorkingTree.open_containing(filename)
1304
1675
        b = tree.branch
1305
 
        inv = tree.read_working_inventory()
1306
 
        file_id = inv.path2id(relpath)
1307
 
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1308
 
            print "%6d %s" % (revno, what)
 
1676
        file_id = tree.path2id(relpath)
 
1677
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
1678
            self.outf.write("%6d %s\n" % (revno, what))
1309
1679
 
1310
1680
 
1311
1681
class cmd_ls(Command):
1312
1682
    """List files in a tree.
1313
1683
    """
 
1684
 
 
1685
    takes_args = ['path?']
1314
1686
    # TODO: Take a revision or remote path and list that tree instead.
1315
 
    hidden = True
1316
1687
    takes_options = ['verbose', 'revision',
1317
1688
                     Option('non-recursive',
1318
1689
                            help='don\'t recurse into sub-directories'),
1323
1694
                     Option('ignored', help='Print ignored files'),
1324
1695
 
1325
1696
                     Option('null', help='Null separate the files'),
 
1697
                     'kind', 'show-ids'
1326
1698
                    ]
1327
1699
    @display_command
1328
1700
    def run(self, revision=None, verbose=False, 
1329
1701
            non_recursive=False, from_root=False,
1330
1702
            unknown=False, versioned=False, ignored=False,
1331
 
            null=False):
 
1703
            null=False, kind=None, show_ids=False, path=None):
 
1704
 
 
1705
        if kind and kind not in ('file', 'directory', 'symlink'):
 
1706
            raise errors.BzrCommandError('invalid kind specified')
1332
1707
 
1333
1708
        if verbose and null:
1334
 
            raise BzrCommandError('Cannot set both --verbose and --null')
 
1709
            raise errors.BzrCommandError('Cannot set both --verbose and --null')
1335
1710
        all = not (unknown or versioned or ignored)
1336
1711
 
1337
1712
        selection = {'I':ignored, '?':unknown, 'V':versioned}
1338
1713
 
1339
 
        tree, relpath = WorkingTree.open_containing(u'.')
 
1714
        if path is None:
 
1715
            fs_path = '.'
 
1716
            prefix = ''
 
1717
        else:
 
1718
            if from_root:
 
1719
                raise errors.BzrCommandError('cannot specify both --from-root'
 
1720
                                             ' and PATH')
 
1721
            fs_path = path
 
1722
            prefix = path
 
1723
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
1724
            fs_path)
1340
1725
        if from_root:
1341
1726
            relpath = u''
1342
1727
        elif relpath:
1343
1728
            relpath += '/'
1344
1729
        if revision is not None:
1345
 
            tree = tree.branch.repository.revision_tree(
1346
 
                revision[0].in_history(tree.branch).rev_id)
1347
 
        for fp, fc, kind, fid, entry in tree.list_files():
1348
 
            if fp.startswith(relpath):
1349
 
                fp = fp[len(relpath):]
1350
 
                if non_recursive and '/' in fp:
1351
 
                    continue
1352
 
                if not all and not selection[fc]:
1353
 
                    continue
1354
 
                if verbose:
1355
 
                    kindch = entry.kind_character()
1356
 
                    print '%-8s %s%s' % (fc, fp, kindch)
1357
 
                elif null:
1358
 
                    sys.stdout.write(fp)
1359
 
                    sys.stdout.write('\0')
1360
 
                    sys.stdout.flush()
1361
 
                else:
1362
 
                    print fp
 
1730
            tree = branch.repository.revision_tree(
 
1731
                revision[0].in_history(branch).rev_id)
 
1732
        elif tree is None:
 
1733
            tree = branch.basis_tree()
 
1734
 
 
1735
        tree.lock_read()
 
1736
        try:
 
1737
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
 
1738
                if fp.startswith(relpath):
 
1739
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
 
1740
                    if non_recursive and '/' in fp:
 
1741
                        continue
 
1742
                    if not all and not selection[fc]:
 
1743
                        continue
 
1744
                    if kind is not None and fkind != kind:
 
1745
                        continue
 
1746
                    if verbose:
 
1747
                        kindch = entry.kind_character()
 
1748
                        outstring = '%-8s %s%s' % (fc, fp, kindch)
 
1749
                        if show_ids and fid is not None:
 
1750
                            outstring = "%-50s %s" % (outstring, fid)
 
1751
                        self.outf.write(outstring + '\n')
 
1752
                    elif null:
 
1753
                        self.outf.write(fp + '\0')
 
1754
                        if show_ids:
 
1755
                            if fid is not None:
 
1756
                                self.outf.write(fid)
 
1757
                            self.outf.write('\0')
 
1758
                        self.outf.flush()
 
1759
                    else:
 
1760
                        if fid is not None:
 
1761
                            my_id = fid
 
1762
                        else:
 
1763
                            my_id = ''
 
1764
                        if show_ids:
 
1765
                            self.outf.write('%-50s %s\n' % (fp, my_id))
 
1766
                        else:
 
1767
                            self.outf.write(fp + '\n')
 
1768
        finally:
 
1769
            tree.unlock()
1363
1770
 
1364
1771
 
1365
1772
class cmd_unknowns(Command):
1366
 
    """List unknown files."""
 
1773
    """List unknown files.
 
1774
 
 
1775
    See also: "bzr ls --unknown".
 
1776
    """
 
1777
 
 
1778
    hidden = True
 
1779
 
1367
1780
    @display_command
1368
1781
    def run(self):
1369
 
        from bzrlib.osutils import quotefn
1370
1782
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1371
 
            print quotefn(f)
 
1783
            self.outf.write(osutils.quotefn(f) + '\n')
1372
1784
 
1373
1785
 
1374
1786
class cmd_ignore(Command):
1375
 
    """Ignore a command or pattern.
 
1787
    """Ignore specified files or patterns.
1376
1788
 
1377
1789
    To remove patterns from the ignore list, edit the .bzrignore file.
1378
1790
 
1379
 
    If the pattern contains a slash, it is compared to the whole path
1380
 
    from the branch root.  Otherwise, it is compared to only the last
1381
 
    component of the path.  To match a file only in the root directory,
1382
 
    prepend './'.
1383
 
 
1384
 
    Ignore patterns are case-insensitive on case-insensitive systems.
1385
 
 
1386
 
    Note: wildcards must be quoted from the shell on Unix.
 
1791
    Trailing slashes on patterns are ignored. 
 
1792
    If the pattern contains a slash or is a regular expression, it is compared 
 
1793
    to the whole path from the branch root.  Otherwise, it is compared to only
 
1794
    the last component of the path.  To match a file only in the root 
 
1795
    directory, prepend './'.
 
1796
 
 
1797
    Ignore patterns specifying absolute paths are not allowed.
 
1798
 
 
1799
    Ignore patterns may include globbing wildcards such as:
 
1800
      ? - Matches any single character except '/'
 
1801
      * - Matches 0 or more characters except '/'
 
1802
      /**/ - Matches 0 or more directories in a path
 
1803
      [a-z] - Matches a single character from within a group of characters
 
1804
 
 
1805
    Ignore patterns may also be Python regular expressions.  
 
1806
    Regular expression ignore patterns are identified by a 'RE:' prefix 
 
1807
    followed by the regular expression.  Regular expression ignore patterns
 
1808
    may not include named or numbered groups.
 
1809
 
 
1810
    Note: ignore patterns containing shell wildcards must be quoted from 
 
1811
    the shell on Unix.
1387
1812
 
1388
1813
    examples:
1389
1814
        bzr ignore ./Makefile
1390
1815
        bzr ignore '*.class'
 
1816
        bzr ignore 'lib/**/*.o'
 
1817
        bzr ignore 'RE:lib/.*\.o'
1391
1818
    """
1392
 
    # TODO: Complain if the filename is absolute
1393
 
    takes_args = ['name_pattern']
 
1819
    takes_args = ['name_pattern*']
 
1820
    takes_options = [
 
1821
                     Option('old-default-rules',
 
1822
                            help='Out the ignore rules bzr < 0.9 always used.')
 
1823
                     ]
1394
1824
    
1395
 
    def run(self, name_pattern):
 
1825
    def run(self, name_pattern_list=None, old_default_rules=None):
1396
1826
        from bzrlib.atomicfile import AtomicFile
1397
 
        import os.path
1398
 
 
 
1827
        if old_default_rules is not None:
 
1828
            # dump the rules and exit
 
1829
            for pattern in ignores.OLD_DEFAULTS:
 
1830
                print pattern
 
1831
            return
 
1832
        if not name_pattern_list:
 
1833
            raise errors.BzrCommandError("ignore requires at least one "
 
1834
                                  "NAME_PATTERN or --old-default-rules")
 
1835
        name_pattern_list = [globbing.normalize_pattern(p) 
 
1836
                             for p in name_pattern_list]
 
1837
        for name_pattern in name_pattern_list:
 
1838
            if (name_pattern[0] == '/' or 
 
1839
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
 
1840
                raise errors.BzrCommandError(
 
1841
                    "NAME_PATTERN should not be an absolute path")
1399
1842
        tree, relpath = WorkingTree.open_containing(u'.')
1400
1843
        ifn = tree.abspath('.bzrignore')
1401
 
 
1402
1844
        if os.path.exists(ifn):
1403
1845
            f = open(ifn, 'rt')
1404
1846
            try:
1413
1855
 
1414
1856
        if igns and igns[-1] != '\n':
1415
1857
            igns += '\n'
1416
 
        igns += name_pattern + '\n'
 
1858
        for name_pattern in name_pattern_list:
 
1859
            igns += name_pattern + '\n'
1417
1860
 
1418
 
        f = AtomicFile(ifn, 'wt')
 
1861
        f = AtomicFile(ifn, 'wb')
1419
1862
        try:
1420
1863
            f.write(igns.encode('utf-8'))
1421
1864
            f.commit()
1422
1865
        finally:
1423
1866
            f.close()
1424
1867
 
1425
 
        inv = tree.inventory
1426
 
        if inv.path2id('.bzrignore'):
1427
 
            mutter('.bzrignore is already versioned')
1428
 
        else:
1429
 
            mutter('need to make new .bzrignore file versioned')
 
1868
        if not tree.path2id('.bzrignore'):
1430
1869
            tree.add(['.bzrignore'])
1431
1870
 
1432
1871
 
1437
1876
    @display_command
1438
1877
    def run(self):
1439
1878
        tree = WorkingTree.open_containing(u'.')[0]
1440
 
        for path, file_class, kind, file_id, entry in tree.list_files():
1441
 
            if file_class != 'I':
1442
 
                continue
1443
 
            ## XXX: Slightly inefficient since this was already calculated
1444
 
            pat = tree.is_ignored(path)
1445
 
            print '%-50s %s' % (path, pat)
 
1879
        tree.lock_read()
 
1880
        try:
 
1881
            for path, file_class, kind, file_id, entry in tree.list_files():
 
1882
                if file_class != 'I':
 
1883
                    continue
 
1884
                ## XXX: Slightly inefficient since this was already calculated
 
1885
                pat = tree.is_ignored(path)
 
1886
                print '%-50s %s' % (path, pat)
 
1887
        finally:
 
1888
            tree.unlock()
1446
1889
 
1447
1890
 
1448
1891
class cmd_lookup_revision(Command):
1459
1902
        try:
1460
1903
            revno = int(revno)
1461
1904
        except ValueError:
1462
 
            raise BzrCommandError("not a valid revision-number: %r" % revno)
 
1905
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
1463
1906
 
1464
1907
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1465
1908
 
1476
1919
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1477
1920
    is given, the top directory will be the root name of the file.
1478
1921
 
 
1922
    If branch is omitted then the branch containing the CWD will be used.
 
1923
 
1479
1924
    Note: export of tree with non-ascii filenames to zip is not supported.
1480
1925
 
1481
1926
     Supported formats       Autodetected by extension
1486
1931
         tgz                      .tar.gz, .tgz
1487
1932
         zip                          .zip
1488
1933
    """
1489
 
    takes_args = ['dest']
 
1934
    takes_args = ['dest', 'branch?']
1490
1935
    takes_options = ['revision', 'format', 'root']
1491
 
    def run(self, dest, revision=None, format=None, root=None):
1492
 
        import os.path
 
1936
    def run(self, dest, branch=None, revision=None, format=None, root=None):
1493
1937
        from bzrlib.export import export
1494
 
        tree = WorkingTree.open_containing(u'.')[0]
1495
 
        b = tree.branch
 
1938
 
 
1939
        if branch is None:
 
1940
            tree = WorkingTree.open_containing(u'.')[0]
 
1941
            b = tree.branch
 
1942
        else:
 
1943
            b = Branch.open(branch)
 
1944
            
1496
1945
        if revision is None:
1497
1946
            # should be tree.last_revision  FIXME
1498
1947
            rev_id = b.last_revision()
1499
1948
        else:
1500
1949
            if len(revision) != 1:
1501
 
                raise BzrError('bzr export --revision takes exactly 1 argument')
 
1950
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
1502
1951
            rev_id = revision[0].in_history(b).rev_id
1503
1952
        t = b.repository.revision_tree(rev_id)
1504
1953
        try:
1505
1954
            export(t, dest, format, root)
1506
1955
        except errors.NoSuchExportFormat, e:
1507
 
            raise BzrCommandError('Unsupported export format: %s' % e.format)
 
1956
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
1508
1957
 
1509
1958
 
1510
1959
class cmd_cat(Command):
1511
1960
    """Write a file's text from a previous revision."""
1512
1961
 
1513
 
    takes_options = ['revision']
 
1962
    takes_options = ['revision', 'name-from-revision']
1514
1963
    takes_args = ['filename']
 
1964
    encoding_type = 'exact'
1515
1965
 
1516
1966
    @display_command
1517
 
    def run(self, filename, revision=None):
 
1967
    def run(self, filename, revision=None, name_from_revision=False):
1518
1968
        if revision is not None and len(revision) != 1:
1519
 
            raise BzrCommandError("bzr cat --revision takes exactly one number")
 
1969
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
 
1970
                                        " one number")
 
1971
 
1520
1972
        tree = None
1521
1973
        try:
1522
 
            tree, relpath = WorkingTree.open_containing(filename)
1523
 
            b = tree.branch
1524
 
        except NotBranchError:
 
1974
            tree, b, relpath = \
 
1975
                    bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
1976
        except errors.NotBranchError:
1525
1977
            pass
1526
1978
 
 
1979
        if revision is not None and revision[0].get_branch() is not None:
 
1980
            b = Branch.open(revision[0].get_branch())
1527
1981
        if tree is None:
1528
 
            b, relpath = Branch.open_containing(filename)
 
1982
            tree = b.basis_tree()
1529
1983
        if revision is None:
1530
1984
            revision_id = b.last_revision()
1531
1985
        else:
1532
1986
            revision_id = revision[0].in_history(b).rev_id
1533
 
        b.print_file(relpath, revision_id)
 
1987
 
 
1988
        cur_file_id = tree.path2id(relpath)
 
1989
        rev_tree = b.repository.revision_tree(revision_id)
 
1990
        old_file_id = rev_tree.path2id(relpath)
 
1991
        
 
1992
        if name_from_revision:
 
1993
            if old_file_id is None:
 
1994
                raise errors.BzrCommandError("%r is not present in revision %s"
 
1995
                                                % (filename, revision_id))
 
1996
            else:
 
1997
                rev_tree.print_file(old_file_id)
 
1998
        elif cur_file_id is not None:
 
1999
            rev_tree.print_file(cur_file_id)
 
2000
        elif old_file_id is not None:
 
2001
            rev_tree.print_file(old_file_id)
 
2002
        else:
 
2003
            raise errors.BzrCommandError("%r is not present in revision %s" %
 
2004
                                         (filename, revision_id))
1534
2005
 
1535
2006
 
1536
2007
class cmd_local_time_offset(Command):
1538
2009
    hidden = True    
1539
2010
    @display_command
1540
2011
    def run(self):
1541
 
        print bzrlib.osutils.local_time_offset()
 
2012
        print osutils.local_time_offset()
1542
2013
 
1543
2014
 
1544
2015
 
1569
2040
                     Option('unchanged',
1570
2041
                            help='commit even if nothing has changed'),
1571
2042
                     Option('file', type=str, 
 
2043
                            short_name='F',
1572
2044
                            argname='msgfile',
1573
2045
                            help='file containing commit message'),
1574
2046
                     Option('strict',
1590
2062
                StrictCommitFailed)
1591
2063
        from bzrlib.msgeditor import edit_commit_message, \
1592
2064
                make_commit_message_template
1593
 
        from tempfile import TemporaryFile
1594
 
        import codecs
1595
2065
 
1596
2066
        # TODO: Need a blackbox test for invoking the external editor; may be
1597
2067
        # slightly problematic to run this cross-platform.
1598
2068
 
1599
2069
        # TODO: do more checks that the commit will succeed before 
1600
2070
        # spending the user's valuable time typing a commit message.
1601
 
        #
1602
 
        # TODO: if the commit *does* happen to fail, then save the commit 
1603
 
        # message to a temporary file where it can be recovered
1604
2071
        tree, selected_list = tree_files(selected_list)
1605
2072
        if selected_list == ['']:
1606
2073
            # workaround - commit of root of tree should be exactly the same
1610
2077
 
1611
2078
        if local and not tree.branch.get_bound_location():
1612
2079
            raise errors.LocalRequiresBoundBranch()
1613
 
        if message is None and not file:
1614
 
            template = make_commit_message_template(tree, selected_list)
1615
 
            message = edit_commit_message(template)
1616
 
            if message is None:
1617
 
                raise BzrCommandError("please specify a commit message"
1618
 
                                      " with either --message or --file")
1619
 
        elif message and file:
1620
 
            raise BzrCommandError("please specify either --message or --file")
1621
 
        
1622
 
        if file:
1623
 
            import codecs
1624
 
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1625
2080
 
1626
 
        if message == "":
1627
 
                raise BzrCommandError("empty commit message specified")
 
2081
        def get_message(commit_obj):
 
2082
            """Callback to get commit message"""
 
2083
            my_message = message
 
2084
            if my_message is None and not file:
 
2085
                template = make_commit_message_template(tree, selected_list)
 
2086
                my_message = edit_commit_message(template)
 
2087
                if my_message is None:
 
2088
                    raise errors.BzrCommandError("please specify a commit"
 
2089
                        " message with either --message or --file")
 
2090
            elif my_message and file:
 
2091
                raise errors.BzrCommandError(
 
2092
                    "please specify either --message or --file")
 
2093
            if file:
 
2094
                my_message = codecs.open(file, 'rt', 
 
2095
                                         bzrlib.user_encoding).read()
 
2096
            if my_message == "":
 
2097
                raise errors.BzrCommandError("empty commit message specified")
 
2098
            return my_message
1628
2099
        
1629
2100
        if verbose:
1630
2101
            reporter = ReportCommitToLog()
1631
2102
        else:
1632
2103
            reporter = NullCommitReporter()
1633
 
        
 
2104
 
1634
2105
        try:
1635
 
            tree.commit(message, specific_files=selected_list,
 
2106
            tree.commit(message_callback=get_message,
 
2107
                        specific_files=selected_list,
1636
2108
                        allow_pointless=unchanged, strict=strict, local=local,
1637
2109
                        reporter=reporter)
1638
2110
        except PointlessCommit:
1639
2111
            # FIXME: This should really happen before the file is read in;
1640
2112
            # perhaps prepare the commit; get the message; then actually commit
1641
 
            raise BzrCommandError("no changes to commit",
1642
 
                                  ["use --unchanged to commit anyhow"])
 
2113
            raise errors.BzrCommandError("no changes to commit."
 
2114
                              " use --unchanged to commit anyhow")
1643
2115
        except ConflictsInTree:
1644
 
            raise BzrCommandError("Conflicts detected in working tree.  "
1645
 
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
 
2116
            raise errors.BzrCommandError('Conflicts detected in working '
 
2117
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
 
2118
                ' resolve.')
1646
2119
        except StrictCommitFailed:
1647
 
            raise BzrCommandError("Commit refused because there are unknown "
1648
 
                                  "files in the working tree.")
 
2120
            raise errors.BzrCommandError("Commit refused because there are"
 
2121
                              " unknown files in the working tree.")
1649
2122
        except errors.BoundBranchOutOfDate, e:
1650
 
            raise BzrCommandError(str(e)
1651
 
                                  + ' Either unbind, update, or'
1652
 
                                    ' pass --local to commit.')
 
2123
            raise errors.BzrCommandError(str(e) + "\n"
 
2124
            'To commit to master branch, run update and then commit.\n'
 
2125
            'You can also pass --local to commit to continue working '
 
2126
            'disconnected.')
1653
2127
 
1654
2128
 
1655
2129
class cmd_check(Command):
1671
2145
        check(branch, verbose)
1672
2146
 
1673
2147
 
1674
 
class cmd_scan_cache(Command):
1675
 
    hidden = True
1676
 
    def run(self):
1677
 
        from bzrlib.hashcache import HashCache
1678
 
 
1679
 
        c = HashCache(u'.')
1680
 
        c.read()
1681
 
        c.scan()
1682
 
            
1683
 
        print '%6d stats' % c.stat_count
1684
 
        print '%6d in hashcache' % len(c._cache)
1685
 
        print '%6d files removed from cache' % c.removed_count
1686
 
        print '%6d hashes updated' % c.update_count
1687
 
        print '%6d files changed too recently to cache' % c.danger_count
1688
 
 
1689
 
        if c.needs_write:
1690
 
            c.write()
1691
 
 
1692
 
 
1693
2148
class cmd_upgrade(Command):
1694
2149
    """Upgrade branch storage to current format.
1695
2150
 
1699
2154
    """
1700
2155
    takes_args = ['url?']
1701
2156
    takes_options = [
1702
 
                     Option('format', 
1703
 
                            help='Upgrade to a specific format. Current formats'
1704
 
                                 ' are: default, knit, metaweave and weave.'
1705
 
                                 ' Default is knit; metaweave and weave are'
1706
 
                                 ' deprecated',
1707
 
                            type=get_format_type),
 
2157
                    RegistryOption('format',
 
2158
                        help='Upgrade to a specific format.  See "bzr help'
 
2159
                             ' formats" for details',
 
2160
                        registry=bzrdir.format_registry,
 
2161
                        converter=bzrdir.format_registry.make_bzrdir,
 
2162
                        value_switches=True, title='Branch format'),
1708
2163
                    ]
1709
2164
 
1710
 
 
1711
2165
    def run(self, url='.', format=None):
1712
2166
        from bzrlib.upgrade import upgrade
1713
2167
        if format is None:
1714
 
            format = get_format_type('default')
 
2168
            format = bzrdir.format_registry.make_bzrdir('default')
1715
2169
        upgrade(url, format)
1716
2170
 
1717
2171
 
1718
2172
class cmd_whoami(Command):
1719
 
    """Show bzr user id."""
1720
 
    takes_options = ['email']
 
2173
    """Show or set bzr user id.
 
2174
    
 
2175
    examples:
 
2176
        bzr whoami --email
 
2177
        bzr whoami 'Frank Chu <fchu@example.com>'
 
2178
    """
 
2179
    takes_options = [ Option('email',
 
2180
                             help='display email address only'),
 
2181
                      Option('branch',
 
2182
                             help='set identity for the current branch instead of '
 
2183
                                  'globally'),
 
2184
                    ]
 
2185
    takes_args = ['name?']
 
2186
    encoding_type = 'replace'
1721
2187
    
1722
2188
    @display_command
1723
 
    def run(self, email=False):
 
2189
    def run(self, email=False, branch=False, name=None):
 
2190
        if name is None:
 
2191
            # use branch if we're inside one; otherwise global config
 
2192
            try:
 
2193
                c = Branch.open_containing('.')[0].get_config()
 
2194
            except errors.NotBranchError:
 
2195
                c = config.GlobalConfig()
 
2196
            if email:
 
2197
                self.outf.write(c.user_email() + '\n')
 
2198
            else:
 
2199
                self.outf.write(c.username() + '\n')
 
2200
            return
 
2201
 
 
2202
        # display a warning if an email address isn't included in the given name.
1724
2203
        try:
1725
 
            b = WorkingTree.open_containing(u'.')[0].branch
1726
 
            config = bzrlib.config.BranchConfig(b)
1727
 
        except NotBranchError:
1728
 
            config = bzrlib.config.GlobalConfig()
 
2204
            config.extract_email_address(name)
 
2205
        except errors.NoEmailInUsername, e:
 
2206
            warning('"%s" does not seem to contain an email address.  '
 
2207
                    'This is allowed, but not recommended.', name)
1729
2208
        
1730
 
        if email:
1731
 
            print config.user_email()
 
2209
        # use global config unless --branch given
 
2210
        if branch:
 
2211
            c = Branch.open_containing('.')[0].get_config()
1732
2212
        else:
1733
 
            print config.username()
 
2213
            c = config.GlobalConfig()
 
2214
        c.set_user_option('email', name)
1734
2215
 
1735
2216
 
1736
2217
class cmd_nick(Command):
1755
2236
class cmd_selftest(Command):
1756
2237
    """Run internal test suite.
1757
2238
    
1758
 
    This creates temporary test directories in the working directory,
1759
 
    but not existing data is affected.  These directories are deleted
1760
 
    if the tests pass, or left behind to help in debugging if they
1761
 
    fail and --keep-output is specified.
 
2239
    This creates temporary test directories in the working directory, but not
 
2240
    existing data is affected.  These directories are deleted if the tests
 
2241
    pass, or left behind to help in debugging if they fail and --keep-output
 
2242
    is specified.
1762
2243
    
1763
 
    If arguments are given, they are regular expressions that say
1764
 
    which tests should run.
 
2244
    If arguments are given, they are regular expressions that say which tests
 
2245
    should run.  Tests matching any expression are run, and other tests are
 
2246
    not run.
 
2247
 
 
2248
    Alternatively if --first is given, matching tests are run first and then
 
2249
    all other tests are run.  This is useful if you have been working in a
 
2250
    particular area, but want to make sure nothing else was broken.
1765
2251
 
1766
2252
    If the global option '--no-plugins' is given, plugins are not loaded
1767
2253
    before running the selftests.  This has two effects: features provided or
1768
2254
    modified by plugins will not be tested, and tests provided by plugins will
1769
2255
    not be run.
1770
2256
 
1771
 
    examples:
 
2257
    examples::
1772
2258
        bzr selftest ignore
 
2259
            run only tests relating to 'ignore'
1773
2260
        bzr --no-plugins selftest -v
 
2261
            disable plugins and list tests as they're run
 
2262
 
 
2263
    For each test, that needs actual disk access, bzr create their own
 
2264
    subdirectory in the temporary testing directory (testXXXX.tmp).
 
2265
    By default the name of such subdirectory is based on the name of the test.
 
2266
    If option '--numbered-dirs' is given, bzr will use sequent numbers
 
2267
    of running tests to create such subdirectories. This is default behavior
 
2268
    on Windows because of path length limitation.
1774
2269
    """
1775
2270
    # TODO: --list should give a list of all available tests
1776
2271
 
1789
2284
            return FakeNFSServer
1790
2285
        msg = "No known transport type %s. Supported types are: sftp\n" %\
1791
2286
            (typestring)
1792
 
        raise BzrCommandError(msg)
 
2287
        raise errors.BzrCommandError(msg)
1793
2288
 
1794
2289
    hidden = True
1795
2290
    takes_args = ['testspecs*']
1805
2300
                     Option('lsprof-timed',
1806
2301
                            help='generate lsprof output for benchmarked'
1807
2302
                                 ' sections of code.'),
 
2303
                     Option('cache-dir', type=str,
 
2304
                            help='a directory to cache intermediate'
 
2305
                                 ' benchmark steps'),
 
2306
                     Option('clean-output',
 
2307
                            help='clean temporary tests directories'
 
2308
                                 ' without running tests'),
 
2309
                     Option('first',
 
2310
                            help='run all tests, but run specified tests first',
 
2311
                            ),
 
2312
                     Option('numbered-dirs',
 
2313
                            help='use numbered dirs for TestCaseInTempDir'),
1808
2314
                     ]
 
2315
    encoding_type = 'replace'
1809
2316
 
1810
2317
    def run(self, testspecs_list=None, verbose=None, one=False,
1811
2318
            keep_output=False, transport=None, benchmark=None,
1812
 
            lsprof_timed=None):
 
2319
            lsprof_timed=None, cache_dir=None, clean_output=False,
 
2320
            first=False, numbered_dirs=None):
1813
2321
        import bzrlib.ui
1814
2322
        from bzrlib.tests import selftest
1815
2323
        import bzrlib.benchmarks as benchmarks
1816
 
        # we don't want progress meters from the tests to go to the
1817
 
        # real output; and we don't want log messages cluttering up
1818
 
        # the real logs.
1819
 
        save_ui = bzrlib.ui.ui_factory
1820
 
        print '%10s: %s' % ('bzr', bzrlib.osutils.realpath(sys.argv[0]))
 
2324
        from bzrlib.benchmarks import tree_creator
 
2325
 
 
2326
        if clean_output:
 
2327
            from bzrlib.tests import clean_selftest_output
 
2328
            clean_selftest_output()
 
2329
            return 0
 
2330
 
 
2331
        if numbered_dirs is None and sys.platform == 'win32':
 
2332
            numbered_dirs = True
 
2333
 
 
2334
        if cache_dir is not None:
 
2335
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
 
2336
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1821
2337
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1822
2338
        print
1823
 
        bzrlib.trace.info('running tests...')
 
2339
        if testspecs_list is not None:
 
2340
            pattern = '|'.join(testspecs_list)
 
2341
        else:
 
2342
            pattern = ".*"
 
2343
        if benchmark:
 
2344
            test_suite_factory = benchmarks.test_suite
 
2345
            if verbose is None:
 
2346
                verbose = True
 
2347
            # TODO: should possibly lock the history file...
 
2348
            benchfile = open(".perf_history", "at", buffering=1)
 
2349
        else:
 
2350
            test_suite_factory = None
 
2351
            if verbose is None:
 
2352
                verbose = False
 
2353
            benchfile = None
1824
2354
        try:
1825
 
            bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1826
 
            if testspecs_list is not None:
1827
 
                pattern = '|'.join(testspecs_list)
1828
 
            else:
1829
 
                pattern = ".*"
1830
 
            if benchmark:
1831
 
                test_suite_factory = benchmarks.test_suite
1832
 
                if verbose is None:
1833
 
                    verbose = True
1834
 
            else:
1835
 
                test_suite_factory = None
1836
 
                if verbose is None:
1837
 
                    verbose = False
1838
2355
            result = selftest(verbose=verbose, 
1839
2356
                              pattern=pattern,
1840
2357
                              stop_on_failure=one, 
1841
2358
                              keep_output=keep_output,
1842
2359
                              transport=transport,
1843
2360
                              test_suite_factory=test_suite_factory,
1844
 
                              lsprof_timed=lsprof_timed)
1845
 
            if result:
1846
 
                bzrlib.trace.info('tests passed')
1847
 
            else:
1848
 
                bzrlib.trace.info('tests failed')
1849
 
            return int(not result)
 
2361
                              lsprof_timed=lsprof_timed,
 
2362
                              bench_history=benchfile,
 
2363
                              matching_tests_first=first,
 
2364
                              numbered_dirs=numbered_dirs,
 
2365
                              )
1850
2366
        finally:
1851
 
            bzrlib.ui.ui_factory = save_ui
1852
 
 
1853
 
 
1854
 
def _get_bzr_branch():
1855
 
    """If bzr is run from a branch, return Branch or None"""
1856
 
    import bzrlib.errors
1857
 
    from bzrlib.branch import Branch
1858
 
    from bzrlib.osutils import abspath
1859
 
    from os.path import dirname
1860
 
    
1861
 
    try:
1862
 
        branch = Branch.open(dirname(abspath(dirname(__file__))))
1863
 
        return branch
1864
 
    except bzrlib.errors.BzrError:
1865
 
        return None
1866
 
    
1867
 
 
1868
 
def show_version():
1869
 
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
1870
 
    # is bzrlib itself in a branch?
1871
 
    branch = _get_bzr_branch()
1872
 
    if branch:
1873
 
        rh = branch.revision_history()
1874
 
        revno = len(rh)
1875
 
        print "  bzr checkout, revision %d" % (revno,)
1876
 
        print "  nick: %s" % (branch.nick,)
1877
 
        if rh:
1878
 
            print "  revid: %s" % (rh[-1],)
1879
 
    print "Using python interpreter:", sys.executable
1880
 
    import site
1881
 
    print "Using python standard library:", os.path.dirname(site.__file__)
1882
 
    print "Using bzrlib:",
1883
 
    if len(bzrlib.__path__) > 1:
1884
 
        # print repr, which is a good enough way of making it clear it's
1885
 
        # more than one element (eg ['/foo/bar', '/foo/bzr'])
1886
 
        print repr(bzrlib.__path__)
1887
 
    else:
1888
 
        print bzrlib.__path__[0]
1889
 
 
1890
 
    print
1891
 
    print bzrlib.__copyright__
1892
 
    print "http://bazaar-vcs.org/"
1893
 
    print
1894
 
    print "bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and"
1895
 
    print "you may use, modify and redistribute it under the terms of the GNU"
1896
 
    print "General Public License version 2 or later."
 
2367
            if benchfile is not None:
 
2368
                benchfile.close()
 
2369
        if result:
 
2370
            info('tests passed')
 
2371
        else:
 
2372
            info('tests failed')
 
2373
        return int(not result)
1897
2374
 
1898
2375
 
1899
2376
class cmd_version(Command):
1900
2377
    """Show version of bzr."""
 
2378
 
1901
2379
    @display_command
1902
2380
    def run(self):
 
2381
        from bzrlib.version import show_version
1903
2382
        show_version()
1904
2383
 
 
2384
 
1905
2385
class cmd_rocks(Command):
1906
2386
    """Statement of optimism."""
 
2387
 
1907
2388
    hidden = True
 
2389
 
1908
2390
    @display_command
1909
2391
    def run(self):
1910
 
        print "it sure does!"
 
2392
        print "It sure does!"
1911
2393
 
1912
2394
 
1913
2395
class cmd_find_merge_base(Command):
1914
 
    """Find and print a base revision for merging two branches.
1915
 
    """
 
2396
    """Find and print a base revision for merging two branches."""
1916
2397
    # TODO: Options to specify revisions on either side, as if
1917
2398
    #       merging only part of the history.
1918
2399
    takes_args = ['branch', 'other']
1920
2401
    
1921
2402
    @display_command
1922
2403
    def run(self, branch, other):
1923
 
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
 
2404
        from bzrlib.revision import MultipleRevisionSources
1924
2405
        
1925
2406
        branch1 = Branch.open_containing(branch)[0]
1926
2407
        branch2 = Branch.open_containing(other)[0]
1927
2408
 
1928
 
        history_1 = branch1.revision_history()
1929
 
        history_2 = branch2.revision_history()
1930
 
 
1931
2409
        last1 = branch1.last_revision()
1932
2410
        last2 = branch2.last_revision()
1933
2411
 
1937
2415
        base_rev_id = common_ancestor(last1, last2, source)
1938
2416
 
1939
2417
        print 'merge base is revision %s' % base_rev_id
1940
 
        
1941
 
        return
1942
 
 
1943
 
        if base_revno is None:
1944
 
            raise bzrlib.errors.UnrelatedBranches()
1945
 
 
1946
 
        print ' r%-6d in %s' % (base_revno, branch)
1947
 
 
1948
 
        other_revno = branch2.revision_id_to_revno(base_revid)
1949
 
        
1950
 
        print ' r%-6d in %s' % (other_revno, other)
1951
 
 
1952
2418
 
1953
2419
 
1954
2420
class cmd_merge(Command):
1955
2421
    """Perform a three-way merge.
1956
2422
    
1957
 
    The branch is the branch you will merge from.  By default, it will
1958
 
    merge the latest revision.  If you specify a revision, that
1959
 
    revision will be merged.  If you specify two revisions, the first
1960
 
    will be used as a BASE, and the second one as OTHER.  Revision
1961
 
    numbers are always relative to the specified branch.
 
2423
    The branch is the branch you will merge from.  By default, it will merge
 
2424
    the latest revision.  If you specify a revision, that revision will be
 
2425
    merged.  If you specify two revisions, the first will be used as a BASE,
 
2426
    and the second one as OTHER.  Revision numbers are always relative to the
 
2427
    specified branch.
1962
2428
 
1963
2429
    By default, bzr will try to merge in all new work from the other
1964
2430
    branch, automatically determining an appropriate base.  If this
1973
2439
 
1974
2440
    If there is no default branch set, the first merge will set it. After
1975
2441
    that, you can omit the branch to use the default.  To change the
1976
 
    default, use --remember.
 
2442
    default, use --remember. The value will only be saved if the remote
 
2443
    location can be accessed.
 
2444
 
 
2445
    The results of the merge are placed into the destination working
 
2446
    directory, where they can be reviewed (with bzr diff), tested, and then
 
2447
    committed to record the result of the merge.
1977
2448
 
1978
2449
    Examples:
1979
2450
 
1993
2464
    """
1994
2465
    takes_args = ['branch?']
1995
2466
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
1996
 
                     Option('show-base', help="Show base revision text in "
1997
 
                            "conflicts")]
1998
 
 
1999
 
    def help(self):
2000
 
        from merge import merge_type_help
2001
 
        from inspect import getdoc
2002
 
        return getdoc(self) + '\n' + merge_type_help() 
 
2467
        Option('show-base', help="Show base revision text in "
 
2468
               "conflicts"),
 
2469
        Option('uncommitted', help='Apply uncommitted changes'
 
2470
               ' from a working copy, instead of branch changes'),
 
2471
        Option('pull', help='If the destination is already'
 
2472
                ' completely merged into the source, pull from the'
 
2473
                ' source rather than merging. When this happens,'
 
2474
                ' you do not need to commit the result.'),
 
2475
        Option('directory',
 
2476
            help='Branch to merge into, '
 
2477
                 'rather than the one containing the working directory',
 
2478
            short_name='d',
 
2479
            type=unicode,
 
2480
            ),
 
2481
    ]
2003
2482
 
2004
2483
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2005
 
            show_base=False, reprocess=False, remember=False):
 
2484
            show_base=False, reprocess=False, remember=False,
 
2485
            uncommitted=False, pull=False,
 
2486
            directory=None,
 
2487
            ):
 
2488
        from bzrlib.tag import _merge_tags_if_possible
2006
2489
        if merge_type is None:
2007
 
            merge_type = Merge3Merger
2008
 
 
2009
 
 
2010
 
        tree = WorkingTree.open_containing(u'.')[0]
2011
 
        try:
2012
 
            if branch is not None:
2013
 
                reader = BundleReader(file(branch, 'rb'))
2014
 
            else:
2015
 
                reader = None
2016
 
        except IOError, e:
2017
 
            if e.errno not in (errno.ENOENT, errno.EISDIR):
2018
 
                raise
2019
 
            reader = None
2020
 
        except BadBundle:
2021
 
            reader = None
2022
 
        if reader is not None:
2023
 
            conflicts = merge_bundle(reader, tree, not force, merge_type,
2024
 
                                        reprocess, show_base)
2025
 
            if conflicts == 0:
2026
 
                return 0
2027
 
            else:
2028
 
                return 1
2029
 
 
2030
 
        stored_loc = tree.branch.get_parent()
2031
 
        if branch is None:
2032
 
            if stored_loc is None:
2033
 
                raise BzrCommandError("No merge branch known or specified.")
2034
 
            else:
2035
 
                print "Using saved branch: %s" % stored_loc
2036
 
                branch = stored_loc
2037
 
 
2038
 
        if tree.branch.get_parent() is None or remember:
2039
 
            tree.branch.set_parent(branch)
 
2490
            merge_type = _mod_merge.Merge3Merger
 
2491
 
 
2492
        if directory is None: directory = u'.'
 
2493
        # XXX: jam 20070225 WorkingTree should be locked before you extract its
 
2494
        #      inventory. Because merge is a mutating operation, it really
 
2495
        #      should be a lock_write() for the whole cmd_merge operation.
 
2496
        #      However, cmd_merge open's its own tree in _merge_helper, which
 
2497
        #      means if we lock here, the later lock_write() will always block.
 
2498
        #      Either the merge helper code should be updated to take a tree,
 
2499
        #      (What about tree.merge_from_branch?)
 
2500
        tree = WorkingTree.open_containing(directory)[0]
 
2501
        change_reporter = delta.ChangeReporter(
 
2502
            unversioned_filter=tree.is_ignored)
 
2503
 
 
2504
        if branch is not None:
 
2505
            try:
 
2506
                reader = bundle.read_bundle_from_url(branch)
 
2507
            except errors.NotABundle:
 
2508
                pass # Continue on considering this url a Branch
 
2509
            else:
 
2510
                conflicts = merge_bundle(reader, tree, not force, merge_type,
 
2511
                                         reprocess, show_base, change_reporter)
 
2512
                if conflicts == 0:
 
2513
                    return 0
 
2514
                else:
 
2515
                    return 1
 
2516
 
 
2517
        if revision is None \
 
2518
                or len(revision) < 1 or revision[0].needs_branch():
 
2519
            branch = self._get_remembered_parent(tree, branch, 'Merging from')
2040
2520
 
2041
2521
        if revision is None or len(revision) < 1:
2042
 
            base = [None, None]
2043
 
            other = [branch, -1]
 
2522
            if uncommitted:
 
2523
                base = [branch, -1]
 
2524
                other = [branch, None]
 
2525
            else:
 
2526
                base = [None, None]
 
2527
                other = [branch, -1]
2044
2528
            other_branch, path = Branch.open_containing(branch)
2045
2529
        else:
 
2530
            if uncommitted:
 
2531
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
2532
                                             ' --revision at the same time.')
 
2533
            branch = revision[0].get_branch() or branch
2046
2534
            if len(revision) == 1:
2047
2535
                base = [None, None]
2048
2536
                other_branch, path = Branch.open_containing(branch)
2051
2539
            else:
2052
2540
                assert len(revision) == 2
2053
2541
                if None in revision:
2054
 
                    raise BzrCommandError(
2055
 
                        "Merge doesn't permit that revision specifier.")
2056
 
                b, path = Branch.open_containing(branch)
2057
 
 
2058
 
                base = [branch, revision[0].in_history(b).revno]
2059
 
                other = [branch, revision[1].in_history(b).revno]
 
2542
                    raise errors.BzrCommandError(
 
2543
                        "Merge doesn't permit empty revision specifier.")
 
2544
                base_branch, path = Branch.open_containing(branch)
 
2545
                branch1 = revision[1].get_branch() or branch
 
2546
                other_branch, path1 = Branch.open_containing(branch1)
 
2547
                if revision[0].get_branch() is not None:
 
2548
                    # then path was obtained from it, and is None.
 
2549
                    path = path1
 
2550
 
 
2551
                base = [branch, revision[0].in_history(base_branch).revno]
 
2552
                other = [branch1, revision[1].in_history(other_branch).revno]
 
2553
 
 
2554
        if tree.branch.get_parent() is None or remember:
 
2555
            tree.branch.set_parent(other_branch.base)
 
2556
 
 
2557
        # pull tags now... it's a bit inconsistent to do it ahead of copying
 
2558
        # the history but that's done inside the merge code
 
2559
        _merge_tags_if_possible(other_branch, tree.branch)
 
2560
 
2060
2561
        if path != "":
2061
2562
            interesting_files = [path]
2062
2563
        else:
2063
2564
            interesting_files = None
2064
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
2565
        pb = ui.ui_factory.nested_progress_bar()
2065
2566
        try:
2066
2567
            try:
2067
 
                conflict_count = merge(other, base, check_clean=(not force),
2068
 
                                       merge_type=merge_type, 
2069
 
                                       reprocess=reprocess,
2070
 
                                       show_base=show_base, 
2071
 
                                       pb=pb, file_list=interesting_files)
 
2568
                conflict_count = _merge_helper(
 
2569
                    other, base, check_clean=(not force),
 
2570
                    merge_type=merge_type,
 
2571
                    reprocess=reprocess,
 
2572
                    show_base=show_base,
 
2573
                    pull=pull,
 
2574
                    this_dir=directory,
 
2575
                    pb=pb, file_list=interesting_files,
 
2576
                    change_reporter=change_reporter)
2072
2577
            finally:
2073
2578
                pb.finished()
2074
2579
            if conflict_count != 0:
2075
2580
                return 1
2076
2581
            else:
2077
2582
                return 0
2078
 
        except bzrlib.errors.AmbiguousBase, e:
 
2583
        except errors.AmbiguousBase, e:
2079
2584
            m = ("sorry, bzr can't determine the right merge base yet\n"
2080
2585
                 "candidates are:\n  "
2081
2586
                 + "\n  ".join(e.bases)
2084
2589
                 "and (if you want) report this to the bzr developers\n")
2085
2590
            log_error(m)
2086
2591
 
 
2592
    # TODO: move up to common parent; this isn't merge-specific anymore. 
 
2593
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
 
2594
        """Use tree.branch's parent if none was supplied.
 
2595
 
 
2596
        Report if the remembered location was used.
 
2597
        """
 
2598
        if supplied_location is not None:
 
2599
            return supplied_location
 
2600
        stored_location = tree.branch.get_parent()
 
2601
        mutter("%s", stored_location)
 
2602
        if stored_location is None:
 
2603
            raise errors.BzrCommandError("No location specified or remembered")
 
2604
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
 
2605
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
 
2606
        return stored_location
 
2607
 
2087
2608
 
2088
2609
class cmd_remerge(Command):
2089
2610
    """Redo a merge.
2111
2632
                     Option('show-base', help="Show base revision text in "
2112
2633
                            "conflicts")]
2113
2634
 
2114
 
    def help(self):
2115
 
        from merge import merge_type_help
2116
 
        from inspect import getdoc
2117
 
        return getdoc(self) + '\n' + merge_type_help() 
2118
 
 
2119
2635
    def run(self, file_list=None, merge_type=None, show_base=False,
2120
2636
            reprocess=False):
2121
 
        from bzrlib.merge import merge_inner, transform_tree
2122
2637
        if merge_type is None:
2123
 
            merge_type = Merge3Merger
 
2638
            merge_type = _mod_merge.Merge3Merger
2124
2639
        tree, file_list = tree_files(file_list)
2125
2640
        tree.lock_write()
2126
2641
        try:
2127
 
            pending_merges = tree.pending_merges() 
2128
 
            if len(pending_merges) != 1:
2129
 
                raise BzrCommandError("Sorry, remerge only works after normal"
2130
 
                                      + " merges.  Not cherrypicking or"
2131
 
                                      + "multi-merges.")
 
2642
            parents = tree.get_parent_ids()
 
2643
            if len(parents) != 2:
 
2644
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
2645
                                             " merges.  Not cherrypicking or"
 
2646
                                             " multi-merges.")
2132
2647
            repository = tree.branch.repository
2133
 
            base_revision = common_ancestor(tree.branch.last_revision(), 
2134
 
                                            pending_merges[0], repository)
 
2648
            base_revision = common_ancestor(parents[0],
 
2649
                                            parents[1], repository)
2135
2650
            base_tree = repository.revision_tree(base_revision)
2136
 
            other_tree = repository.revision_tree(pending_merges[0])
 
2651
            other_tree = repository.revision_tree(parents[1])
2137
2652
            interesting_ids = None
 
2653
            new_conflicts = []
 
2654
            conflicts = tree.conflicts()
2138
2655
            if file_list is not None:
2139
2656
                interesting_ids = set()
2140
2657
                for filename in file_list:
2141
2658
                    file_id = tree.path2id(filename)
2142
2659
                    if file_id is None:
2143
 
                        raise NotVersionedError(filename)
 
2660
                        raise errors.NotVersionedError(filename)
2144
2661
                    interesting_ids.add(file_id)
2145
2662
                    if tree.kind(file_id) != "directory":
2146
2663
                        continue
2147
2664
                    
2148
2665
                    for name, ie in tree.inventory.iter_entries(file_id):
2149
2666
                        interesting_ids.add(ie.file_id)
2150
 
            transform_tree(tree, tree.basis_tree(), interesting_ids)
2151
 
            if file_list is None:
2152
 
                restore_files = list(tree.iter_conflicts())
 
2667
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2153
2668
            else:
 
2669
                # Remerge only supports resolving contents conflicts
 
2670
                allowed_conflicts = ('text conflict', 'contents conflict')
 
2671
                restore_files = [c.path for c in conflicts
 
2672
                                 if c.typestring in allowed_conflicts]
 
2673
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
2674
            tree.set_conflicts(ConflictList(new_conflicts))
 
2675
            if file_list is not None:
2154
2676
                restore_files = file_list
2155
2677
            for filename in restore_files:
2156
2678
                try:
2157
2679
                    restore(tree.abspath(filename))
2158
 
                except NotConflicted:
 
2680
                except errors.NotConflicted:
2159
2681
                    pass
2160
 
            conflicts =  merge_inner(tree.branch, other_tree, base_tree,
2161
 
                                     this_tree=tree,
2162
 
                                     interesting_ids = interesting_ids, 
2163
 
                                     other_rev_id=pending_merges[0], 
2164
 
                                     merge_type=merge_type, 
2165
 
                                     show_base=show_base,
2166
 
                                     reprocess=reprocess)
 
2682
            conflicts = _mod_merge.merge_inner(
 
2683
                                      tree.branch, other_tree, base_tree,
 
2684
                                      this_tree=tree,
 
2685
                                      interesting_ids=interesting_ids,
 
2686
                                      other_rev_id=parents[1],
 
2687
                                      merge_type=merge_type,
 
2688
                                      show_base=show_base,
 
2689
                                      reprocess=reprocess)
2167
2690
        finally:
2168
2691
            tree.unlock()
2169
2692
        if conflicts > 0:
2171
2694
        else:
2172
2695
            return 0
2173
2696
 
 
2697
 
2174
2698
class cmd_revert(Command):
2175
 
    """Reverse all changes since the last commit.
2176
 
 
2177
 
    Only versioned files are affected.  Specify filenames to revert only 
2178
 
    those files.  By default, any files that are changed will be backed up
2179
 
    first.  Backup files have a '~' appended to their name.
 
2699
    """Revert files to a previous revision.
 
2700
 
 
2701
    Giving a list of files will revert only those files.  Otherwise, all files
 
2702
    will be reverted.  If the revision is not specified with '--revision', the
 
2703
    last committed revision is used.
 
2704
 
 
2705
    To remove only some changes, without reverting to a prior version, use
 
2706
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
 
2707
    introduced by -2, without affecting the changes introduced by -1.  Or
 
2708
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
2709
    
 
2710
    By default, any files that have been manually changed will be backed up
 
2711
    first.  (Files changed only by merge are not backed up.)  Backup files have
 
2712
    '.~#~' appended to their name, where # is a number.
 
2713
 
 
2714
    When you provide files, you can use their current pathname or the pathname
 
2715
    from the target revision.  So you can use revert to "undelete" a file by
 
2716
    name.  If you name a directory, all the contents of that directory will be
 
2717
    reverted.
2180
2718
    """
2181
2719
    takes_options = ['revision', 'no-backup']
2182
2720
    takes_args = ['file*']
2183
2721
    aliases = ['merge-revert']
2184
2722
 
2185
2723
    def run(self, revision=None, no_backup=False, file_list=None):
2186
 
        from bzrlib.commands import parse_spec
2187
2724
        if file_list is not None:
2188
2725
            if len(file_list) == 0:
2189
 
                raise BzrCommandError("No files specified")
 
2726
                raise errors.BzrCommandError("No files specified")
2190
2727
        else:
2191
2728
            file_list = []
2192
2729
        
2195
2732
            # FIXME should be tree.last_revision
2196
2733
            rev_id = tree.last_revision()
2197
2734
        elif len(revision) != 1:
2198
 
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
 
2735
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
2199
2736
        else:
2200
2737
            rev_id = revision[0].in_history(tree.branch).rev_id
2201
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
2738
        pb = ui.ui_factory.nested_progress_bar()
2202
2739
        try:
2203
2740
            tree.revert(file_list, 
2204
2741
                        tree.branch.repository.revision_tree(rev_id),
2205
 
                        not no_backup, pb)
 
2742
                        not no_backup, pb, report_changes=True)
2206
2743
        finally:
2207
2744
            pb.finished()
2208
2745
 
2209
2746
 
2210
2747
class cmd_assert_fail(Command):
2211
2748
    """Test reporting of assertion failures"""
 
2749
    # intended just for use in testing
 
2750
 
2212
2751
    hidden = True
 
2752
 
2213
2753
    def run(self):
2214
 
        assert False, "always fails"
 
2754
        raise AssertionError("always fails")
2215
2755
 
2216
2756
 
2217
2757
class cmd_help(Command):
2218
2758
    """Show help on a command or other topic.
2219
2759
 
2220
 
    For a list of all available commands, say 'bzr help commands'."""
 
2760
    For a list of all available commands, say 'bzr help commands'.
 
2761
    """
2221
2762
    takes_options = [Option('long', 'show help on all commands')]
2222
2763
    takes_args = ['topic?']
2223
2764
    aliases = ['?', '--help', '-?', '-h']
2224
2765
    
2225
2766
    @display_command
2226
2767
    def run(self, topic=None, long=False):
2227
 
        import help
 
2768
        import bzrlib.help
2228
2769
        if topic is None and long:
2229
2770
            topic = "commands"
2230
 
        help.help(topic)
 
2771
        bzrlib.help.help(topic)
2231
2772
 
2232
2773
 
2233
2774
class cmd_shell_complete(Command):
2234
2775
    """Show appropriate completions for context.
2235
2776
 
2236
 
    For a list of all available commands, say 'bzr shell-complete'."""
 
2777
    For a list of all available commands, say 'bzr shell-complete'.
 
2778
    """
2237
2779
    takes_args = ['context?']
2238
2780
    aliases = ['s-c']
2239
2781
    hidden = True
2247
2789
class cmd_fetch(Command):
2248
2790
    """Copy in history from another branch but don't merge it.
2249
2791
 
2250
 
    This is an internal method used for pull and merge."""
 
2792
    This is an internal method used for pull and merge.
 
2793
    """
2251
2794
    hidden = True
2252
2795
    takes_args = ['from_branch', 'to_branch']
2253
2796
    def run(self, from_branch, to_branch):
2254
2797
        from bzrlib.fetch import Fetcher
2255
 
        from bzrlib.branch import Branch
2256
2798
        from_b = Branch.open(from_branch)
2257
2799
        to_b = Branch.open(to_branch)
2258
2800
        Fetcher(to_b, from_b)
2261
2803
class cmd_missing(Command):
2262
2804
    """Show unmerged/unpulled revisions between two branches.
2263
2805
 
2264
 
    OTHER_BRANCH may be local or remote."""
 
2806
    OTHER_BRANCH may be local or remote.
 
2807
    """
2265
2808
    takes_args = ['other_branch?']
2266
2809
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
2267
2810
                     Option('mine-only', 
2269
2812
                     Option('theirs-only', 
2270
2813
                            'Display changes in the remote branch only'), 
2271
2814
                     'log-format',
2272
 
                     'line',
2273
 
                     'long', 
2274
 
                     'short',
2275
2815
                     'show-ids',
2276
2816
                     'verbose'
2277
2817
                     ]
 
2818
    encoding_type = 'replace'
2278
2819
 
 
2820
    @display_command
2279
2821
    def run(self, other_branch=None, reverse=False, mine_only=False,
2280
2822
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
2281
2823
            show_ids=False, verbose=False):
2282
2824
        from bzrlib.missing import find_unmerged, iter_log_data
2283
2825
        from bzrlib.log import log_formatter
2284
 
        local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
 
2826
        local_branch = Branch.open_containing(u".")[0]
2285
2827
        parent = local_branch.get_parent()
2286
2828
        if other_branch is None:
2287
2829
            other_branch = parent
2288
2830
            if other_branch is None:
2289
 
                raise BzrCommandError("No missing location known or specified.")
2290
 
            print "Using last location: " + local_branch.get_parent()
2291
 
        remote_branch = bzrlib.branch.Branch.open(other_branch)
 
2831
                raise errors.BzrCommandError("No peer location known or specified.")
 
2832
            display_url = urlutils.unescape_for_display(parent,
 
2833
                                                        self.outf.encoding)
 
2834
            print "Using last location: " + display_url
 
2835
 
 
2836
        remote_branch = Branch.open(other_branch)
2292
2837
        if remote_branch.base == local_branch.base:
2293
2838
            remote_branch = local_branch
2294
2839
        local_branch.lock_read()
2296
2841
            remote_branch.lock_read()
2297
2842
            try:
2298
2843
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2299
 
                if (log_format == None):
2300
 
                    default = bzrlib.config.BranchConfig(local_branch).log_format()
2301
 
                    log_format = get_log_format(long=long, short=short, line=line, default=default)
2302
 
                lf = log_formatter(log_format, sys.stdout,
2303
 
                                   show_ids=show_ids,
2304
 
                                   show_timezone='original')
 
2844
                if (log_format is None):
 
2845
                    log_format = log.log_formatter_registry.get_default(
 
2846
                        local_branch)
 
2847
                lf = log_format(to_file=self.outf,
 
2848
                                show_ids=show_ids,
 
2849
                                show_timezone='original')
2305
2850
                if reverse is False:
2306
2851
                    local_extra.reverse()
2307
2852
                    remote_extra.reverse()
2334
2879
            try:
2335
2880
                # handle race conditions - a parent might be set while we run.
2336
2881
                if local_branch.get_parent() is None:
2337
 
                    local_branch.set_parent(other_branch)
 
2882
                    local_branch.set_parent(remote_branch.base)
2338
2883
            finally:
2339
2884
                local_branch.unlock()
2340
2885
        return status_code
2348
2893
        import bzrlib.plugin
2349
2894
        from inspect import getdoc
2350
2895
        for name, plugin in bzrlib.plugin.all_plugins().items():
2351
 
            if hasattr(plugin, '__path__'):
 
2896
            if getattr(plugin, '__path__', None) is not None:
2352
2897
                print plugin.__path__[0]
2353
 
            elif hasattr(plugin, '__file__'):
 
2898
            elif getattr(plugin, '__file__', None) is not None:
2354
2899
                print plugin.__file__
2355
2900
            else:
2356
 
                print `plugin`
 
2901
                print repr(plugin)
2357
2902
                
2358
2903
            d = getdoc(plugin)
2359
2904
            if d:
2362
2907
 
2363
2908
class cmd_testament(Command):
2364
2909
    """Show testament (signing-form) of a revision."""
2365
 
    takes_options = ['revision', 'long']
 
2910
    takes_options = ['revision', 
 
2911
                     Option('long', help='Produce long-format testament'), 
 
2912
                     Option('strict', help='Produce a strict-format'
 
2913
                            ' testament')]
2366
2914
    takes_args = ['branch?']
2367
2915
    @display_command
2368
 
    def run(self, branch=u'.', revision=None, long=False):
2369
 
        from bzrlib.testament import Testament
 
2916
    def run(self, branch=u'.', revision=None, long=False, strict=False):
 
2917
        from bzrlib.testament import Testament, StrictTestament
 
2918
        if strict is True:
 
2919
            testament_class = StrictTestament
 
2920
        else:
 
2921
            testament_class = Testament
2370
2922
        b = WorkingTree.open_containing(branch)[0].branch
2371
2923
        b.lock_read()
2372
2924
        try:
2374
2926
                rev_id = b.last_revision()
2375
2927
            else:
2376
2928
                rev_id = revision[0].in_history(b).rev_id
2377
 
            t = Testament.from_revision(b.repository, rev_id)
 
2929
            t = testament_class.from_revision(b.repository, rev_id)
2378
2930
            if long:
2379
2931
                sys.stdout.writelines(t.as_text_lines())
2380
2932
            else:
2395
2947
    # TODO: annotate directories; showing when each file was last changed
2396
2948
    # TODO: if the working copy is modified, show annotations on that 
2397
2949
    #       with new uncommitted lines marked
2398
 
    aliases = ['blame', 'praise']
 
2950
    aliases = ['ann', 'blame', 'praise']
2399
2951
    takes_args = ['filename']
2400
2952
    takes_options = [Option('all', help='show annotations on all lines'),
2401
2953
                     Option('long', help='show date in annotations'),
2402
 
                     'revision'
 
2954
                     'revision',
 
2955
                     'show-ids',
2403
2956
                     ]
2404
2957
 
2405
2958
    @display_command
2406
 
    def run(self, filename, all=False, long=False, revision=None):
 
2959
    def run(self, filename, all=False, long=False, revision=None,
 
2960
            show_ids=False):
2407
2961
        from bzrlib.annotate import annotate_file
2408
2962
        tree, relpath = WorkingTree.open_containing(filename)
2409
2963
        branch = tree.branch
2412
2966
            if revision is None:
2413
2967
                revision_id = branch.last_revision()
2414
2968
            elif len(revision) != 1:
2415
 
                raise BzrCommandError('bzr annotate --revision takes exactly 1 argument')
 
2969
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2416
2970
            else:
2417
2971
                revision_id = revision[0].in_history(branch).rev_id
2418
 
            file_id = tree.inventory.path2id(relpath)
 
2972
            file_id = tree.path2id(relpath)
2419
2973
            tree = branch.repository.revision_tree(revision_id)
2420
2974
            file_version = tree.inventory[file_id].revision
2421
 
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
 
2975
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
 
2976
                          show_ids=show_ids)
2422
2977
        finally:
2423
2978
            branch.unlock()
2424
2979
 
2432
2987
    takes_options = ['revision']
2433
2988
    
2434
2989
    def run(self, revision_id_list=None, revision=None):
2435
 
        import bzrlib.config as config
2436
2990
        import bzrlib.gpg as gpg
2437
2991
        if revision_id_list is not None and revision is not None:
2438
 
            raise BzrCommandError('You can only supply one of revision_id or --revision')
 
2992
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
2439
2993
        if revision_id_list is None and revision is None:
2440
 
            raise BzrCommandError('You must supply either --revision or a revision_id')
 
2994
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
2441
2995
        b = WorkingTree.open_containing(u'.')[0].branch
2442
 
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
 
2996
        gpg_strategy = gpg.GPGStrategy(b.get_config())
2443
2997
        if revision_id_list is not None:
2444
2998
            for revision_id in revision_id_list:
2445
2999
                b.repository.sign_revision(revision_id, gpg_strategy)
2456
3010
                if to_revid is None:
2457
3011
                    to_revno = b.revno()
2458
3012
                if from_revno is None or to_revno is None:
2459
 
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
 
3013
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
2460
3014
                for revno in range(from_revno, to_revno + 1):
2461
3015
                    b.repository.sign_revision(b.get_rev_id(revno), 
2462
3016
                                               gpg_strategy)
2463
3017
            else:
2464
 
                raise BzrCommandError('Please supply either one revision, or a range.')
 
3018
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
2465
3019
 
2466
3020
 
2467
3021
class cmd_bind(Command):
2468
 
    """Bind the current branch to a master branch.
2469
 
 
2470
 
    After binding, commits must succeed on the master branch
2471
 
    before they are executed on the local one.
 
3022
    """Convert the current branch into a checkout of the supplied branch.
 
3023
 
 
3024
    Once converted into a checkout, commits must succeed on the master branch
 
3025
    before they will be applied to the local branch.
 
3026
 
 
3027
    See "help checkouts" for more information on checkouts.
2472
3028
    """
2473
3029
 
2474
 
    takes_args = ['location']
 
3030
    takes_args = ['location?']
2475
3031
    takes_options = []
2476
3032
 
2477
3033
    def run(self, location=None):
2478
3034
        b, relpath = Branch.open_containing(u'.')
 
3035
        if location is None:
 
3036
            try:
 
3037
                location = b.get_old_bound_location()
 
3038
            except errors.UpgradeRequired:
 
3039
                raise errors.BzrCommandError('No location supplied.  '
 
3040
                    'This format does not remember old locations.')
 
3041
            else:
 
3042
                if location is None:
 
3043
                    raise errors.BzrCommandError('No location supplied and no '
 
3044
                        'previous location known')
2479
3045
        b_other = Branch.open(location)
2480
3046
        try:
2481
3047
            b.bind(b_other)
2482
 
        except DivergedBranches:
2483
 
            raise BzrCommandError('These branches have diverged.'
2484
 
                                  ' Try merging, and then bind again.')
 
3048
        except errors.DivergedBranches:
 
3049
            raise errors.BzrCommandError('These branches have diverged.'
 
3050
                                         ' Try merging, and then bind again.')
2485
3051
 
2486
3052
 
2487
3053
class cmd_unbind(Command):
2488
 
    """Unbind the current branch from its master branch.
2489
 
 
2490
 
    After unbinding, the local branch is considered independent.
2491
 
    All subsequent commits will be local.
 
3054
    """Convert the current checkout into a regular branch.
 
3055
 
 
3056
    After unbinding, the local branch is considered independent and subsequent
 
3057
    commits will be local only.
 
3058
 
 
3059
    See "help checkouts" for more information on checkouts.
2492
3060
    """
2493
3061
 
2494
3062
    takes_args = []
2497
3065
    def run(self):
2498
3066
        b, relpath = Branch.open_containing(u'.')
2499
3067
        if not b.unbind():
2500
 
            raise BzrCommandError('Local branch is not bound')
2501
 
 
2502
 
 
2503
 
class cmd_uncommit(bzrlib.commands.Command):
 
3068
            raise errors.BzrCommandError('Local branch is not bound')
 
3069
 
 
3070
 
 
3071
class cmd_uncommit(Command):
2504
3072
    """Remove the last committed revision.
2505
3073
 
2506
3074
    --verbose will print out what is being removed.
2512
3080
    """
2513
3081
 
2514
3082
    # TODO: jam 20060108 Add an option to allow uncommit to remove
2515
 
    # unreferenced information in 'branch-as-repostory' branches.
 
3083
    # unreferenced information in 'branch-as-repository' branches.
2516
3084
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2517
3085
    # information in shared branches as well.
2518
3086
    takes_options = ['verbose', 'revision',
2521
3089
    takes_args = ['location?']
2522
3090
    aliases = []
2523
3091
 
2524
 
    def run(self, location=None, 
 
3092
    def run(self, location=None,
2525
3093
            dry_run=False, verbose=False,
2526
3094
            revision=None, force=False):
2527
 
        from bzrlib.branch import Branch
2528
 
        from bzrlib.log import log_formatter
 
3095
        from bzrlib.log import log_formatter, show_log
2529
3096
        import sys
2530
3097
        from bzrlib.uncommit import uncommit
2531
3098
 
2539
3106
            tree = None
2540
3107
            b = control.open_branch()
2541
3108
 
 
3109
        rev_id = None
2542
3110
        if revision is None:
2543
3111
            revno = b.revno()
2544
 
            rev_id = b.last_revision()
2545
3112
        else:
2546
 
            revno, rev_id = revision[0].in_history(b)
 
3113
            # 'bzr uncommit -r 10' actually means uncommit
 
3114
            # so that the final tree is at revno 10.
 
3115
            # but bzrlib.uncommit.uncommit() actually uncommits
 
3116
            # the revisions that are supplied.
 
3117
            # So we need to offset it by one
 
3118
            revno = revision[0].in_history(b).revno+1
 
3119
 
 
3120
        if revno <= b.revno():
 
3121
            rev_id = b.get_rev_id(revno)
2547
3122
        if rev_id is None:
2548
 
            print 'No revisions to uncommit.'
2549
 
 
2550
 
        for r in range(revno, b.revno()+1):
2551
 
            rev_id = b.get_rev_id(r)
2552
 
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2553
 
            lf.show(r, b.repository.get_revision(rev_id), None)
 
3123
            self.outf.write('No revisions to uncommit.\n')
 
3124
            return 1
 
3125
 
 
3126
        lf = log_formatter('short',
 
3127
                           to_file=self.outf,
 
3128
                           show_timezone='original')
 
3129
 
 
3130
        show_log(b,
 
3131
                 lf,
 
3132
                 verbose=False,
 
3133
                 direction='forward',
 
3134
                 start_revision=revno,
 
3135
                 end_revision=b.revno())
2554
3136
 
2555
3137
        if dry_run:
2556
3138
            print 'Dry-run, pretending to remove the above revisions.'
2591
3173
            pass
2592
3174
        
2593
3175
 
 
3176
class cmd_wait_until_signalled(Command):
 
3177
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
3178
 
 
3179
    This just prints a line to signal when it is ready, then blocks on stdin.
 
3180
    """
 
3181
 
 
3182
    hidden = True
 
3183
 
 
3184
    def run(self):
 
3185
        sys.stdout.write("running\n")
 
3186
        sys.stdout.flush()
 
3187
        sys.stdin.readline()
 
3188
 
 
3189
 
 
3190
class cmd_serve(Command):
 
3191
    """Run the bzr server."""
 
3192
 
 
3193
    aliases = ['server']
 
3194
 
 
3195
    takes_options = [
 
3196
        Option('inet',
 
3197
               help='serve on stdin/out for use from inetd or sshd'),
 
3198
        Option('port',
 
3199
               help='listen for connections on nominated port of the form '
 
3200
                    '[hostname:]portnumber. Passing 0 as the port number will '
 
3201
                    'result in a dynamically allocated port. Default port is '
 
3202
                    '4155.',
 
3203
               type=str),
 
3204
        Option('directory',
 
3205
               help='serve contents of directory',
 
3206
               type=unicode),
 
3207
        Option('allow-writes',
 
3208
               help='By default the server is a readonly server. Supplying '
 
3209
                    '--allow-writes enables write access to the contents of '
 
3210
                    'the served directory and below. '
 
3211
                ),
 
3212
        ]
 
3213
 
 
3214
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
 
3215
        from bzrlib.transport import smart
 
3216
        from bzrlib.transport import get_transport
 
3217
        if directory is None:
 
3218
            directory = os.getcwd()
 
3219
        url = urlutils.local_path_to_url(directory)
 
3220
        if not allow_writes:
 
3221
            url = 'readonly+' + url
 
3222
        t = get_transport(url)
 
3223
        if inet:
 
3224
            server = smart.SmartServerPipeStreamMedium(sys.stdin, sys.stdout, t)
 
3225
        else:
 
3226
            if port is None:
 
3227
                port = smart.BZR_DEFAULT_PORT
 
3228
                host = '127.0.0.1'
 
3229
            else:
 
3230
                if ':' in port:
 
3231
                    host, port = port.split(':')
 
3232
                else:
 
3233
                    host = '127.0.0.1'
 
3234
                port = int(port)
 
3235
            server = smart.SmartTCPServer(t, host=host, port=port)
 
3236
            print 'listening on port: ', server.port
 
3237
            sys.stdout.flush()
 
3238
        server.serve()
 
3239
 
 
3240
class cmd_join(Command):
 
3241
    """Combine a subtree into its containing tree.
 
3242
    
 
3243
    This is marked as a merge of the subtree into the containing tree, and all
 
3244
    history is preserved.
 
3245
    """
 
3246
 
 
3247
    takes_args = ['tree']
 
3248
    takes_options = [Option('reference', 'join by reference')]
 
3249
 
 
3250
    def run(self, tree, reference=False):
 
3251
        sub_tree = WorkingTree.open(tree)
 
3252
        parent_dir = osutils.dirname(sub_tree.basedir)
 
3253
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
 
3254
        repo = containing_tree.branch.repository
 
3255
        if not repo.supports_rich_root():
 
3256
            raise errors.BzrCommandError(
 
3257
                "Can't join trees because %s doesn't support rich root data.\n"
 
3258
                "You can use bzr upgrade on the repository."
 
3259
                % (repo,))
 
3260
        if reference:
 
3261
            try:
 
3262
                containing_tree.add_reference(sub_tree)
 
3263
            except errors.BadReferenceTarget, e:
 
3264
                # XXX: Would be better to just raise a nicely printable
 
3265
                # exception from the real origin.  Also below.  mbp 20070306
 
3266
                raise errors.BzrCommandError("Cannot join %s.  %s" %
 
3267
                                             (tree, e.reason))
 
3268
        else:
 
3269
            try:
 
3270
                containing_tree.subsume(sub_tree)
 
3271
            except errors.BadSubsumeSource, e:
 
3272
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
 
3273
                                             (tree, e.reason))
 
3274
 
 
3275
 
 
3276
class cmd_split(Command):
 
3277
    """Split a tree into two trees.
 
3278
    """
 
3279
 
 
3280
    takes_args = ['tree']
 
3281
 
 
3282
    def run(self, tree):
 
3283
        containing_tree, subdir = WorkingTree.open_containing(tree)
 
3284
        sub_id = containing_tree.path2id(subdir)
 
3285
        if sub_id is None:
 
3286
            raise errors.NotVersionedError(subdir)
 
3287
        try:
 
3288
            containing_tree.extract(sub_id)
 
3289
        except errors.RootNotRich:
 
3290
            raise errors.UpgradeRequired(containing_tree.branch.base)
 
3291
 
 
3292
 
 
3293
 
 
3294
class cmd_tag(Command):
 
3295
    """Create a tag naming a revision.
 
3296
    
 
3297
    Tags give human-meaningful names to revisions.  Commands that take a -r
 
3298
    (--revision) option can be given -rtag:X, where X is any previously
 
3299
    created tag.
 
3300
 
 
3301
    Tags are stored in the branch.  Tags are copied from one branch to another
 
3302
    along when you branch, push, pull or merge.
 
3303
 
 
3304
    It is an error to give a tag name that already exists unless you pass 
 
3305
    --force, in which case the tag is moved to point to the new revision.
 
3306
    """
 
3307
 
 
3308
    takes_args = ['tag_name']
 
3309
    takes_options = [
 
3310
        Option('delete',
 
3311
            help='Delete this tag rather than placing it.',
 
3312
            ),
 
3313
        Option('directory',
 
3314
            help='Branch in which to place the tag.',
 
3315
            short_name='d',
 
3316
            type=unicode,
 
3317
            ),
 
3318
        Option('force',
 
3319
            help='Replace existing tags',
 
3320
            ),
 
3321
        'revision',
 
3322
        ]
 
3323
 
 
3324
    def run(self, tag_name,
 
3325
            delete=None,
 
3326
            directory='.',
 
3327
            force=None,
 
3328
            revision=None,
 
3329
            ):
 
3330
        branch, relpath = Branch.open_containing(directory)
 
3331
        branch.lock_write()
 
3332
        try:
 
3333
            if delete:
 
3334
                branch.tags.delete_tag(tag_name)
 
3335
                self.outf.write('Deleted tag %s.\n' % tag_name)
 
3336
            else:
 
3337
                if revision:
 
3338
                    if len(revision) != 1:
 
3339
                        raise errors.BzrCommandError(
 
3340
                            "Tags can only be placed on a single revision, "
 
3341
                            "not on a range")
 
3342
                    revision_id = revision[0].in_history(branch).rev_id
 
3343
                else:
 
3344
                    revision_id = branch.last_revision()
 
3345
                if (not force) and branch.tags.has_tag(tag_name):
 
3346
                    raise errors.TagAlreadyExists(tag_name)
 
3347
                branch.tags.set_tag(tag_name, revision_id)
 
3348
                self.outf.write('Created tag %s.\n' % tag_name)
 
3349
        finally:
 
3350
            branch.unlock()
 
3351
 
 
3352
 
 
3353
class cmd_tags(Command):
 
3354
    """List tags.
 
3355
 
 
3356
    This tag shows a table of tag names and the revisions they reference.
 
3357
    """
 
3358
 
 
3359
    takes_options = [
 
3360
        Option('directory',
 
3361
            help='Branch whose tags should be displayed',
 
3362
            short_name='d',
 
3363
            type=unicode,
 
3364
            ),
 
3365
    ]
 
3366
 
 
3367
    @display_command
 
3368
    def run(self,
 
3369
            directory='.',
 
3370
            ):
 
3371
        branch, relpath = Branch.open_containing(directory)
 
3372
        for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
 
3373
            self.outf.write('%-20s %s\n' % (tag_name, target))
 
3374
 
2594
3375
 
2595
3376
# command-line interpretation helper for merge-related commands
2596
 
def merge(other_revision, base_revision,
2597
 
          check_clean=True, ignore_zero=False,
2598
 
          this_dir=None, backup_files=False, merge_type=Merge3Merger,
2599
 
          file_list=None, show_base=False, reprocess=False,
2600
 
          pb=DummyProgress()):
 
3377
def _merge_helper(other_revision, base_revision,
 
3378
                  check_clean=True, ignore_zero=False,
 
3379
                  this_dir=None, backup_files=False,
 
3380
                  merge_type=None,
 
3381
                  file_list=None, show_base=False, reprocess=False,
 
3382
                  pull=False,
 
3383
                  pb=DummyProgress(),
 
3384
                  change_reporter=None):
2601
3385
    """Merge changes into a tree.
2602
3386
 
2603
3387
    base_revision
2625
3409
    clients might prefer to call merge.merge_inner(), which has less magic 
2626
3410
    behavior.
2627
3411
    """
2628
 
    from bzrlib.merge import Merger
 
3412
    # Loading it late, so that we don't always have to import bzrlib.merge
 
3413
    if merge_type is None:
 
3414
        merge_type = _mod_merge.Merge3Merger
2629
3415
    if this_dir is None:
2630
3416
        this_dir = u'.'
2631
3417
    this_tree = WorkingTree.open_containing(this_dir)[0]
2632
 
    if show_base and not merge_type is Merge3Merger:
2633
 
        raise BzrCommandError("Show-base is not supported for this merge"
2634
 
                              " type. %s" % merge_type)
 
3418
    if show_base and not merge_type is _mod_merge.Merge3Merger:
 
3419
        raise errors.BzrCommandError("Show-base is not supported for this merge"
 
3420
                                     " type. %s" % merge_type)
2635
3421
    if reprocess and not merge_type.supports_reprocess:
2636
 
        raise BzrCommandError("Conflict reduction is not supported for merge"
2637
 
                              " type %s." % merge_type)
 
3422
        raise errors.BzrCommandError("Conflict reduction is not supported for merge"
 
3423
                                     " type %s." % merge_type)
2638
3424
    if reprocess and show_base:
2639
 
        raise BzrCommandError("Cannot do conflict reduction and show base.")
 
3425
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
 
3426
    # TODO: jam 20070226 We should really lock these trees earlier. However, we
 
3427
    #       only want to take out a lock_tree_write() if we don't have to pull
 
3428
    #       any ancestry. But merge might fetch ancestry in the middle, in
 
3429
    #       which case we would need a lock_write().
 
3430
    #       Because we cannot upgrade locks, for now we live with the fact that
 
3431
    #       the tree will be locked multiple times during a merge. (Maybe
 
3432
    #       read-only some of the time, but it means things will get read
 
3433
    #       multiple times.)
2640
3434
    try:
2641
 
        merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
 
3435
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
 
3436
                                   pb=pb, change_reporter=change_reporter)
2642
3437
        merger.pp = ProgressPhase("Merge phase", 5, pb)
2643
3438
        merger.pp.next_phase()
2644
3439
        merger.check_basis(check_clean)
2648
3443
        if merger.base_rev_id == merger.other_rev_id:
2649
3444
            note('Nothing to do.')
2650
3445
            return 0
 
3446
        if file_list is None:
 
3447
            if pull and merger.base_rev_id == merger.this_rev_id:
 
3448
                # FIXME: deduplicate with pull
 
3449
                result = merger.this_tree.pull(merger.this_branch,
 
3450
                        False, merger.other_rev_id)
 
3451
                if result.old_revid == result.new_revid:
 
3452
                    note('No revisions to pull.')
 
3453
                else:
 
3454
                    note('Now on revision %d.' % result.new_revno)
 
3455
                return 0
2651
3456
        merger.backup_files = backup_files
2652
3457
        merger.merge_type = merge_type 
2653
3458
        merger.set_interesting_files(file_list)
2661
3466
    return conflicts
2662
3467
 
2663
3468
 
 
3469
# Compatibility
 
3470
merge = _merge_helper
 
3471
 
 
3472
 
2664
3473
# these get imported and then picked up by the scan for cmd_*
2665
3474
# TODO: Some more consistent way to split command definitions across files;
2666
3475
# we do need to load at least some information about them to know of 
2667
3476
# aliases.  ideally we would avoid loading the implementation until the
2668
3477
# details were needed.
 
3478
from bzrlib.cmd_version_info import cmd_version_info
2669
3479
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2670
3480
from bzrlib.bundle.commands import cmd_bundle_revisions
2671
3481
from bzrlib.sign_my_commits import cmd_sign_my_commits