~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Alexander Belchenko
  • Date: 2006-07-31 16:12:57 UTC
  • mto: (1711.2.111 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1906.
  • Revision ID: bialix@ukr.net-20060731161257-91a231523255332c
new official bzr.ico

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
2
 
 
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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
17
17
"""builtin bzr commands"""
18
18
 
19
19
 
 
20
import codecs
20
21
import errno
21
22
import os
22
 
from shutil import rmtree
 
23
import os.path
23
24
import sys
24
25
 
25
26
import bzrlib
26
 
import bzrlib.branch
27
 
from bzrlib.branch import Branch
28
 
import bzrlib.bzrdir as bzrdir
 
27
from bzrlib import (
 
28
    branch,
 
29
    bundle,
 
30
    bzrdir,
 
31
    config,
 
32
    errors,
 
33
    ignores,
 
34
    log,
 
35
    osutils,
 
36
    repository,
 
37
    transport,
 
38
    ui,
 
39
    urlutils,
 
40
    )
 
41
from bzrlib.branch import Branch, BranchReferenceFormat
 
42
from bzrlib.bundle import read_bundle_from_url
 
43
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
 
44
from bzrlib.conflicts import ConflictList
29
45
from bzrlib.commands import Command, display_command
30
 
from bzrlib.revision import common_ancestor
31
 
import bzrlib.errors as errors
32
46
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
33
47
                           NotBranchError, DivergedBranches, NotConflicted,
34
48
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
35
 
                           NotVersionedError)
36
 
from bzrlib.log import show_one_log
 
49
                           NotVersionedError, NotABundle)
37
50
from bzrlib.merge import Merge3Merger
38
51
from bzrlib.option import Option
39
52
from bzrlib.progress import DummyProgress, ProgressPhase
 
53
from bzrlib.revision import common_ancestor
40
54
from bzrlib.revisionspec import RevisionSpec
41
 
import bzrlib.trace
42
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
 
55
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
43
56
from bzrlib.transport.local import LocalTransport
44
 
import bzrlib.ui
45
57
from bzrlib.workingtree import WorkingTree
46
58
 
47
59
 
85
97
    """Parse and return a format specifier."""
86
98
    if typestring == "weave":
87
99
        return bzrdir.BzrDirFormat6()
88
 
    if typestring == "metadir":
 
100
    if typestring == "default":
89
101
        return bzrdir.BzrDirMetaFormat1()
 
102
    if typestring == "metaweave":
 
103
        format = bzrdir.BzrDirMetaFormat1()
 
104
        format.repository_format = repository.RepositoryFormat7()
 
105
        return format
90
106
    if typestring == "knit":
91
107
        format = bzrdir.BzrDirMetaFormat1()
92
 
        format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
 
108
        format.repository_format = repository.RepositoryFormatKnit1()
93
109
        return format
94
 
    msg = "No known bzr-dir format %s. Supported types are: weave, metadir\n" %\
95
 
        (typestring)
 
110
    msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
 
111
          "metaweave and weave" % typestring
96
112
    raise BzrCommandError(msg)
97
113
 
98
114
 
123
139
    modified
124
140
        Text has changed since the previous revision.
125
141
 
126
 
    unchanged
127
 
        Nothing about this file has changed since the previous revision.
128
 
        Only shown with --all.
129
 
 
130
142
    unknown
131
143
        Not versioned and not matching an ignore pattern.
132
144
 
145
157
    # TODO: --no-recurse, --recurse options
146
158
    
147
159
    takes_args = ['file*']
148
 
    takes_options = ['all', 'show-ids', 'revision']
 
160
    takes_options = ['show-ids', 'revision']
149
161
    aliases = ['st', 'stat']
 
162
 
 
163
    encoding_type = 'replace'
150
164
    
151
165
    @display_command
152
 
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
153
 
        tree, file_list = tree_files(file_list)
154
 
            
 
166
    def run(self, show_ids=False, file_list=None, revision=None):
155
167
        from bzrlib.status import show_tree_status
156
 
        show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
157
 
                         specific_files=file_list, revision=revision)
 
168
 
 
169
        tree, file_list = tree_files(file_list)
 
170
            
 
171
        show_tree_status(tree, show_ids=show_ids,
 
172
                         specific_files=file_list, revision=revision,
 
173
                         to_file=self.outf)
158
174
 
159
175
 
160
176
class cmd_cat_revision(Command):
167
183
    hidden = True
168
184
    takes_args = ['revision_id?']
169
185
    takes_options = ['revision']
 
186
    # cat-revision is more for frontends so should be exact
 
187
    encoding = 'strict'
170
188
    
171
189
    @display_command
172
190
    def run(self, revision_id=None, revision=None):
176
194
        if revision_id is None and revision is None:
177
195
            raise BzrCommandError('You must supply either --revision or a revision_id')
178
196
        b = WorkingTree.open_containing(u'.')[0].branch
 
197
 
 
198
        # TODO: jam 20060112 should cat-revision always output utf-8?
179
199
        if revision_id is not None:
180
 
            sys.stdout.write(b.repository.get_revision_xml(revision_id))
 
200
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
181
201
        elif revision is not None:
182
202
            for rev in revision:
183
203
                if rev is None:
184
204
                    raise BzrCommandError('You cannot specify a NULL revision.')
185
205
                revno, rev_id = rev.in_history(b)
186
 
                sys.stdout.write(b.repository.get_revision_xml(rev_id))
 
206
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
187
207
    
188
208
 
189
209
class cmd_revno(Command):
190
210
    """Show current revision number.
191
211
 
192
 
    This is equal to the number of revisions on this branch."""
 
212
    This is equal to the number of revisions on this branch.
 
213
    """
 
214
 
193
215
    takes_args = ['location?']
 
216
 
194
217
    @display_command
195
218
    def run(self, location=u'.'):
196
 
        print Branch.open_containing(location)[0].revno()
 
219
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
 
220
        self.outf.write('\n')
197
221
 
198
222
 
199
223
class cmd_revision_info(Command):
202
226
    hidden = True
203
227
    takes_args = ['revision_info*']
204
228
    takes_options = ['revision']
 
229
 
205
230
    @display_command
206
231
    def run(self, revision=None, revision_info_list=[]):
207
232
 
244
269
 
245
270
    Adding a file whose parent directory is not versioned will
246
271
    implicitly add the parent, and so on up to the root. This means
247
 
    you should never need to explictly add a directory, they'll just
 
272
    you should never need to explicitly add a directory, they'll just
248
273
    get added when you add a file in the directory.
249
274
 
250
275
    --dry-run will show which files would be added, but not actually 
252
277
    """
253
278
    takes_args = ['file*']
254
279
    takes_options = ['no-recurse', 'dry-run', 'verbose']
 
280
    encoding_type = 'replace'
255
281
 
256
282
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
257
283
        import bzrlib.add
258
284
 
259
 
        if dry_run:
260
 
            if is_quiet():
261
 
                # This is pointless, but I'd rather not raise an error
262
 
                action = bzrlib.add.add_action_null
263
 
            else:
264
 
                action = bzrlib.add.add_action_print
265
 
        elif is_quiet():
266
 
            action = bzrlib.add.add_action_add
267
 
        else:
268
 
            action = bzrlib.add.add_action_add_and_print
 
285
        action = bzrlib.add.AddAction(to_file=self.outf,
 
286
            should_print=(not is_quiet()))
269
287
 
270
288
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
271
 
                                              action)
 
289
                                              action=action, save=not dry_run)
272
290
        if len(ignored) > 0:
273
 
            for glob in sorted(ignored.keys()):
274
 
                match_len = len(ignored[glob])
275
 
                if verbose:
 
291
            if verbose:
 
292
                for glob in sorted(ignored.keys()):
276
293
                    for path in ignored[glob]:
277
 
                        print "ignored %s matching \"%s\"" % (path, glob)
278
 
                else:
279
 
                    print "ignored %d file(s) matching \"%s\"" % (match_len,
280
 
                                                              glob)
281
 
            print "If you wish to add some of these files, please add them"\
282
 
                " by name."
 
294
                        self.outf.write("ignored %s matching \"%s\"\n" 
 
295
                                        % (path, glob))
 
296
            else:
 
297
                match_len = 0
 
298
                for glob, paths in ignored.items():
 
299
                    match_len += len(paths)
 
300
                self.outf.write("ignored %d file(s).\n" % match_len)
 
301
            self.outf.write("If you wish to add some of these files,"
 
302
                            " please add them by name.\n")
283
303
 
284
304
 
285
305
class cmd_mkdir(Command):
287
307
 
288
308
    This is equivalent to creating the directory and then adding it.
289
309
    """
 
310
 
290
311
    takes_args = ['dir+']
 
312
    encoding_type = 'replace'
291
313
 
292
314
    def run(self, dir_list):
293
315
        for d in dir_list:
294
316
            os.mkdir(d)
295
317
            wt, dd = WorkingTree.open_containing(d)
296
318
            wt.add([dd])
297
 
            print 'added', d
 
319
            self.outf.write('added %s\n' % d)
298
320
 
299
321
 
300
322
class cmd_relpath(Command):
301
323
    """Show path of a file relative to root"""
 
324
 
302
325
    takes_args = ['filename']
303
326
    hidden = True
304
327
    
305
328
    @display_command
306
329
    def run(self, filename):
 
330
        # TODO: jam 20050106 Can relpath return a munged path if
 
331
        #       sys.stdout encoding cannot represent it?
307
332
        tree, relpath = WorkingTree.open_containing(filename)
308
 
        print relpath
 
333
        self.outf.write(relpath)
 
334
        self.outf.write('\n')
309
335
 
310
336
 
311
337
class cmd_inventory(Command):
314
340
    It is possible to limit the output to a particular entry
315
341
    type using the --kind option.  For example; --kind file.
316
342
    """
 
343
 
317
344
    takes_options = ['revision', 'show-ids', 'kind']
318
345
    
319
346
    @display_command
334
361
            if kind and kind != entry.kind:
335
362
                continue
336
363
            if show_ids:
337
 
                print '%-50s %s' % (path, entry.file_id)
 
364
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
338
365
            else:
339
 
                print path
 
366
                self.outf.write(path)
 
367
                self.outf.write('\n')
340
368
 
341
369
 
342
370
class cmd_mv(Command):
352
380
 
353
381
    Files cannot be moved between branches.
354
382
    """
 
383
 
355
384
    takes_args = ['names*']
356
385
    aliases = ['move', 'rename']
 
386
    encoding_type = 'replace'
357
387
 
358
388
    def run(self, names_list):
 
389
        if names_list is None:
 
390
            names_list = []
 
391
 
359
392
        if len(names_list) < 2:
360
393
            raise BzrCommandError("missing file argument")
361
394
        tree, rel_names = tree_files(names_list)
363
396
        if os.path.isdir(names_list[-1]):
364
397
            # move into existing directory
365
398
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
366
 
                print "%s => %s" % pair
 
399
                self.outf.write("%s => %s\n" % pair)
367
400
        else:
368
401
            if len(names_list) != 2:
369
402
                raise BzrCommandError('to mv multiple files the destination '
370
403
                                      'must be a versioned directory')
371
404
            tree.rename_one(rel_names[0], rel_names[1])
372
 
            print "%s => %s" % (rel_names[0], rel_names[1])
 
405
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
373
406
            
374
407
    
375
408
class cmd_pull(Command):
383
416
    from one into the other.  Once one branch has merged, the other should
384
417
    be able to pull it again.
385
418
 
386
 
    If branches have diverged, you can use 'bzr merge' to pull the text changes
387
 
    from one into the other.  Once one branch has merged, the other should
388
 
    be able to pull it again.
389
 
 
390
419
    If you want to forget your local changes and just update your branch to
391
420
    match the remote one, use pull --overwrite.
392
421
 
393
422
    If there is no default location set, the first pull will set it.  After
394
423
    that, you can omit the location to use the default.  To change the
395
 
    default, use --remember.
 
424
    default, use --remember. The value will only be saved if the remote
 
425
    location can be accessed.
396
426
    """
 
427
 
397
428
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
398
429
    takes_args = ['location?']
 
430
    encoding_type = 'replace'
399
431
 
400
432
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
401
433
        # FIXME: too much stuff is in the command class
404
436
            branch_to = tree_to.branch
405
437
        except NoWorkingTree:
406
438
            tree_to = None
407
 
            branch_to = Branch.open_containing(u'.')[0] 
 
439
            branch_to = Branch.open_containing(u'.')[0]
 
440
 
 
441
        reader = None
 
442
        if location is not None:
 
443
            try:
 
444
                reader = bundle.read_bundle_from_url(location)
 
445
            except NotABundle:
 
446
                pass # Continue on considering this url a Branch
 
447
 
408
448
        stored_loc = branch_to.get_parent()
409
449
        if location is None:
410
450
            if stored_loc is None:
411
451
                raise BzrCommandError("No pull location known or specified.")
412
452
            else:
413
 
                print "Using saved location: %s" % stored_loc
 
453
                display_url = urlutils.unescape_for_display(stored_loc,
 
454
                        self.outf.encoding)
 
455
                self.outf.write("Using saved location: %s\n" % display_url)
414
456
                location = stored_loc
415
457
 
416
 
        if branch_to.get_parent() is None or remember:
417
 
            branch_to.set_parent(location)
418
 
 
419
 
        branch_from = Branch.open(location)
420
 
 
 
458
 
 
459
        if reader is not None:
 
460
            install_bundle(branch_to.repository, reader)
 
461
            branch_from = branch_to
 
462
        else:
 
463
            branch_from = Branch.open(location)
 
464
 
 
465
            if branch_to.get_parent() is None or remember:
 
466
                branch_to.set_parent(branch_from.base)
 
467
 
 
468
        rev_id = None
421
469
        if revision is None:
422
 
            rev_id = None
 
470
            if reader is not None:
 
471
                rev_id = reader.target
423
472
        elif len(revision) == 1:
424
473
            rev_id = revision[0].in_history(branch_from).rev_id
425
474
        else:
437
486
            if old_rh != new_rh:
438
487
                # Something changed
439
488
                from bzrlib.log import show_changed_revisions
440
 
                show_changed_revisions(branch_to, old_rh, new_rh)
 
489
                show_changed_revisions(branch_to, old_rh, new_rh,
 
490
                                       to_file=self.outf)
441
491
 
442
492
 
443
493
class cmd_push(Command):
462
512
 
463
513
    If there is no default push location set, the first push will set it.
464
514
    After that, you can omit the location to use the default.  To change the
465
 
    default, use --remember.
 
515
    default, use --remember. The value will only be saved if the remote
 
516
    location can be accessed.
466
517
    """
467
 
    takes_options = ['remember', 'overwrite', 
 
518
 
 
519
    takes_options = ['remember', 'overwrite', 'verbose',
468
520
                     Option('create-prefix', 
469
521
                            help='Create the path leading up to the branch '
470
522
                                 'if it does not already exist')]
471
523
    takes_args = ['location?']
 
524
    encoding_type = 'replace'
472
525
 
473
526
    def run(self, location=None, remember=False, overwrite=False,
474
527
            create_prefix=False, verbose=False):
475
528
        # FIXME: Way too big!  Put this into a function called from the
476
529
        # command.
477
 
        from bzrlib.transport import get_transport
478
530
        
479
 
        tree_from = WorkingTree.open_containing(u'.')[0]
480
 
        br_from = tree_from.branch
481
 
        stored_loc = tree_from.branch.get_push_location()
 
531
        br_from = Branch.open_containing('.')[0]
 
532
        stored_loc = br_from.get_push_location()
482
533
        if location is None:
483
534
            if stored_loc is None:
484
535
                raise BzrCommandError("No push location known or specified.")
485
536
            else:
486
 
                print "Using saved location: %s" % stored_loc
 
537
                display_url = urlutils.unescape_for_display(stored_loc,
 
538
                        self.outf.encoding)
 
539
                self.outf.write("Using saved location: %s\n" % display_url)
487
540
                location = stored_loc
488
 
        if br_from.get_push_location() is None or remember:
489
 
            br_from.set_push_location(location)
 
541
 
 
542
        to_transport = transport.get_transport(location)
 
543
        location_url = to_transport.base
 
544
 
 
545
        old_rh = []
490
546
        try:
491
 
            dir_to = bzrlib.bzrdir.BzrDir.open(location)
 
547
            dir_to = bzrdir.BzrDir.open(location_url)
492
548
            br_to = dir_to.open_branch()
493
549
        except NotBranchError:
494
550
            # create a branch.
495
 
            transport = get_transport(location).clone('..')
 
551
            to_transport = to_transport.clone('..')
496
552
            if not create_prefix:
497
553
                try:
498
 
                    transport.mkdir(transport.relpath(location))
 
554
                    relurl = to_transport.relpath(location_url)
 
555
                    mutter('creating directory %s => %s', location_url, relurl)
 
556
                    to_transport.mkdir(relurl)
499
557
                except NoSuchFile:
500
558
                    raise BzrCommandError("Parent directory of %s "
501
559
                                          "does not exist." % location)
502
560
            else:
503
 
                current = transport.base
504
 
                needed = [(transport, transport.relpath(location))]
 
561
                current = to_transport.base
 
562
                needed = [(to_transport, to_transport.relpath(location_url))]
505
563
                while needed:
506
564
                    try:
507
 
                        transport, relpath = needed[-1]
508
 
                        transport.mkdir(relpath)
 
565
                        to_transport, relpath = needed[-1]
 
566
                        to_transport.mkdir(relpath)
509
567
                        needed.pop()
510
568
                    except NoSuchFile:
511
 
                        new_transport = transport.clone('..')
 
569
                        new_transport = to_transport.clone('..')
512
570
                        needed.append((new_transport,
513
 
                                       new_transport.relpath(transport.base)))
514
 
                        if new_transport.base == transport.base:
 
571
                                       new_transport.relpath(to_transport.base)))
 
572
                        if new_transport.base == to_transport.base:
515
573
                            raise BzrCommandError("Could not create "
516
574
                                                  "path prefix.")
517
 
            dir_to = br_from.bzrdir.clone(location)
 
575
            dir_to = br_from.bzrdir.clone(location_url,
 
576
                revision_id=br_from.last_revision())
518
577
            br_to = dir_to.open_branch()
519
 
        old_rh = br_to.revision_history()
520
 
        try:
 
578
            count = len(br_to.revision_history())
 
579
            # We successfully created the target, remember it
 
580
            if br_from.get_push_location() is None or remember:
 
581
                br_from.set_push_location(br_to.base)
 
582
        else:
 
583
            # We were able to connect to the remote location, so remember it
 
584
            # we don't need to successfully push because of possible divergence.
 
585
            if br_from.get_push_location() is None or remember:
 
586
                br_from.set_push_location(br_to.base)
 
587
            old_rh = br_to.revision_history()
521
588
            try:
522
 
                tree_to = dir_to.open_workingtree()
523
 
            except errors.NotLocalUrl:
524
 
                # TODO: This should be updated for branches which don't have a
525
 
                # working tree, as opposed to ones where we just couldn't 
526
 
                # update the tree.
527
 
                warning('This transport does not update the working '
528
 
                        'tree of: %s' % (br_to.base,))
529
 
                count = br_to.pull(br_from, overwrite)
530
 
            except NoWorkingTree:
531
 
                count = br_to.pull(br_from, overwrite)
532
 
            else:
533
 
                count = tree_to.pull(br_from, overwrite)
534
 
        except DivergedBranches:
535
 
            raise BzrCommandError("These branches have diverged."
536
 
                                  "  Try a merge then push with overwrite.")
 
589
                try:
 
590
                    tree_to = dir_to.open_workingtree()
 
591
                except errors.NotLocalUrl:
 
592
                    warning('This transport does not update the working '
 
593
                            'tree of: %s' % (br_to.base,))
 
594
                    count = br_to.pull(br_from, overwrite)
 
595
                except NoWorkingTree:
 
596
                    count = br_to.pull(br_from, overwrite)
 
597
                else:
 
598
                    count = tree_to.pull(br_from, overwrite)
 
599
            except DivergedBranches:
 
600
                raise BzrCommandError("These branches have diverged."
 
601
                                      "  Try a merge then push with overwrite.")
537
602
        note('%d revision(s) pushed.' % (count,))
538
603
 
539
604
        if verbose:
541
606
            if old_rh != new_rh:
542
607
                # Something changed
543
608
                from bzrlib.log import show_changed_revisions
544
 
                show_changed_revisions(br_to, old_rh, new_rh)
 
609
                show_changed_revisions(br_to, old_rh, new_rh,
 
610
                                       to_file=self.outf)
545
611
 
546
612
 
547
613
class cmd_branch(Command):
593
659
                name = None
594
660
            else:
595
661
                name = os.path.basename(to_location) + '\n'
 
662
 
 
663
            to_transport = transport.get_transport(to_location)
596
664
            try:
597
 
                os.mkdir(to_location)
598
 
            except OSError, e:
599
 
                if e.errno == errno.EEXIST:
600
 
                    raise BzrCommandError('Target directory "%s" already'
601
 
                                          ' exists.' % to_location)
602
 
                if e.errno == errno.ENOENT:
603
 
                    raise BzrCommandError('Parent of "%s" does not exist.' %
604
 
                                          to_location)
605
 
                else:
606
 
                    raise
 
665
                to_transport.mkdir('.')
 
666
            except errors.FileExists:
 
667
                raise BzrCommandError('Target directory "%s" already'
 
668
                                      ' exists.' % to_location)
 
669
            except errors.NoSuchFile:
 
670
                raise BzrCommandError('Parent of "%s" does not exist.' %
 
671
                                      to_location)
607
672
            try:
608
673
                # preserve whatever source format we have.
609
 
                dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
 
674
                dir = br_from.bzrdir.sprout(to_transport.base,
 
675
                        revision_id, basis_dir)
610
676
                branch = dir.open_branch()
611
 
            except bzrlib.errors.NoSuchRevision:
612
 
                rmtree(to_location)
 
677
            except errors.NoSuchRevision:
 
678
                to_transport.delete_tree('.')
613
679
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
614
680
                raise BzrCommandError(msg)
615
 
            except bzrlib.errors.UnlistableBranch:
616
 
                rmtree(to_location)
 
681
            except errors.UnlistableBranch:
 
682
                osutils.rmtree(to_location)
617
683
                msg = "The branch %s cannot be used as a --basis" % (basis,)
618
684
                raise BzrCommandError(msg)
619
685
            if name:
620
686
                branch.control_files.put_utf8('branch-name', name)
621
 
 
622
687
            note('Branched %d revision(s).' % branch.revno())
623
688
        finally:
624
689
            br_from.unlock()
642
707
 
643
708
    --basis is to speed up checking out from remote branches.  When specified, it
644
709
    uses the inventory and file contents from the basis branch in preference to the
645
 
    branch being checked out. [Not implemented yet.]
 
710
    branch being checked out.
646
711
    """
647
712
    takes_args = ['branch_location?', 'to_location?']
648
713
    takes_options = ['revision', # , 'basis']
654
719
                                 "such access, and also support local commits."
655
720
                            ),
656
721
                     ]
 
722
    aliases = ['co']
657
723
 
658
724
    def run(self, branch_location=None, to_location=None, revision=None, basis=None,
659
725
            lightweight=False):
663
729
            raise BzrCommandError(
664
730
                'bzr checkout --revision takes exactly 1 revision value')
665
731
        if branch_location is None:
666
 
            branch_location = bzrlib.osutils.getcwd()
 
732
            branch_location = osutils.getcwd()
667
733
            to_location = branch_location
668
734
        source = Branch.open(branch_location)
669
735
        if len(revision) == 1 and revision[0] is not None:
675
741
        # if the source and to_location are the same, 
676
742
        # and there is no working tree,
677
743
        # then reconstitute a branch
678
 
        if (bzrlib.osutils.abspath(to_location) == 
679
 
            bzrlib.osutils.abspath(branch_location)):
 
744
        if (osutils.abspath(to_location) == 
 
745
            osutils.abspath(branch_location)):
680
746
            try:
681
747
                source.bzrdir.open_workingtree()
682
748
            except errors.NoWorkingTree:
693
759
                                      to_location)
694
760
            else:
695
761
                raise
696
 
        old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
697
 
        bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
 
762
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
763
        bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
698
764
        try:
699
765
            if lightweight:
700
766
                checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
701
 
                bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
767
                branch.BranchReferenceFormat().initialize(checkout, source)
702
768
            else:
703
 
                checkout_branch =  bzrlib.bzrdir.BzrDir.create_branch_convenience(
 
769
                checkout_branch =  bzrdir.BzrDir.create_branch_convenience(
704
770
                    to_location, force_new_tree=False)
705
771
                checkout = checkout_branch.bzrdir
706
772
                checkout_branch.bind(source)
709
775
                    checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
710
776
            checkout.create_workingtree(revision_id)
711
777
        finally:
712
 
            bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
 
778
            bzrdir.BzrDirFormat.set_default_format(old_format)
713
779
 
714
780
 
715
781
class cmd_renames(Command):
722
788
 
723
789
    @display_command
724
790
    def run(self, dir=u'.'):
 
791
        from bzrlib.tree import find_renames
725
792
        tree = WorkingTree.open_containing(dir)[0]
726
793
        old_inv = tree.basis_tree().inventory
727
794
        new_inv = tree.read_working_inventory()
728
 
 
729
 
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
 
795
        renames = list(find_renames(old_inv, new_inv))
730
796
        renames.sort()
731
797
        for old_name, new_name in renames:
732
 
            print "%s => %s" % (old_name, new_name)        
 
798
            self.outf.write("%s => %s\n" % (old_name, new_name))
733
799
 
734
800
 
735
801
class cmd_update(Command):
743
809
    'bzr revert' instead of 'bzr commit' after the update.
744
810
    """
745
811
    takes_args = ['dir?']
 
812
    aliases = ['up']
746
813
 
747
814
    def run(self, dir='.'):
748
815
        tree = WorkingTree.open_containing(dir)[0]
749
816
        tree.lock_write()
750
817
        try:
751
 
            if tree.last_revision() == tree.branch.last_revision():
 
818
            last_rev = tree.last_revision() 
 
819
            if last_rev == tree.branch.last_revision():
752
820
                # may be up to date, check master too.
753
821
                master = tree.branch.get_master_branch()
754
 
                if master is None or master.last_revision == tree.last_revision():
755
 
                    note("Tree is up to date.")
756
 
                    return
 
822
                if master is None or last_rev == master.last_revision():
 
823
                    revno = tree.branch.revision_id_to_revno(last_rev)
 
824
                    note("Tree is up to date at revision %d." % (revno,))
 
825
                    return 0
757
826
            conflicts = tree.update()
758
 
            note('Updated to revision %d.' %
759
 
                 (tree.branch.revision_id_to_revno(tree.last_revision()),))
 
827
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
 
828
            note('Updated to revision %d.' % (revno,))
760
829
            if conflicts != 0:
761
830
                return 1
762
831
            else:
766
835
 
767
836
 
768
837
class cmd_info(Command):
769
 
    """Show statistical information about a branch."""
770
 
    takes_args = ['branch?']
 
838
    """Show information about a working tree, branch or repository.
 
839
 
 
840
    This command will show all known locations and formats associated to the
 
841
    tree, branch or repository.  Statistical information is included with
 
842
    each report.
 
843
 
 
844
    Branches and working trees will also report any missing revisions.
 
845
    """
 
846
    takes_args = ['location?']
771
847
    takes_options = ['verbose']
772
 
    
 
848
 
773
849
    @display_command
774
 
    def run(self, branch=None, verbose=False):
775
 
        import bzrlib.info
776
 
        bzrlib.info.show_bzrdir_info(bzrdir.BzrDir.open_containing(branch)[0],
777
 
                                     verbose=verbose)
 
850
    def run(self, location=None, verbose=False):
 
851
        from bzrlib.info import show_bzrdir_info
 
852
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
 
853
                         verbose=verbose)
778
854
 
779
855
 
780
856
class cmd_remove(Command):
782
858
 
783
859
    This makes bzr stop tracking changes to a versioned file.  It does
784
860
    not delete the working copy.
 
861
 
 
862
    You can specify one or more files, and/or --new.  If you specify --new,
 
863
    only 'added' files will be removed.  If you specify both, then new files
 
864
    in the specified directories will be removed.  If the directories are
 
865
    also new, they will also be removed.
785
866
    """
786
 
    takes_args = ['file+']
787
 
    takes_options = ['verbose']
 
867
    takes_args = ['file*']
 
868
    takes_options = ['verbose', Option('new', help='remove newly-added files')]
788
869
    aliases = ['rm']
 
870
    encoding_type = 'replace'
789
871
    
790
 
    def run(self, file_list, verbose=False):
 
872
    def run(self, file_list, verbose=False, new=False):
791
873
        tree, file_list = tree_files(file_list)
792
 
        tree.remove(file_list, verbose=verbose)
 
874
        if new is False:
 
875
            if file_list is None:
 
876
                raise BzrCommandError('Specify one or more files to remove, or'
 
877
                                      ' use --new.')
 
878
        else:
 
879
            added = tree.changes_from(tree.basis_tree(),
 
880
                specific_files=file_list).added
 
881
            file_list = sorted([f[0] for f in added], reverse=True)
 
882
            if len(file_list) == 0:
 
883
                raise BzrCommandError('No matching files.')
 
884
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
793
885
 
794
886
 
795
887
class cmd_file_id(Command):
799
891
    same through all revisions where the file exists, even when it is
800
892
    moved or renamed.
801
893
    """
 
894
 
802
895
    hidden = True
803
896
    takes_args = ['filename']
 
897
 
804
898
    @display_command
805
899
    def run(self, filename):
806
900
        tree, relpath = WorkingTree.open_containing(filename)
808
902
        if i == None:
809
903
            raise BzrError("%r is not a versioned file" % filename)
810
904
        else:
811
 
            print i
 
905
            self.outf.write(i + '\n')
812
906
 
813
907
 
814
908
class cmd_file_path(Command):
815
909
    """Print path of file_ids to a file or directory.
816
910
 
817
911
    This prints one line for each directory down to the target,
818
 
    starting at the branch root."""
 
912
    starting at the branch root.
 
913
    """
 
914
 
819
915
    hidden = True
820
916
    takes_args = ['filename']
 
917
 
821
918
    @display_command
822
919
    def run(self, filename):
823
920
        tree, relpath = WorkingTree.open_containing(filename)
826
923
        if fid == None:
827
924
            raise BzrError("%r is not a versioned file" % filename)
828
925
        for fip in inv.get_idpath(fid):
829
 
            print fip
 
926
            self.outf.write(fip + '\n')
830
927
 
831
928
 
832
929
class cmd_reconcile(Command):
851
948
 
852
949
    def run(self, branch="."):
853
950
        from bzrlib.reconcile import reconcile
854
 
        dir = bzrlib.bzrdir.BzrDir.open(branch)
 
951
        dir = bzrdir.BzrDir.open(branch)
855
952
        reconcile(dir)
856
953
 
857
954
 
858
955
class cmd_revision_history(Command):
859
 
    """Display list of revision ids on this branch."""
 
956
    """Display the list of revision ids on a branch."""
 
957
    takes_args = ['location?']
 
958
 
860
959
    hidden = True
 
960
 
861
961
    @display_command
862
 
    def run(self):
863
 
        branch = WorkingTree.open_containing(u'.')[0].branch
864
 
        for patchid in branch.revision_history():
865
 
            print patchid
 
962
    def run(self, location="."):
 
963
        branch = Branch.open_containing(location)[0]
 
964
        for revid in branch.revision_history():
 
965
            self.outf.write(revid)
 
966
            self.outf.write('\n')
866
967
 
867
968
 
868
969
class cmd_ancestry(Command):
869
970
    """List all revisions merged into this branch."""
 
971
    takes_args = ['location?']
 
972
 
870
973
    hidden = True
 
974
 
871
975
    @display_command
872
 
    def run(self):
873
 
        tree = WorkingTree.open_containing(u'.')[0]
874
 
        b = tree.branch
875
 
        # FIXME. should be tree.last_revision
876
 
        for revision_id in b.repository.get_ancestry(b.last_revision()):
877
 
            print revision_id
 
976
    def run(self, location="."):
 
977
        try:
 
978
            wt = WorkingTree.open_containing(location)[0]
 
979
        except errors.NoWorkingTree:
 
980
            b = Branch.open(location)
 
981
            last_revision = b.last_revision()
 
982
        else:
 
983
            b = wt.branch
 
984
            last_revision = wt.last_revision()
 
985
 
 
986
        revision_ids = b.repository.get_ancestry(last_revision)
 
987
        assert revision_ids[0] == None
 
988
        revision_ids.pop(0)
 
989
        for revision_id in revision_ids:
 
990
            self.outf.write(revision_id + '\n')
878
991
 
879
992
 
880
993
class cmd_init(Command):
901
1014
    takes_args = ['location?']
902
1015
    takes_options = [
903
1016
                     Option('format', 
904
 
                            help='Create a specific format rather than the'
905
 
                                 ' current default format. Currently this '
906
 
                                 ' option only accepts "metadir"',
 
1017
                            help='Specify a format for this branch. Current'
 
1018
                                 ' formats are: default, knit, metaweave and'
 
1019
                                 ' weave. Default is knit; metaweave and'
 
1020
                                 ' weave are deprecated',
907
1021
                            type=get_format_type),
908
1022
                     ]
909
1023
    def run(self, location=None, format=None):
910
 
        from bzrlib.branch import Branch
 
1024
        if format is None:
 
1025
            format = get_format_type('default')
911
1026
        if location is None:
912
1027
            location = u'.'
913
 
        else:
914
 
            # The path has to exist to initialize a
915
 
            # branch inside of it.
916
 
            # Just using os.mkdir, since I don't
917
 
            # believe that we want to create a bunch of
918
 
            # locations if the user supplies an extended path
919
 
            if not os.path.exists(location):
920
 
                os.mkdir(location)
 
1028
 
 
1029
        to_transport = transport.get_transport(location)
 
1030
 
 
1031
        # The path has to exist to initialize a
 
1032
        # branch inside of it.
 
1033
        # Just using os.mkdir, since I don't
 
1034
        # believe that we want to create a bunch of
 
1035
        # locations if the user supplies an extended path
 
1036
        # TODO: create-prefix
 
1037
        try:
 
1038
            to_transport.mkdir('.')
 
1039
        except errors.FileExists:
 
1040
            pass
 
1041
                    
921
1042
        try:
922
1043
            existing_bzrdir = bzrdir.BzrDir.open(location)
923
1044
        except NotBranchError:
925
1046
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
926
1047
        else:
927
1048
            if existing_bzrdir.has_branch():
928
 
                if existing_bzrdir.has_workingtree():
929
 
                    raise errors.AlreadyBranchError(location)
930
 
                else:
931
 
                    raise errors.BranchExistsWithoutWorkingTree(location)
 
1049
                if (isinstance(to_transport, LocalTransport)
 
1050
                    and not existing_bzrdir.has_workingtree()):
 
1051
                        raise errors.BranchExistsWithoutWorkingTree(location)
 
1052
                raise errors.AlreadyBranchError(location)
932
1053
            else:
933
1054
                existing_bzrdir.create_branch()
934
1055
                existing_bzrdir.create_workingtree()
950
1071
    """
951
1072
    takes_args = ["location"] 
952
1073
    takes_options = [Option('format', 
953
 
                            help='Use a specific format rather than the'
954
 
                            ' current default format. Currently this'
955
 
                            ' option accepts "weave", "metadir" and "knit"',
 
1074
                            help='Specify a format for this repository.'
 
1075
                                 ' Current formats are: default, knit,'
 
1076
                                 ' metaweave and weave. Default is knit;'
 
1077
                                 ' metaweave and weave are deprecated',
956
1078
                            type=get_format_type),
957
1079
                     Option('trees',
958
1080
                             help='Allows branches in repository to have'
959
1081
                             ' a working tree')]
960
1082
    aliases = ["init-repo"]
961
1083
    def run(self, location, format=None, trees=False):
962
 
        from bzrlib.bzrdir import BzrDirMetaFormat1
963
 
        from bzrlib.transport import get_transport
964
1084
        if format is None:
965
 
            format = BzrDirMetaFormat1()
966
 
        transport = get_transport(location)
967
 
        if not transport.has('.'):
968
 
            transport.mkdir('')
969
 
        newdir = format.initialize_on_transport(transport)
 
1085
            format = get_format_type('default')
 
1086
 
 
1087
        if location is None:
 
1088
            location = '.'
 
1089
 
 
1090
        to_transport = transport.get_transport(location)
 
1091
        try:
 
1092
            to_transport.mkdir('.')
 
1093
        except errors.FileExists:
 
1094
            pass
 
1095
 
 
1096
        newdir = format.initialize_on_transport(to_transport)
970
1097
        repo = newdir.create_repository(shared=True)
971
1098
        repo.set_make_working_trees(trees)
972
1099
 
973
1100
 
974
1101
class cmd_diff(Command):
975
 
    """Show differences in working tree.
 
1102
    """Show differences in the working tree or between revisions.
976
1103
    
977
1104
    If files are listed, only the changes in those files are listed.
978
1105
    Otherwise, all changes for the tree are listed.
979
1106
 
 
1107
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
 
1108
    produces patches suitable for "patch -p1".
 
1109
 
980
1110
    examples:
981
1111
        bzr diff
 
1112
            Shows the difference in the working tree versus the last commit
982
1113
        bzr diff -r1
 
1114
            Difference between the working tree and revision 1
983
1115
        bzr diff -r1..2
 
1116
            Difference between revision 2 and revision 1
 
1117
        bzr diff --diff-prefix old/:new/
 
1118
            Same as 'bzr diff' but prefix paths with old/ and new/
 
1119
        bzr diff bzr.mine bzr.dev
 
1120
            Show the differences between the two working trees
 
1121
        bzr diff foo.c
 
1122
            Show just the differences for 'foo.c'
984
1123
    """
985
 
    # TODO: Allow diff across branches.
986
1124
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
987
1125
    #       or a graphical diff.
988
1126
 
989
1127
    # TODO: Python difflib is not exactly the same as unidiff; should
990
1128
    #       either fix it up or prefer to use an external diff.
991
1129
 
992
 
    # TODO: If a directory is given, diff everything under that.
993
 
 
994
1130
    # TODO: Selected-file diff is inefficient and doesn't show you
995
1131
    #       deleted files.
996
1132
 
997
1133
    # TODO: This probably handles non-Unix newlines poorly.
998
1134
    
999
1135
    takes_args = ['file*']
1000
 
    takes_options = ['revision', 'diff-options']
 
1136
    takes_options = ['revision', 'diff-options', 'prefix']
1001
1137
    aliases = ['di', 'dif']
 
1138
    encoding_type = 'exact'
1002
1139
 
1003
1140
    @display_command
1004
 
    def run(self, revision=None, file_list=None, diff_options=None):
 
1141
    def run(self, revision=None, file_list=None, diff_options=None,
 
1142
            prefix=None):
1005
1143
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
 
1144
 
 
1145
        if (prefix is None) or (prefix == '0'):
 
1146
            # diff -p0 format
 
1147
            old_label = ''
 
1148
            new_label = ''
 
1149
        elif prefix == '1':
 
1150
            old_label = 'old/'
 
1151
            new_label = 'new/'
 
1152
        else:
 
1153
            if not ':' in prefix:
 
1154
                 raise BzrError("--diff-prefix expects two values separated by a colon")
 
1155
            old_label, new_label = prefix.split(":")
 
1156
        
1006
1157
        try:
1007
1158
            tree1, file_list = internal_tree_files(file_list)
1008
1159
            tree2 = None
1018
1169
                # FIXME diff those two files. rbc 20051123
1019
1170
                raise BzrCommandError("Files are in different branches")
1020
1171
            file_list = None
 
1172
        except NotBranchError:
 
1173
            if (revision is not None and len(revision) == 2
 
1174
                and not revision[0].needs_branch()
 
1175
                and not revision[1].needs_branch()):
 
1176
                # If both revision specs include a branch, we can
 
1177
                # diff them without needing a local working tree
 
1178
                tree1, tree2 = None, None
 
1179
            else:
 
1180
                raise
1021
1181
        if revision is not None:
1022
1182
            if tree2 is not None:
1023
1183
                raise BzrCommandError("Can't specify -r with two branches")
1024
1184
            if (len(revision) == 1) or (revision[1].spec is None):
1025
1185
                return diff_cmd_helper(tree1, file_list, diff_options,
1026
 
                                       revision[0])
 
1186
                                       revision[0], 
 
1187
                                       old_label=old_label, new_label=new_label)
1027
1188
            elif len(revision) == 2:
1028
1189
                return diff_cmd_helper(tree1, file_list, diff_options,
1029
 
                                       revision[0], revision[1])
 
1190
                                       revision[0], revision[1],
 
1191
                                       old_label=old_label, new_label=new_label)
1030
1192
            else:
1031
1193
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
1032
1194
        else:
1033
1195
            if tree2 is not None:
1034
1196
                return show_diff_trees(tree1, tree2, sys.stdout, 
1035
1197
                                       specific_files=file_list,
1036
 
                                       external_diff_options=diff_options)
 
1198
                                       external_diff_options=diff_options,
 
1199
                                       old_label=old_label, new_label=new_label)
1037
1200
            else:
1038
 
                return diff_cmd_helper(tree1, file_list, diff_options)
 
1201
                return diff_cmd_helper(tree1, file_list, diff_options,
 
1202
                                       old_label=old_label, new_label=new_label)
1039
1203
 
1040
1204
 
1041
1205
class cmd_deleted(Command):
1047
1211
    # directories with readdir, rather than stating each one.  Same
1048
1212
    # level of effort but possibly much less IO.  (Or possibly not,
1049
1213
    # if the directories are very large...)
 
1214
    takes_options = ['show-ids']
 
1215
 
1050
1216
    @display_command
1051
1217
    def run(self, show_ids=False):
1052
1218
        tree = WorkingTree.open_containing(u'.')[0]
1053
1219
        old = tree.basis_tree()
1054
1220
        for path, ie in old.inventory.iter_entries():
1055
1221
            if not tree.has_id(ie.file_id):
 
1222
                self.outf.write(path)
1056
1223
                if show_ids:
1057
 
                    print '%-50s %s' % (path, ie.file_id)
1058
 
                else:
1059
 
                    print path
 
1224
                    self.outf.write(' ')
 
1225
                    self.outf.write(ie.file_id)
 
1226
                self.outf.write('\n')
1060
1227
 
1061
1228
 
1062
1229
class cmd_modified(Command):
1064
1231
    hidden = True
1065
1232
    @display_command
1066
1233
    def run(self):
1067
 
        from bzrlib.delta import compare_trees
1068
 
 
1069
1234
        tree = WorkingTree.open_containing(u'.')[0]
1070
 
        td = compare_trees(tree.basis_tree(), tree)
1071
 
 
 
1235
        td = tree.changes_from(tree.basis_tree())
1072
1236
        for path, id, kind, text_modified, meta_modified in td.modified:
1073
 
            print path
1074
 
 
 
1237
            self.outf.write(path + '\n')
1075
1238
 
1076
1239
 
1077
1240
class cmd_added(Command):
1086
1249
            if file_id in basis_inv:
1087
1250
                continue
1088
1251
            path = inv.id2path(file_id)
1089
 
            if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
 
1252
            if not os.access(osutils.abspath(path), os.F_OK):
1090
1253
                continue
1091
 
            print path
1092
 
                
1093
 
        
 
1254
            self.outf.write(path + '\n')
 
1255
 
1094
1256
 
1095
1257
class cmd_root(Command):
1096
1258
    """Show the tree root directory.
1102
1264
    def run(self, filename=None):
1103
1265
        """Print the branch root."""
1104
1266
        tree = WorkingTree.open_containing(filename)[0]
1105
 
        print tree.basedir
 
1267
        self.outf.write(tree.basedir + '\n')
1106
1268
 
1107
1269
 
1108
1270
class cmd_log(Command):
1136
1298
                            type=str),
1137
1299
                     'short',
1138
1300
                     ]
 
1301
    encoding_type = 'replace'
 
1302
 
1139
1303
    @display_command
1140
1304
    def run(self, location=None, timezone='original',
1141
1305
            verbose=False,
1148
1312
            short=False,
1149
1313
            line=False):
1150
1314
        from bzrlib.log import log_formatter, show_log
1151
 
        import codecs
1152
1315
        assert message is None or isinstance(message, basestring), \
1153
1316
            "invalid message argument %r" % message
1154
1317
        direction = (forward and 'forward') or 'reverse'
1200
1363
        if rev1 > rev2:
1201
1364
            (rev2, rev1) = (rev1, rev2)
1202
1365
 
1203
 
        mutter('encoding log as %r', bzrlib.user_encoding)
1204
 
 
1205
 
        # use 'replace' so that we don't abort if trying to write out
1206
 
        # in e.g. the default C locale.
1207
 
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1208
 
 
1209
1366
        if (log_format == None):
1210
 
            default = bzrlib.config.BranchConfig(b).log_format()
1211
 
            log_format = get_log_format(long=long, short=short, line=line, default=default)
1212
 
 
 
1367
            default = b.get_config().log_format()
 
1368
            log_format = get_log_format(long=long, short=short, line=line, 
 
1369
                                        default=default)
1213
1370
        lf = log_formatter(log_format,
1214
1371
                           show_ids=show_ids,
1215
 
                           to_file=outf,
 
1372
                           to_file=self.outf,
1216
1373
                           show_timezone=timezone)
1217
1374
 
1218
1375
        show_log(b,
1239
1396
class cmd_touching_revisions(Command):
1240
1397
    """Return revision-ids which affected a particular file.
1241
1398
 
1242
 
    A more user-friendly interface is "bzr log FILE"."""
 
1399
    A more user-friendly interface is "bzr log FILE".
 
1400
    """
 
1401
 
1243
1402
    hidden = True
1244
1403
    takes_args = ["filename"]
 
1404
 
1245
1405
    @display_command
1246
1406
    def run(self, filename):
1247
1407
        tree, relpath = WorkingTree.open_containing(filename)
1248
1408
        b = tree.branch
1249
1409
        inv = tree.read_working_inventory()
1250
1410
        file_id = inv.path2id(relpath)
1251
 
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1252
 
            print "%6d %s" % (revno, what)
 
1411
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
1412
            self.outf.write("%6d %s\n" % (revno, what))
1253
1413
 
1254
1414
 
1255
1415
class cmd_ls(Command):
1288
1448
        if revision is not None:
1289
1449
            tree = tree.branch.repository.revision_tree(
1290
1450
                revision[0].in_history(tree.branch).rev_id)
 
1451
 
1291
1452
        for fp, fc, kind, fid, entry in tree.list_files():
1292
1453
            if fp.startswith(relpath):
1293
1454
                fp = fp[len(relpath):]
1297
1458
                    continue
1298
1459
                if verbose:
1299
1460
                    kindch = entry.kind_character()
1300
 
                    print '%-8s %s%s' % (fc, fp, kindch)
 
1461
                    self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1301
1462
                elif null:
1302
 
                    sys.stdout.write(fp)
1303
 
                    sys.stdout.write('\0')
1304
 
                    sys.stdout.flush()
 
1463
                    self.outf.write(fp + '\0')
 
1464
                    self.outf.flush()
1305
1465
                else:
1306
 
                    print fp
 
1466
                    self.outf.write(fp + '\n')
1307
1467
 
1308
1468
 
1309
1469
class cmd_unknowns(Command):
1310
1470
    """List unknown files."""
1311
1471
    @display_command
1312
1472
    def run(self):
1313
 
        from bzrlib.osutils import quotefn
1314
1473
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1315
 
            print quotefn(f)
 
1474
            self.outf.write(osutils.quotefn(f) + '\n')
1316
1475
 
1317
1476
 
1318
1477
class cmd_ignore(Command):
1334
1493
        bzr ignore '*.class'
1335
1494
    """
1336
1495
    # TODO: Complain if the filename is absolute
1337
 
    takes_args = ['name_pattern']
 
1496
    takes_args = ['name_pattern?']
 
1497
    takes_options = [
 
1498
                     Option('old-default-rules',
 
1499
                            help='Out the ignore rules bzr < 0.9 always used.')
 
1500
                     ]
1338
1501
    
1339
 
    def run(self, name_pattern):
 
1502
    def run(self, name_pattern=None, old_default_rules=None):
1340
1503
        from bzrlib.atomicfile import AtomicFile
1341
 
        import os.path
1342
 
 
 
1504
        if old_default_rules is not None:
 
1505
            # dump the rules and exit
 
1506
            for pattern in ignores.OLD_DEFAULTS:
 
1507
                print pattern
 
1508
            return
 
1509
        if name_pattern is None:
 
1510
            raise BzrCommandError("ignore requires a NAME_PATTERN")
1343
1511
        tree, relpath = WorkingTree.open_containing(u'.')
1344
1512
        ifn = tree.abspath('.bzrignore')
1345
 
 
1346
1513
        if os.path.exists(ifn):
1347
1514
            f = open(ifn, 'rt')
1348
1515
            try:
1359
1526
            igns += '\n'
1360
1527
        igns += name_pattern + '\n'
1361
1528
 
 
1529
        f = AtomicFile(ifn, 'wt')
1362
1530
        try:
1363
 
            f = AtomicFile(ifn, 'wt')
1364
1531
            f.write(igns.encode('utf-8'))
1365
1532
            f.commit()
1366
1533
        finally:
1433
1600
    takes_args = ['dest']
1434
1601
    takes_options = ['revision', 'format', 'root']
1435
1602
    def run(self, dest, revision=None, format=None, root=None):
1436
 
        import os.path
1437
1603
        from bzrlib.export import export
1438
1604
        tree = WorkingTree.open_containing(u'.')[0]
1439
1605
        b = tree.branch
1482
1648
    hidden = True    
1483
1649
    @display_command
1484
1650
    def run(self):
1485
 
        print bzrlib.osutils.local_time_offset()
 
1651
        print osutils.local_time_offset()
1486
1652
 
1487
1653
 
1488
1654
 
1535
1701
        from bzrlib.msgeditor import edit_commit_message, \
1536
1702
                make_commit_message_template
1537
1703
        from tempfile import TemporaryFile
1538
 
        import codecs
1539
1704
 
1540
1705
        # TODO: Need a blackbox test for invoking the external editor; may be
1541
1706
        # slightly problematic to run this cross-platform.
1546
1711
        # TODO: if the commit *does* happen to fail, then save the commit 
1547
1712
        # message to a temporary file where it can be recovered
1548
1713
        tree, selected_list = tree_files(selected_list)
 
1714
        if selected_list == ['']:
 
1715
            # workaround - commit of root of tree should be exactly the same
 
1716
            # as just default commit in that tree, and succeed even though
 
1717
            # selected-file merge commit is not done yet
 
1718
            selected_list = []
 
1719
 
1549
1720
        if local and not tree.branch.get_bound_location():
1550
1721
            raise errors.LocalRequiresBoundBranch()
1551
1722
        if message is None and not file:
1558
1729
            raise BzrCommandError("please specify either --message or --file")
1559
1730
        
1560
1731
        if file:
1561
 
            import codecs
1562
1732
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1563
1733
 
1564
1734
        if message == "":
1565
 
                raise BzrCommandError("empty commit message specified")
 
1735
            raise BzrCommandError("empty commit message specified")
1566
1736
        
1567
1737
        if verbose:
1568
1738
            reporter = ReportCommitToLog()
1576
1746
        except PointlessCommit:
1577
1747
            # FIXME: This should really happen before the file is read in;
1578
1748
            # perhaps prepare the commit; get the message; then actually commit
1579
 
            raise BzrCommandError("no changes to commit",
1580
 
                                  ["use --unchanged to commit anyhow"])
 
1749
            raise BzrCommandError("no changes to commit."
 
1750
                                  " use --unchanged to commit anyhow")
1581
1751
        except ConflictsInTree:
1582
1752
            raise BzrCommandError("Conflicts detected in working tree.  "
1583
1753
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1638
1808
    takes_args = ['url?']
1639
1809
    takes_options = [
1640
1810
                     Option('format', 
1641
 
                            help='Upgrade to a specific format rather than the'
1642
 
                                 ' current default format. Currently this'
1643
 
                                 ' option accepts "weave", "metadir" and'
1644
 
                                 ' "knit".',
 
1811
                            help='Upgrade to a specific format. Current formats'
 
1812
                                 ' are: default, knit, metaweave and weave.'
 
1813
                                 ' Default is knit; metaweave and weave are'
 
1814
                                 ' deprecated',
1645
1815
                            type=get_format_type),
1646
1816
                    ]
1647
1817
 
1648
1818
 
1649
1819
    def run(self, url='.', format=None):
1650
1820
        from bzrlib.upgrade import upgrade
 
1821
        if format is None:
 
1822
            format = get_format_type('default')
1651
1823
        upgrade(url, format)
1652
1824
 
1653
1825
 
1654
1826
class cmd_whoami(Command):
1655
 
    """Show bzr user id."""
1656
 
    takes_options = ['email']
 
1827
    """Show or set bzr user id.
 
1828
    
 
1829
    examples:
 
1830
        bzr whoami --email
 
1831
        bzr whoami 'Frank Chu <fchu@example.com>'
 
1832
    """
 
1833
    takes_options = [ Option('email',
 
1834
                             help='display email address only'),
 
1835
                      Option('branch',
 
1836
                             help='set identity for the current branch instead of '
 
1837
                                  'globally'),
 
1838
                    ]
 
1839
    takes_args = ['name?']
 
1840
    encoding_type = 'replace'
1657
1841
    
1658
1842
    @display_command
1659
 
    def run(self, email=False):
 
1843
    def run(self, email=False, branch=False, name=None):
 
1844
        if name is None:
 
1845
            # use branch if we're inside one; otherwise global config
 
1846
            try:
 
1847
                c = Branch.open_containing('.')[0].get_config()
 
1848
            except NotBranchError:
 
1849
                c = config.GlobalConfig()
 
1850
            if email:
 
1851
                self.outf.write(c.user_email() + '\n')
 
1852
            else:
 
1853
                self.outf.write(c.username() + '\n')
 
1854
            return
 
1855
 
 
1856
        # display a warning if an email address isn't included in the given name.
1660
1857
        try:
1661
 
            b = WorkingTree.open_containing(u'.')[0].branch
1662
 
            config = bzrlib.config.BranchConfig(b)
1663
 
        except NotBranchError:
1664
 
            config = bzrlib.config.GlobalConfig()
 
1858
            config.extract_email_address(name)
 
1859
        except BzrError, e:
 
1860
            warning('"%s" does not seem to contain an email address.  '
 
1861
                    'This is allowed, but not recommended.', name)
1665
1862
        
1666
 
        if email:
1667
 
            print config.user_email()
 
1863
        # use global config unless --branch given
 
1864
        if branch:
 
1865
            c = Branch.open_containing('.')[0].get_config()
1668
1866
        else:
1669
 
            print config.username()
 
1867
            c = config.GlobalConfig()
 
1868
        c.set_user_option('email', name)
1670
1869
 
1671
1870
 
1672
1871
class cmd_nick(Command):
1737
1936
                            help='Use a different transport by default '
1738
1937
                                 'throughout the test suite.',
1739
1938
                            type=get_transport_type),
1740
 
                    ]
 
1939
                     Option('benchmark', help='run the bzr bencharks.'),
 
1940
                     Option('lsprof-timed',
 
1941
                            help='generate lsprof output for benchmarked'
 
1942
                                 ' sections of code.'),
 
1943
                     ]
1741
1944
 
1742
 
    def run(self, testspecs_list=None, verbose=False, one=False,
1743
 
            keep_output=False, transport=None):
 
1945
    def run(self, testspecs_list=None, verbose=None, one=False,
 
1946
            keep_output=False, transport=None, benchmark=None,
 
1947
            lsprof_timed=None):
1744
1948
        import bzrlib.ui
1745
1949
        from bzrlib.tests import selftest
 
1950
        import bzrlib.benchmarks as benchmarks
1746
1951
        # we don't want progress meters from the tests to go to the
1747
1952
        # real output; and we don't want log messages cluttering up
1748
1953
        # the real logs.
1749
 
        save_ui = bzrlib.ui.ui_factory
1750
 
        bzrlib.trace.info('running tests...')
 
1954
        save_ui = ui.ui_factory
 
1955
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
 
1956
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
 
1957
        print
 
1958
        info('running tests...')
1751
1959
        try:
1752
 
            bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
 
1960
            ui.ui_factory = ui.SilentUIFactory()
1753
1961
            if testspecs_list is not None:
1754
1962
                pattern = '|'.join(testspecs_list)
1755
1963
            else:
1756
1964
                pattern = ".*"
 
1965
            if benchmark:
 
1966
                test_suite_factory = benchmarks.test_suite
 
1967
                if verbose is None:
 
1968
                    verbose = True
 
1969
            else:
 
1970
                test_suite_factory = None
 
1971
                if verbose is None:
 
1972
                    verbose = False
1757
1973
            result = selftest(verbose=verbose, 
1758
1974
                              pattern=pattern,
1759
1975
                              stop_on_failure=one, 
1760
1976
                              keep_output=keep_output,
1761
 
                              transport=transport)
 
1977
                              transport=transport,
 
1978
                              test_suite_factory=test_suite_factory,
 
1979
                              lsprof_timed=lsprof_timed)
1762
1980
            if result:
1763
 
                bzrlib.trace.info('tests passed')
 
1981
                info('tests passed')
1764
1982
            else:
1765
 
                bzrlib.trace.info('tests failed')
 
1983
                info('tests failed')
1766
1984
            return int(not result)
1767
1985
        finally:
1768
 
            bzrlib.ui.ui_factory = save_ui
 
1986
            ui.ui_factory = save_ui
1769
1987
 
1770
1988
 
1771
1989
def _get_bzr_branch():
1772
1990
    """If bzr is run from a branch, return Branch or None"""
1773
 
    import bzrlib.errors
1774
 
    from bzrlib.branch import Branch
1775
 
    from bzrlib.osutils import abspath
1776
1991
    from os.path import dirname
1777
1992
    
1778
1993
    try:
1779
 
        branch = Branch.open(dirname(abspath(dirname(__file__))))
 
1994
        branch = Branch.open(dirname(osutils.abspath(dirname(__file__))))
1780
1995
        return branch
1781
 
    except bzrlib.errors.BzrError:
 
1996
    except errors.BzrError:
1782
1997
        return None
1783
1998
    
1784
1999
 
1785
2000
def show_version():
1786
 
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
 
2001
    import bzrlib
 
2002
    print "Bazaar (bzr) %s" % bzrlib.__version__
1787
2003
    # is bzrlib itself in a branch?
1788
2004
    branch = _get_bzr_branch()
1789
2005
    if branch:
1793
2009
        print "  nick: %s" % (branch.nick,)
1794
2010
        if rh:
1795
2011
            print "  revid: %s" % (rh[-1],)
 
2012
    print "Using python interpreter:", sys.executable
 
2013
    import site
 
2014
    print "Using python standard library:", os.path.dirname(site.__file__)
 
2015
    print "Using bzrlib:",
 
2016
    if len(bzrlib.__path__) > 1:
 
2017
        # print repr, which is a good enough way of making it clear it's
 
2018
        # more than one element (eg ['/foo/bar', '/foo/bzr'])
 
2019
        print repr(bzrlib.__path__)
 
2020
    else:
 
2021
        print bzrlib.__path__[0]
 
2022
 
 
2023
    print
1796
2024
    print bzrlib.__copyright__
1797
 
    print "http://bazaar-ng.org/"
 
2025
    print "http://bazaar-vcs.org/"
1798
2026
    print
1799
2027
    print "bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and"
1800
2028
    print "you may use, modify and redistribute it under the terms of the GNU"
1803
2031
 
1804
2032
class cmd_version(Command):
1805
2033
    """Show version of bzr."""
 
2034
 
1806
2035
    @display_command
1807
2036
    def run(self):
1808
2037
        show_version()
1809
2038
 
 
2039
 
1810
2040
class cmd_rocks(Command):
1811
2041
    """Statement of optimism."""
 
2042
 
1812
2043
    hidden = True
 
2044
 
1813
2045
    @display_command
1814
2046
    def run(self):
1815
2047
        print "it sure does!"
1816
2048
 
1817
2049
 
1818
2050
class cmd_find_merge_base(Command):
1819
 
    """Find and print a base revision for merging two branches.
1820
 
    """
 
2051
    """Find and print a base revision for merging two branches."""
1821
2052
    # TODO: Options to specify revisions on either side, as if
1822
2053
    #       merging only part of the history.
1823
2054
    takes_args = ['branch', 'other']
1842
2073
        base_rev_id = common_ancestor(last1, last2, source)
1843
2074
 
1844
2075
        print 'merge base is revision %s' % base_rev_id
1845
 
        
1846
 
        return
1847
 
 
1848
 
        if base_revno is None:
1849
 
            raise bzrlib.errors.UnrelatedBranches()
1850
 
 
1851
 
        print ' r%-6d in %s' % (base_revno, branch)
1852
 
 
1853
 
        other_revno = branch2.revision_id_to_revno(base_revid)
1854
 
        
1855
 
        print ' r%-6d in %s' % (other_revno, other)
1856
 
 
1857
2076
 
1858
2077
 
1859
2078
class cmd_merge(Command):
1860
2079
    """Perform a three-way merge.
1861
2080
    
1862
 
    The branch is the branch you will merge from.  By default, it will
1863
 
    merge the latest revision.  If you specify a revision, that
1864
 
    revision will be merged.  If you specify two revisions, the first
1865
 
    will be used as a BASE, and the second one as OTHER.  Revision
1866
 
    numbers are always relative to the specified branch.
 
2081
    The branch is the branch you will merge from.  By default, it will merge
 
2082
    the latest revision.  If you specify a revision, that revision will be
 
2083
    merged.  If you specify two revisions, the first will be used as a BASE,
 
2084
    and the second one as OTHER.  Revision numbers are always relative to the
 
2085
    specified branch.
1867
2086
 
1868
2087
    By default, bzr will try to merge in all new work from the other
1869
2088
    branch, automatically determining an appropriate base.  If this
1878
2097
 
1879
2098
    If there is no default branch set, the first merge will set it. After
1880
2099
    that, you can omit the branch to use the default.  To change the
1881
 
    default, use --remember.
 
2100
    default, use --remember. The value will only be saved if the remote
 
2101
    location can be accessed.
1882
2102
 
1883
2103
    Examples:
1884
2104
 
1893
2113
    
1894
2114
    merge refuses to run if there are any uncommitted changes, unless
1895
2115
    --force is given.
 
2116
 
 
2117
    The following merge types are available:
1896
2118
    """
1897
2119
    takes_args = ['branch?']
1898
2120
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
1899
2121
                     Option('show-base', help="Show base revision text in "
1900
2122
                            "conflicts")]
1901
2123
 
 
2124
    def help(self):
 
2125
        from merge import merge_type_help
 
2126
        from inspect import getdoc
 
2127
        return getdoc(self) + '\n' + merge_type_help() 
 
2128
 
1902
2129
    def run(self, branch=None, revision=None, force=False, merge_type=None,
1903
2130
            show_base=False, reprocess=False, remember=False):
1904
2131
        if merge_type is None:
1905
2132
            merge_type = Merge3Merger
1906
2133
 
1907
2134
        tree = WorkingTree.open_containing(u'.')[0]
1908
 
        stored_loc = tree.branch.get_parent()
1909
 
        if branch is None:
1910
 
            if stored_loc is None:
1911
 
                raise BzrCommandError("No merge branch known or specified.")
 
2135
 
 
2136
        if branch is not None:
 
2137
            try:
 
2138
                reader = bundle.read_bundle_from_url(branch)
 
2139
            except NotABundle:
 
2140
                pass # Continue on considering this url a Branch
1912
2141
            else:
1913
 
                print "Using saved branch: %s" % stored_loc
1914
 
                branch = stored_loc
 
2142
                conflicts = merge_bundle(reader, tree, not force, merge_type,
 
2143
                                            reprocess, show_base)
 
2144
                if conflicts == 0:
 
2145
                    return 0
 
2146
                else:
 
2147
                    return 1
1915
2148
 
1916
 
        if tree.branch.get_parent() is None or remember:
1917
 
            tree.branch.set_parent(branch)
 
2149
        branch = self._get_remembered_parent(tree, branch, 'Merging from')
1918
2150
 
1919
2151
        if revision is None or len(revision) < 1:
1920
2152
            base = [None, None]
1931
2163
                if None in revision:
1932
2164
                    raise BzrCommandError(
1933
2165
                        "Merge doesn't permit that revision specifier.")
1934
 
                b, path = Branch.open_containing(branch)
1935
 
 
1936
 
                base = [branch, revision[0].in_history(b).revno]
1937
 
                other = [branch, revision[1].in_history(b).revno]
 
2166
                other_branch, path = Branch.open_containing(branch)
 
2167
 
 
2168
                base = [branch, revision[0].in_history(other_branch).revno]
 
2169
                other = [branch, revision[1].in_history(other_branch).revno]
 
2170
 
 
2171
        if tree.branch.get_parent() is None or remember:
 
2172
            tree.branch.set_parent(other_branch.base)
 
2173
 
1938
2174
        if path != "":
1939
2175
            interesting_files = [path]
1940
2176
        else:
1941
2177
            interesting_files = None
1942
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
2178
        pb = ui.ui_factory.nested_progress_bar()
1943
2179
        try:
1944
2180
            try:
1945
2181
                conflict_count = merge(other, base, check_clean=(not force),
1946
 
                                       merge_type=merge_type, 
 
2182
                                       merge_type=merge_type,
1947
2183
                                       reprocess=reprocess,
1948
 
                                       show_base=show_base, 
 
2184
                                       show_base=show_base,
1949
2185
                                       pb=pb, file_list=interesting_files)
1950
2186
            finally:
1951
2187
                pb.finished()
1953
2189
                return 1
1954
2190
            else:
1955
2191
                return 0
1956
 
        except bzrlib.errors.AmbiguousBase, e:
 
2192
        except errors.AmbiguousBase, e:
1957
2193
            m = ("sorry, bzr can't determine the right merge base yet\n"
1958
2194
                 "candidates are:\n  "
1959
2195
                 + "\n  ".join(e.bases)
1962
2198
                 "and (if you want) report this to the bzr developers\n")
1963
2199
            log_error(m)
1964
2200
 
 
2201
    # TODO: move up to common parent; this isn't merge-specific anymore. 
 
2202
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
 
2203
        """Use tree.branch's parent if none was supplied.
 
2204
 
 
2205
        Report if the remembered location was used.
 
2206
        """
 
2207
        if supplied_location is not None:
 
2208
            return supplied_location
 
2209
        stored_location = tree.branch.get_parent()
 
2210
        mutter("%s", stored_location)
 
2211
        if stored_location is None:
 
2212
            raise BzrCommandError("No location specified or remembered")
 
2213
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
 
2214
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
 
2215
        return stored_location
 
2216
 
1965
2217
 
1966
2218
class cmd_remerge(Command):
1967
2219
    """Redo a merge.
1968
 
    """
 
2220
 
 
2221
    Use this if you want to try a different merge technique while resolving
 
2222
    conflicts.  Some merge techniques are better than others, and remerge 
 
2223
    lets you try different ones on different files.
 
2224
 
 
2225
    The options for remerge have the same meaning and defaults as the ones for
 
2226
    merge.  The difference is that remerge can (only) be run when there is a
 
2227
    pending merge, and it lets you specify particular files.
 
2228
 
 
2229
    Examples:
 
2230
    $ bzr remerge --show-base
 
2231
        Re-do the merge of all conflicted files, and show the base text in
 
2232
        conflict regions, in addition to the usual THIS and OTHER texts.
 
2233
 
 
2234
    $ bzr remerge --merge-type weave --reprocess foobar
 
2235
        Re-do the merge of "foobar", using the weave merge algorithm, with
 
2236
        additional processing to reduce the size of conflict regions.
 
2237
    
 
2238
    The following merge types are available:"""
1969
2239
    takes_args = ['file*']
1970
2240
    takes_options = ['merge-type', 'reprocess',
1971
2241
                     Option('show-base', help="Show base revision text in "
1972
2242
                            "conflicts")]
1973
2243
 
 
2244
    def help(self):
 
2245
        from merge import merge_type_help
 
2246
        from inspect import getdoc
 
2247
        return getdoc(self) + '\n' + merge_type_help() 
 
2248
 
1974
2249
    def run(self, file_list=None, merge_type=None, show_base=False,
1975
2250
            reprocess=False):
1976
2251
        from bzrlib.merge import merge_inner, transform_tree
1982
2257
            pending_merges = tree.pending_merges() 
1983
2258
            if len(pending_merges) != 1:
1984
2259
                raise BzrCommandError("Sorry, remerge only works after normal"
1985
 
                                      + " merges.  Not cherrypicking or"
1986
 
                                      + "multi-merges.")
 
2260
                                      " merges.  Not cherrypicking or"
 
2261
                                      " multi-merges.")
1987
2262
            repository = tree.branch.repository
1988
2263
            base_revision = common_ancestor(tree.branch.last_revision(), 
1989
2264
                                            pending_merges[0], repository)
1990
2265
            base_tree = repository.revision_tree(base_revision)
1991
2266
            other_tree = repository.revision_tree(pending_merges[0])
1992
2267
            interesting_ids = None
 
2268
            new_conflicts = []
 
2269
            conflicts = tree.conflicts()
1993
2270
            if file_list is not None:
1994
2271
                interesting_ids = set()
1995
2272
                for filename in file_list:
2002
2279
                    
2003
2280
                    for name, ie in tree.inventory.iter_entries(file_id):
2004
2281
                        interesting_ids.add(ie.file_id)
 
2282
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2005
2283
            transform_tree(tree, tree.basis_tree(), interesting_ids)
 
2284
            tree.set_conflicts(ConflictList(new_conflicts))
2006
2285
            if file_list is None:
2007
2286
                restore_files = list(tree.iter_conflicts())
2008
2287
            else:
2012
2291
                    restore(tree.abspath(filename))
2013
2292
                except NotConflicted:
2014
2293
                    pass
2015
 
            conflicts =  merge_inner(tree.branch, other_tree, base_tree,
2016
 
                                     this_tree=tree,
2017
 
                                     interesting_ids = interesting_ids, 
2018
 
                                     other_rev_id=pending_merges[0], 
2019
 
                                     merge_type=merge_type, 
2020
 
                                     show_base=show_base,
2021
 
                                     reprocess=reprocess)
 
2294
            conflicts = merge_inner(tree.branch, other_tree, base_tree,
 
2295
                                    this_tree=tree,
 
2296
                                    interesting_ids=interesting_ids, 
 
2297
                                    other_rev_id=pending_merges[0], 
 
2298
                                    merge_type=merge_type, 
 
2299
                                    show_base=show_base,
 
2300
                                    reprocess=reprocess)
2022
2301
        finally:
2023
2302
            tree.unlock()
2024
2303
        if conflicts > 0:
2053
2332
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2054
2333
        else:
2055
2334
            rev_id = revision[0].in_history(tree.branch).rev_id
2056
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
2335
        pb = ui.ui_factory.nested_progress_bar()
2057
2336
        try:
2058
2337
            tree.revert(file_list, 
2059
2338
                        tree.branch.repository.revision_tree(rev_id),
2107
2386
    takes_args = ['from_branch', 'to_branch']
2108
2387
    def run(self, from_branch, to_branch):
2109
2388
        from bzrlib.fetch import Fetcher
2110
 
        from bzrlib.branch import Branch
2111
2389
        from_b = Branch.open(from_branch)
2112
2390
        to_b = Branch.open(to_branch)
2113
2391
        Fetcher(to_b, from_b)
2130
2408
                     'show-ids',
2131
2409
                     'verbose'
2132
2410
                     ]
 
2411
    encoding_type = 'replace'
2133
2412
 
 
2413
    @display_command
2134
2414
    def run(self, other_branch=None, reverse=False, mine_only=False,
2135
2415
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
2136
2416
            show_ids=False, verbose=False):
2137
2417
        from bzrlib.missing import find_unmerged, iter_log_data
2138
2418
        from bzrlib.log import log_formatter
2139
 
        local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
 
2419
        local_branch = Branch.open_containing(u".")[0]
2140
2420
        parent = local_branch.get_parent()
2141
2421
        if other_branch is None:
2142
2422
            other_branch = parent
2143
2423
            if other_branch is None:
2144
 
                raise BzrCommandError("No missing location known or specified.")
 
2424
                raise BzrCommandError("No peer location known or specified.")
2145
2425
            print "Using last location: " + local_branch.get_parent()
2146
 
        remote_branch = bzrlib.branch.Branch.open(other_branch)
 
2426
        remote_branch = Branch.open(other_branch)
2147
2427
        if remote_branch.base == local_branch.base:
2148
2428
            remote_branch = local_branch
2149
2429
        local_branch.lock_read()
2152
2432
            try:
2153
2433
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2154
2434
                if (log_format == None):
2155
 
                    default = bzrlib.config.BranchConfig(local_branch).log_format()
2156
 
                    log_format = get_log_format(long=long, short=short, line=line, default=default)
2157
 
                lf = log_formatter(log_format, sys.stdout,
 
2435
                    default = local_branch.get_config().log_format()
 
2436
                    log_format = get_log_format(long=long, short=short, 
 
2437
                                                line=line, default=default)
 
2438
                lf = log_formatter(log_format,
 
2439
                                   to_file=self.outf,
2158
2440
                                   show_ids=show_ids,
2159
2441
                                   show_timezone='original')
2160
2442
                if reverse is False:
2189
2471
            try:
2190
2472
                # handle race conditions - a parent might be set while we run.
2191
2473
                if local_branch.get_parent() is None:
2192
 
                    local_branch.set_parent(other_branch)
 
2474
                    local_branch.set_parent(remote_branch.base)
2193
2475
            finally:
2194
2476
                local_branch.unlock()
2195
2477
        return status_code
2217
2499
 
2218
2500
class cmd_testament(Command):
2219
2501
    """Show testament (signing-form) of a revision."""
2220
 
    takes_options = ['revision', 'long']
 
2502
    takes_options = ['revision', 'long', 
 
2503
                     Option('strict', help='Produce a strict-format'
 
2504
                            ' testament')]
2221
2505
    takes_args = ['branch?']
2222
2506
    @display_command
2223
 
    def run(self, branch=u'.', revision=None, long=False):
2224
 
        from bzrlib.testament import Testament
 
2507
    def run(self, branch=u'.', revision=None, long=False, strict=False):
 
2508
        from bzrlib.testament import Testament, StrictTestament
 
2509
        if strict is True:
 
2510
            testament_class = StrictTestament
 
2511
        else:
 
2512
            testament_class = Testament
2225
2513
        b = WorkingTree.open_containing(branch)[0].branch
2226
2514
        b.lock_read()
2227
2515
        try:
2229
2517
                rev_id = b.last_revision()
2230
2518
            else:
2231
2519
                rev_id = revision[0].in_history(b).rev_id
2232
 
            t = Testament.from_revision(b.repository, rev_id)
 
2520
            t = testament_class.from_revision(b.repository, rev_id)
2233
2521
            if long:
2234
2522
                sys.stdout.writelines(t.as_text_lines())
2235
2523
            else:
2248
2536
    shown only at the top, unless the --all option is given.
2249
2537
    """
2250
2538
    # TODO: annotate directories; showing when each file was last changed
2251
 
    # TODO: annotate a previous version of a file
2252
2539
    # TODO: if the working copy is modified, show annotations on that 
2253
2540
    #       with new uncommitted lines marked
2254
 
    aliases = ['blame', 'praise']
 
2541
    aliases = ['ann', 'blame', 'praise']
2255
2542
    takes_args = ['filename']
2256
2543
    takes_options = [Option('all', help='show annotations on all lines'),
2257
2544
                     Option('long', help='show date in annotations'),
 
2545
                     'revision'
2258
2546
                     ]
2259
2547
 
2260
2548
    @display_command
2261
 
    def run(self, filename, all=False, long=False):
 
2549
    def run(self, filename, all=False, long=False, revision=None):
2262
2550
        from bzrlib.annotate import annotate_file
2263
2551
        tree, relpath = WorkingTree.open_containing(filename)
2264
2552
        branch = tree.branch
2265
2553
        branch.lock_read()
2266
2554
        try:
 
2555
            if revision is None:
 
2556
                revision_id = branch.last_revision()
 
2557
            elif len(revision) != 1:
 
2558
                raise BzrCommandError('bzr annotate --revision takes exactly 1 argument')
 
2559
            else:
 
2560
                revision_id = revision[0].in_history(branch).rev_id
2267
2561
            file_id = tree.inventory.path2id(relpath)
2268
 
            tree = branch.repository.revision_tree(branch.last_revision())
 
2562
            tree = branch.repository.revision_tree(revision_id)
2269
2563
            file_version = tree.inventory[file_id].revision
2270
2564
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
2271
2565
        finally:
2281
2575
    takes_options = ['revision']
2282
2576
    
2283
2577
    def run(self, revision_id_list=None, revision=None):
2284
 
        import bzrlib.config as config
2285
2578
        import bzrlib.gpg as gpg
2286
2579
        if revision_id_list is not None and revision is not None:
2287
2580
            raise BzrCommandError('You can only supply one of revision_id or --revision')
2288
2581
        if revision_id_list is None and revision is None:
2289
2582
            raise BzrCommandError('You must supply either --revision or a revision_id')
2290
2583
        b = WorkingTree.open_containing(u'.')[0].branch
2291
 
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
 
2584
        gpg_strategy = gpg.GPGStrategy(b.get_config())
2292
2585
        if revision_id_list is not None:
2293
2586
            for revision_id in revision_id_list:
2294
2587
                b.repository.sign_revision(revision_id, gpg_strategy)
2334
2627
 
2335
2628
 
2336
2629
class cmd_unbind(Command):
2337
 
    """Bind the current branch to its parent.
 
2630
    """Unbind the current branch from its master branch.
2338
2631
 
2339
2632
    After unbinding, the local branch is considered independent.
 
2633
    All subsequent commits will be local.
2340
2634
    """
2341
2635
 
2342
2636
    takes_args = []
2348
2642
            raise BzrCommandError('Local branch is not bound')
2349
2643
 
2350
2644
 
2351
 
class cmd_uncommit(bzrlib.commands.Command):
 
2645
class cmd_uncommit(Command):
2352
2646
    """Remove the last committed revision.
2353
2647
 
2354
 
    By supplying the --all flag, it will not only remove the entry 
2355
 
    from revision_history, but also remove all of the entries in the
2356
 
    stores.
2357
 
 
2358
2648
    --verbose will print out what is being removed.
2359
2649
    --dry-run will go through all the motions, but not actually
2360
2650
    remove anything.
2361
2651
    
2362
 
    In the future, uncommit will create a changeset, which can then
 
2652
    In the future, uncommit will create a revision bundle, which can then
2363
2653
    be re-applied.
2364
2654
    """
2365
2655
 
2366
2656
    # TODO: jam 20060108 Add an option to allow uncommit to remove
2367
 
    # unreferenced information in 'branch-as-repostory' branches.
 
2657
    # unreferenced information in 'branch-as-repository' branches.
2368
2658
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2369
2659
    # information in shared branches as well.
2370
2660
    takes_options = ['verbose', 'revision',
2373
2663
    takes_args = ['location?']
2374
2664
    aliases = []
2375
2665
 
2376
 
    def run(self, location=None, 
 
2666
    def run(self, location=None,
2377
2667
            dry_run=False, verbose=False,
2378
2668
            revision=None, force=False):
2379
 
        from bzrlib.branch import Branch
2380
 
        from bzrlib.log import log_formatter
 
2669
        from bzrlib.log import log_formatter, show_log
2381
2670
        import sys
2382
2671
        from bzrlib.uncommit import uncommit
2383
2672
 
2391
2680
            tree = None
2392
2681
            b = control.open_branch()
2393
2682
 
 
2683
        rev_id = None
2394
2684
        if revision is None:
2395
2685
            revno = b.revno()
2396
 
            rev_id = b.last_revision()
2397
2686
        else:
2398
 
            revno, rev_id = revision[0].in_history(b)
 
2687
            # 'bzr uncommit -r 10' actually means uncommit
 
2688
            # so that the final tree is at revno 10.
 
2689
            # but bzrlib.uncommit.uncommit() actually uncommits
 
2690
            # the revisions that are supplied.
 
2691
            # So we need to offset it by one
 
2692
            revno = revision[0].in_history(b).revno+1
 
2693
 
 
2694
        if revno <= b.revno():
 
2695
            rev_id = b.get_rev_id(revno)
2399
2696
        if rev_id is None:
2400
 
            print 'No revisions to uncommit.'
2401
 
 
2402
 
        for r in range(revno, b.revno()+1):
2403
 
            rev_id = b.get_rev_id(r)
2404
 
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2405
 
            lf.show(r, b.repository.get_revision(rev_id), None)
 
2697
            self.outf.write('No revisions to uncommit.\n')
 
2698
            return 1
 
2699
 
 
2700
        lf = log_formatter('short',
 
2701
                           to_file=self.outf,
 
2702
                           show_timezone='original')
 
2703
 
 
2704
        show_log(b,
 
2705
                 lf,
 
2706
                 verbose=False,
 
2707
                 direction='forward',
 
2708
                 start_revision=revno,
 
2709
                 end_revision=b.revno())
2406
2710
 
2407
2711
        if dry_run:
2408
2712
            print 'Dry-run, pretending to remove the above revisions.'
2425
2729
 
2426
2730
    CAUTION: Locks should only be broken when you are sure that the process
2427
2731
    holding the lock has been stopped.
 
2732
 
 
2733
    You can get information on what locks are open via the 'bzr info' command.
2428
2734
    
2429
2735
    example:
2430
 
        bzr break-lock .
 
2736
        bzr break-lock
2431
2737
    """
2432
 
    takes_args = ['location']
2433
 
    takes_options = [Option('show',
2434
 
                            help="just show information on the lock, " \
2435
 
                                 "don't break it"),
2436
 
                    ]
2437
 
    def run(self, location, show=False):
2438
 
        raise NotImplementedError("sorry, break-lock is not complete yet; "
2439
 
                "you can remove the 'held' directory manually to break the lock")
 
2738
    takes_args = ['location?']
 
2739
 
 
2740
    def run(self, location=None, show=False):
 
2741
        if location is None:
 
2742
            location = u'.'
 
2743
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
2744
        try:
 
2745
            control.break_lock()
 
2746
        except NotImplementedError:
 
2747
            pass
 
2748
        
2440
2749
 
2441
2750
 
2442
2751
# command-line interpretation helper for merge-related commands
2514
2823
# aliases.  ideally we would avoid loading the implementation until the
2515
2824
# details were needed.
2516
2825
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
 
2826
from bzrlib.bundle.commands import cmd_bundle_revisions
2517
2827
from bzrlib.sign_my_commits import cmd_sign_my_commits
2518
2828
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2519
2829
        cmd_weave_plan_merge, cmd_weave_merge_text