~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Martin Pool
  • Date: 2006-01-23 02:09:39 UTC
  • mfrom: (1534.1.11 integration)
  • Revision ID: mbp@sourcefrog.net-20060123020939-567fb193328ed7a6
[merge] robert's integration

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
 
17
"""builtin bzr commands"""
 
18
 
17
19
# DO NOT change this to cStringIO - it results in control files 
18
20
# written as UCS4
19
21
# FIXIT! (Only deal with byte streams OR unicode at any one layer.)
20
22
# RBC 20051018
 
23
 
21
24
from StringIO import StringIO
22
25
import sys
23
26
import os
27
30
from bzrlib.commands import Command, display_command
28
31
from bzrlib.branch import Branch
29
32
from bzrlib.revision import common_ancestor
 
33
import bzrlib.errors as errors
30
34
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
31
35
                           NotBranchError, DivergedBranches, NotConflicted,
32
 
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
 
36
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
33
37
from bzrlib.option import Option
34
38
from bzrlib.revisionspec import RevisionSpec
35
39
import bzrlib.trace
36
 
from bzrlib.trace import mutter, note, log_error, warning
 
40
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
37
41
from bzrlib.workingtree import WorkingTree
38
 
 
39
 
 
40
 
def branch_files(file_list, default_branch='.'):
 
42
from bzrlib.log import show_one_log
 
43
 
 
44
 
 
45
def tree_files(file_list, default_branch=u'.'):
41
46
    try:
42
 
        return inner_branch_files(file_list, default_branch)
 
47
        return internal_tree_files(file_list, default_branch)
43
48
    except FileInWrongBranch, e:
44
49
        raise BzrCommandError("%s is not in the same branch as %s" %
45
50
                             (e.path, file_list[0]))
46
51
 
47
 
def inner_branch_files(file_list, default_branch='.'):
 
52
def internal_tree_files(file_list, default_branch=u'.'):
48
53
    """\
49
54
    Return a branch and list of branch-relative paths.
50
55
    If supplied file_list is empty or None, the branch default will be used,
51
56
    and returned file_list will match the original.
52
57
    """
53
58
    if file_list is None or len(file_list) == 0:
54
 
        return Branch.open_containing(default_branch)[0], file_list
55
 
    b = Branch.open_containing(file_list[0])[0]
56
 
    
57
 
    # note that if this is a remote branch, we would want
58
 
    # relpath against the transport. RBC 20051018
59
 
    # Most branch ops can't meaningfully operate on files in remote branches;
60
 
    # the above comment was in cmd_status.  ADHB 20051026
61
 
    tree = WorkingTree(b.base, b)
 
59
        return WorkingTree.open_containing(default_branch)[0], file_list
 
60
    tree = WorkingTree.open_containing(file_list[0])[0]
62
61
    new_list = []
63
62
    for filename in file_list:
64
63
        try:
65
64
            new_list.append(tree.relpath(filename))
66
 
        except NotBranchError:
67
 
            raise FileInWrongBranch(b, filename)
68
 
    return b, new_list
 
65
        except errors.PathNotChild:
 
66
            raise FileInWrongBranch(tree.branch, filename)
 
67
    return tree, new_list
69
68
 
70
69
 
71
70
# TODO: Make sure no commands unconditionally use the working directory as a
122
121
    
123
122
    @display_command
124
123
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
125
 
        b, file_list = branch_files(file_list)
 
124
        tree, file_list = tree_files(file_list)
126
125
            
127
126
        from bzrlib.status import show_status
128
 
        show_status(b, show_unchanged=all, show_ids=show_ids,
 
127
        show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
129
128
                    specific_files=file_list, revision=revision)
130
129
 
131
130
 
147
146
            raise BzrCommandError('You can only supply one of revision_id or --revision')
148
147
        if revision_id is None and revision is None:
149
148
            raise BzrCommandError('You must supply either --revision or a revision_id')
150
 
        b = Branch.open_containing('.')[0]
 
149
        b = WorkingTree.open_containing(u'.')[0].branch
151
150
        if revision_id is not None:
152
 
            sys.stdout.write(b.get_revision_xml_file(revision_id).read())
 
151
            sys.stdout.write(b.get_revision_xml(revision_id))
153
152
        elif revision is not None:
154
153
            for rev in revision:
155
154
                if rev is None:
156
155
                    raise BzrCommandError('You cannot specify a NULL revision.')
157
156
                revno, rev_id = rev.in_history(b)
158
 
                sys.stdout.write(b.get_revision_xml_file(rev_id).read())
 
157
                sys.stdout.write(b.get_revision_xml(rev_id))
159
158
    
160
159
 
161
160
class cmd_revno(Command):
162
161
    """Show current revision number.
163
162
 
164
163
    This is equal to the number of revisions on this branch."""
 
164
    takes_args = ['location?']
165
165
    @display_command
166
 
    def run(self):
167
 
        print Branch.open_containing('.')[0].revno()
 
166
    def run(self, location=u'.'):
 
167
        print Branch.open_containing(location)[0].revno()
168
168
 
169
169
 
170
170
class cmd_revision_info(Command):
185
185
        if len(revs) == 0:
186
186
            raise BzrCommandError('You must supply a revision identifier')
187
187
 
188
 
        b = Branch.open_containing('.')[0]
 
188
        b = WorkingTree.open_containing(u'.')[0].branch
189
189
 
190
190
        for rev in revs:
191
191
            revinfo = rev.in_history(b)
217
217
    implicitly add the parent, and so on up to the root. This means
218
218
    you should never need to explictly add a directory, they'll just
219
219
    get added when you add a file in the directory.
 
220
 
 
221
    --dry-run will show which files would be added, but not actually 
 
222
    add them.
220
223
    """
221
224
    takes_args = ['file*']
222
 
    takes_options = ['no-recurse', 'quiet']
223
 
    
224
 
    def run(self, file_list, no_recurse=False, quiet=False):
225
 
        from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
226
 
        if quiet:
227
 
            reporter = add_reporter_null
 
225
    takes_options = ['no-recurse', 'dry-run', 'verbose']
 
226
 
 
227
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
 
228
        import bzrlib.add
 
229
 
 
230
        if dry_run:
 
231
            if is_quiet():
 
232
                # This is pointless, but I'd rather not raise an error
 
233
                action = bzrlib.add.add_action_null
 
234
            else:
 
235
                action = bzrlib.add.add_action_print
 
236
        elif is_quiet():
 
237
            action = bzrlib.add.add_action_add
228
238
        else:
229
 
            reporter = add_reporter_print
230
 
        smart_add(file_list, not no_recurse, reporter)
 
239
            action = bzrlib.add.add_action_add_and_print
 
240
 
 
241
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
 
242
                                              action)
 
243
        if len(ignored) > 0:
 
244
            for glob in sorted(ignored.keys()):
 
245
                match_len = len(ignored[glob])
 
246
                if verbose:
 
247
                    for path in ignored[glob]:
 
248
                        print "ignored %s matching \"%s\"" % (path, glob)
 
249
                else:
 
250
                    print "ignored %d file(s) matching \"%s\"" % (match_len,
 
251
                                                              glob)
 
252
            print "If you wish to add some of these files, please add them"\
 
253
                " by name."
231
254
 
232
255
 
233
256
class cmd_mkdir(Command):
238
261
    takes_args = ['dir+']
239
262
 
240
263
    def run(self, dir_list):
241
 
        b = None
242
 
        
243
264
        for d in dir_list:
244
265
            os.mkdir(d)
245
 
            b, dd = Branch.open_containing(d)
246
 
            b.add([dd])
 
266
            wt, dd = WorkingTree.open_containing(d)
 
267
            wt.add([dd])
247
268
            print 'added', d
248
269
 
249
270
 
254
275
    
255
276
    @display_command
256
277
    def run(self, filename):
257
 
        branch, relpath = Branch.open_containing(filename)
 
278
        tree, relpath = WorkingTree.open_containing(filename)
258
279
        print relpath
259
280
 
260
281
 
270
291
    def run(self, revision=None, show_ids=False, kind=None):
271
292
        if kind and kind not in ['file', 'directory', 'symlink']:
272
293
            raise BzrCommandError('invalid kind specified')
273
 
        b = Branch.open_containing('.')[0]
 
294
        tree = WorkingTree.open_containing(u'.')[0]
274
295
        if revision is None:
275
 
            inv = b.working_tree().read_working_inventory()
 
296
            inv = tree.read_working_inventory()
276
297
        else:
277
298
            if len(revision) > 1:
278
299
                raise BzrCommandError('bzr inventory --revision takes'
279
300
                    ' exactly one revision identifier')
280
 
            inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
 
301
            inv = tree.branch.get_revision_inventory(
 
302
                revision[0].in_history(tree.branch).rev_id)
281
303
 
282
304
        for path, entry in inv.entries():
283
305
            if kind and kind != entry.kind:
298
320
    """
299
321
    takes_args = ['source$', 'dest']
300
322
    def run(self, source_list, dest):
301
 
        b, source_list = branch_files(source_list)
302
 
 
 
323
        tree, source_list = tree_files(source_list)
303
324
        # TODO: glob expansion on windows?
304
 
        tree = WorkingTree(b.base, b)
305
 
        b.move(source_list, tree.relpath(dest))
 
325
        tree.move(source_list, tree.relpath(dest))
306
326
 
307
327
 
308
328
class cmd_rename(Command):
322
342
    takes_args = ['from_name', 'to_name']
323
343
    
324
344
    def run(self, from_name, to_name):
325
 
        b, (from_name, to_name) = branch_files((from_name, to_name))
326
 
        b.rename_one(from_name, to_name)
 
345
        tree, (from_name, to_name) = tree_files((from_name, to_name))
 
346
        tree.rename_one(from_name, to_name)
327
347
 
328
348
 
329
349
class cmd_mv(Command):
343
363
    def run(self, names_list):
344
364
        if len(names_list) < 2:
345
365
            raise BzrCommandError("missing file argument")
346
 
        b, rel_names = branch_files(names_list)
 
366
        tree, rel_names = tree_files(names_list)
347
367
        
348
368
        if os.path.isdir(names_list[-1]):
349
369
            # move into existing directory
350
 
            for pair in b.move(rel_names[:-1], rel_names[-1]):
 
370
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
351
371
                print "%s => %s" % pair
352
372
        else:
353
373
            if len(names_list) != 2:
354
374
                raise BzrCommandError('to mv multiple files the destination '
355
375
                                      'must be a versioned directory')
356
 
            b.rename_one(rel_names[0], rel_names[1])
 
376
            tree.rename_one(rel_names[0], rel_names[1])
357
377
            print "%s => %s" % (rel_names[0], rel_names[1])
358
378
            
359
379
    
382
402
        from bzrlib.merge import merge
383
403
        from shutil import rmtree
384
404
        import errno
385
 
        
386
 
        br_to = Branch.open_containing('.')[0]
387
 
        stored_loc = br_to.get_parent()
 
405
        # FIXME: too much stuff is in the command class        
 
406
        tree_to = WorkingTree.open_containing(u'.')[0]
 
407
        stored_loc = tree_to.branch.get_parent()
388
408
        if location is None:
389
409
            if stored_loc is None:
390
410
                raise BzrCommandError("No pull location known or specified.")
391
411
            else:
392
412
                print "Using saved location: %s" % stored_loc
393
413
                location = stored_loc
 
414
 
394
415
        br_from = Branch.open(location)
395
 
        try:
396
 
            old_rh = br_to.revision_history()
397
 
            br_to.working_tree().pull(br_from, overwrite)
398
 
        except DivergedBranches:
399
 
            raise BzrCommandError("These branches have diverged."
400
 
                                  "  Try merge.")
 
416
        br_to = tree_to.branch
 
417
 
 
418
        old_rh = br_to.revision_history()
 
419
        count = tree_to.pull(br_from, overwrite)
 
420
 
401
421
        if br_to.get_parent() is None or remember:
402
422
            br_to.set_parent(location)
 
423
        note('%d revision(s) pulled.' % (count,))
403
424
 
404
425
        if verbose:
405
 
            new_rh = br_to.revision_history()
 
426
            new_rh = tree_to.branch.revision_history()
406
427
            if old_rh != new_rh:
407
428
                # Something changed
408
429
                from bzrlib.log import show_changed_revisions
409
 
                show_changed_revisions(br_to, old_rh, new_rh)
 
430
                show_changed_revisions(tree_to.branch, old_rh, new_rh)
410
431
 
411
432
 
412
433
class cmd_push(Command):
440
461
 
441
462
    def run(self, location=None, remember=False, overwrite=False,
442
463
            create_prefix=False, verbose=False):
 
464
        # FIXME: Way too big!  Put this into a function called from the
 
465
        # command.
443
466
        import errno
444
467
        from shutil import rmtree
445
468
        from bzrlib.transport import get_transport
446
469
        
447
 
        br_from = Branch.open_containing('.')[0]
448
 
        stored_loc = br_from.get_push_location()
 
470
        tree_from = WorkingTree.open_containing(u'.')[0]
 
471
        br_from = tree_from.branch
 
472
        stored_loc = tree_from.branch.get_push_location()
449
473
        if location is None:
450
474
            if stored_loc is None:
451
475
                raise BzrCommandError("No push location known or specified.")
478
502
                        if new_transport.base == transport.base:
479
503
                            raise BzrCommandError("Could not creeate "
480
504
                                                  "path prefix.")
481
 
                        
482
 
            NoSuchFile
483
505
            br_to = Branch.initialize(location)
 
506
        old_rh = br_to.revision_history()
484
507
        try:
485
 
            old_rh = br_to.revision_history()
486
 
            br_to.pull(br_from, overwrite)
 
508
            try:
 
509
                tree_to = br_to.working_tree()
 
510
            except NoWorkingTree:
 
511
                # TODO: This should be updated for branches which don't have a
 
512
                # working tree, as opposed to ones where we just couldn't 
 
513
                # update the tree.
 
514
                warning('Unable to update the working tree of: %s' % (br_to.base,))
 
515
                count = br_to.pull(br_from, overwrite)
 
516
            else:
 
517
                count = tree_to.pull(br_from, overwrite)
487
518
        except DivergedBranches:
488
519
            raise BzrCommandError("These branches have diverged."
489
520
                                  "  Try a merge then push with overwrite.")
490
521
        if br_from.get_push_location() is None or remember:
491
522
            br_from.set_push_location(location)
 
523
        note('%d revision(s) pushed.' % (count,))
492
524
 
493
525
        if verbose:
494
526
            new_rh = br_to.revision_history()
497
529
                from bzrlib.log import show_changed_revisions
498
530
                show_changed_revisions(br_to, old_rh, new_rh)
499
531
 
 
532
 
500
533
class cmd_branch(Command):
501
534
    """Create a new copy of a branch.
502
535
 
534
567
        br_from.lock_read()
535
568
        try:
536
569
            if basis is not None:
537
 
                basis_branch = Branch.open_containing(basis)[0]
 
570
                basis_branch = WorkingTree.open_containing(basis)[0].branch
538
571
            else:
539
572
                basis_branch = None
540
573
            if len(revision) == 1 and revision[0] is not None:
567
600
                rmtree(to_location)
568
601
                msg = "The branch %s cannot be used as a --basis"
569
602
                raise BzrCommandError(msg)
 
603
            branch = Branch.open(to_location)
570
604
            if name:
571
 
                branch = Branch.open(to_location)
572
605
                name = StringIO(name)
573
606
                branch.put_controlfile('branch-name', name)
 
607
            note('Branched %d revision(s).' % branch.revno())
574
608
        finally:
575
609
            br_from.unlock()
576
610
 
584
618
    takes_args = ['dir?']
585
619
 
586
620
    @display_command
587
 
    def run(self, dir='.'):
588
 
        b = Branch.open_containing(dir)[0]
589
 
        old_inv = b.basis_tree().inventory
590
 
        new_inv = b.working_tree().read_working_inventory()
 
621
    def run(self, dir=u'.'):
 
622
        tree = WorkingTree.open_containing(dir)[0]
 
623
        old_inv = tree.branch.basis_tree().inventory
 
624
        new_inv = tree.read_working_inventory()
591
625
 
592
626
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
593
627
        renames.sort()
602
636
    @display_command
603
637
    def run(self, branch=None):
604
638
        import info
605
 
        b = Branch.open_containing(branch)[0]
 
639
        b = WorkingTree.open_containing(branch)[0].branch
606
640
        info.show_info(b)
607
641
 
608
642
 
617
651
    aliases = ['rm']
618
652
    
619
653
    def run(self, file_list, verbose=False):
620
 
        b, file_list = branch_files(file_list)
621
 
        tree = b.working_tree()
 
654
        tree, file_list = tree_files(file_list)
622
655
        tree.remove(file_list, verbose=verbose)
623
656
 
624
657
 
633
666
    takes_args = ['filename']
634
667
    @display_command
635
668
    def run(self, filename):
636
 
        b, relpath = Branch.open_containing(filename)
637
 
        i = b.working_tree().inventory.path2id(relpath)
 
669
        tree, relpath = WorkingTree.open_containing(filename)
 
670
        i = tree.inventory.path2id(relpath)
638
671
        if i == None:
639
672
            raise BzrError("%r is not a versioned file" % filename)
640
673
        else:
650
683
    takes_args = ['filename']
651
684
    @display_command
652
685
    def run(self, filename):
653
 
        b, relpath = Branch.open_containing(filename)
654
 
        inv = b.inventory
 
686
        tree, relpath = WorkingTree.open_containing(filename)
 
687
        inv = tree.inventory
655
688
        fid = inv.path2id(relpath)
656
689
        if fid == None:
657
690
            raise BzrError("%r is not a versioned file" % filename)
664
697
    hidden = True
665
698
    @display_command
666
699
    def run(self):
667
 
        for patchid in Branch.open_containing('.')[0].revision_history():
 
700
        branch = WorkingTree.open_containing(u'.')[0].branch
 
701
        for patchid in branch.revision_history():
668
702
            print patchid
669
703
 
670
704
 
673
707
    hidden = True
674
708
    @display_command
675
709
    def run(self):
676
 
        b = Branch.open_containing('.')[0]
 
710
        tree = WorkingTree.open_containing(u'.')[0]
 
711
        b = tree.branch
 
712
        # FIXME. should be tree.last_revision
677
713
        for revision_id in b.get_ancestry(b.last_revision()):
678
714
            print revision_id
679
715
 
695
731
    def run(self, location=None):
696
732
        from bzrlib.branch import Branch
697
733
        if location is None:
698
 
            location = '.'
 
734
            location = u'.'
699
735
        else:
700
736
            # The path has to exist to initialize a
701
737
            # branch inside of it.
740
776
    def run(self, revision=None, file_list=None, diff_options=None):
741
777
        from bzrlib.diff import show_diff
742
778
        try:
743
 
            b, file_list = inner_branch_files(file_list)
 
779
            tree, file_list = internal_tree_files(file_list)
 
780
            b = None
744
781
            b2 = None
745
782
        except FileInWrongBranch:
746
783
            if len(file_list) != 2:
749
786
            b, file1 = Branch.open_containing(file_list[0])
750
787
            b2, file2 = Branch.open_containing(file_list[1])
751
788
            if file1 != "" or file2 != "":
 
789
                # FIXME diff those two files. rbc 20051123
752
790
                raise BzrCommandError("Files are in different branches")
753
791
            file_list = None
754
792
        if revision is not None:
755
793
            if b2 is not None:
756
794
                raise BzrCommandError("Can't specify -r with two branches")
757
 
            if len(revision) == 1:
758
 
                return show_diff(b, revision[0], specific_files=file_list,
 
795
            if (len(revision) == 1) or (revision[1].spec is None):
 
796
                return show_diff(tree.branch, revision[0], specific_files=file_list,
759
797
                                 external_diff_options=diff_options)
760
798
            elif len(revision) == 2:
761
 
                return show_diff(b, revision[0], specific_files=file_list,
 
799
                return show_diff(tree.branch, revision[0], specific_files=file_list,
762
800
                                 external_diff_options=diff_options,
763
801
                                 revision2=revision[1])
764
802
            else:
765
803
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
766
804
        else:
767
 
            return show_diff(b, None, specific_files=file_list,
768
 
                             external_diff_options=diff_options, b2=b2)
 
805
            if b is not None:
 
806
                return show_diff(b, None, specific_files=file_list,
 
807
                                 external_diff_options=diff_options, b2=b2)
 
808
            else:
 
809
                return show_diff(tree.branch, None, specific_files=file_list,
 
810
                                 external_diff_options=diff_options)
769
811
 
770
812
 
771
813
class cmd_deleted(Command):
779
821
    # if the directories are very large...)
780
822
    @display_command
781
823
    def run(self, show_ids=False):
782
 
        b = Branch.open_containing('.')[0]
783
 
        old = b.basis_tree()
784
 
        new = b.working_tree()
 
824
        tree = WorkingTree.open_containing(u'.')[0]
 
825
        old = tree.branch.basis_tree()
785
826
        for path, ie in old.inventory.iter_entries():
786
 
            if not new.has_id(ie.file_id):
 
827
            if not tree.has_id(ie.file_id):
787
828
                if show_ids:
788
829
                    print '%-50s %s' % (path, ie.file_id)
789
830
                else:
797
838
    def run(self):
798
839
        from bzrlib.delta import compare_trees
799
840
 
800
 
        b = Branch.open_containing('.')[0]
801
 
        td = compare_trees(b.basis_tree(), b.working_tree())
 
841
        tree = WorkingTree.open_containing(u'.')[0]
 
842
        td = compare_trees(tree.branch.basis_tree(), tree)
802
843
 
803
844
        for path, id, kind, text_modified, meta_modified in td.modified:
804
845
            print path
810
851
    hidden = True
811
852
    @display_command
812
853
    def run(self):
813
 
        b = Branch.open_containing('.')[0]
814
 
        wt = b.working_tree()
815
 
        basis_inv = b.basis_tree().inventory
 
854
        wt = WorkingTree.open_containing(u'.')[0]
 
855
        basis_inv = wt.branch.basis_tree().inventory
816
856
        inv = wt.inventory
817
857
        for file_id in inv:
818
858
            if file_id in basis_inv:
819
859
                continue
820
860
            path = inv.id2path(file_id)
821
 
            if not os.access(b.abspath(path), os.F_OK):
 
861
            if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
822
862
                continue
823
863
            print path
824
864
                
833
873
    @display_command
834
874
    def run(self, filename=None):
835
875
        """Print the branch root."""
836
 
        b = Branch.open_containing(filename)[0]
837
 
        print b.base
 
876
        tree = WorkingTree.open_containing(filename)[0]
 
877
        print tree.basedir
838
878
 
839
879
 
840
880
class cmd_log(Command):
852
892
                            help='show from oldest to newest'),
853
893
                     'timezone', 'verbose', 
854
894
                     'show-ids', 'revision',
855
 
                     Option('line', help='format with one line per revision'),
856
 
                     'long', 
 
895
                     'line', 'long', 
857
896
                     Option('message',
858
897
                            help='show revisions whose message matches this regexp',
859
898
                            type=str),
860
 
                     Option('short', help='use moderately short format'),
 
899
                     'short',
861
900
                     ]
862
901
    @display_command
863
902
    def run(self, filename=None, timezone='original',
876
915
        direction = (forward and 'forward') or 'reverse'
877
916
        
878
917
        if filename:
879
 
            b, fp = Branch.open_containing(filename)
 
918
            # might be a tree:
 
919
            tree = None
 
920
            try:
 
921
                tree, fp = WorkingTree.open_containing(filename)
 
922
                b = tree.branch
 
923
                if fp != '':
 
924
                    inv = tree.read_working_inventory()
 
925
            except NotBranchError:
 
926
                pass
 
927
            if tree is None:
 
928
                b, fp = Branch.open_containing(filename)
 
929
                if fp != '':
 
930
                    inv = b.get_inventory(b.last_revision())
880
931
            if fp != '':
881
 
                try:
882
 
                    inv = b.working_tree().read_working_inventory()
883
 
                except NoWorkingTree:
884
 
                    inv = b.get_inventory(b.last_revision())
885
932
                file_id = inv.path2id(fp)
886
933
            else:
887
934
                file_id = None  # points to branch root
888
935
        else:
889
 
            b, relpath = Branch.open_containing('.')
 
936
            tree, relpath = WorkingTree.open_containing(u'.')
 
937
            b = tree.branch
890
938
            file_id = None
891
939
 
892
940
        if revision is None:
912
960
        # in e.g. the default C locale.
913
961
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
914
962
 
915
 
        log_format = 'long'
916
 
        if short:
917
 
            log_format = 'short'
918
 
        if line:
919
 
            log_format = 'line'
 
963
        log_format = get_log_format(long=long, short=short, line=line)
920
964
        lf = log_formatter(log_format,
921
965
                           show_ids=show_ids,
922
966
                           to_file=outf,
931
975
                 end_revision=rev2,
932
976
                 search=message)
933
977
 
 
978
def get_log_format(long=False, short=False, line=False, default='long'):
 
979
    log_format = default
 
980
    if long:
 
981
        log_format = 'long'
 
982
    if short:
 
983
        log_format = 'short'
 
984
    if line:
 
985
        log_format = 'line'
 
986
    return log_format
934
987
 
935
988
 
936
989
class cmd_touching_revisions(Command):
941
994
    takes_args = ["filename"]
942
995
    @display_command
943
996
    def run(self, filename):
944
 
        b, relpath = Branch.open_containing(filename)[0]
945
 
        inv = b.working_tree().read_working_inventory()
 
997
        tree, relpath = WorkingTree.open_containing(filename)
 
998
        b = tree.branch
 
999
        inv = tree.read_working_inventory()
946
1000
        file_id = inv.path2id(relpath)
947
1001
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
948
1002
            print "%6d %s" % (revno, what)
976
1030
 
977
1031
        selection = {'I':ignored, '?':unknown, 'V':versioned}
978
1032
 
979
 
        b, relpath = Branch.open_containing('.')
 
1033
        tree, relpath = WorkingTree.open_containing(u'.')
980
1034
        if from_root:
981
 
            relpath = ''
 
1035
            relpath = u''
982
1036
        elif relpath:
983
1037
            relpath += '/'
984
 
        if revision == None:
985
 
            tree = b.working_tree()
986
 
        else:
987
 
            tree = b.revision_tree(revision[0].in_history(b).rev_id)
 
1038
        if revision is not None:
 
1039
            tree = tree.branch.revision_tree(
 
1040
                revision[0].in_history(tree.branch).rev_id)
988
1041
        for fp, fc, kind, fid, entry in tree.list_files():
989
1042
            if fp.startswith(relpath):
990
1043
                fp = fp[len(relpath):]
1003
1056
                    print fp
1004
1057
 
1005
1058
 
1006
 
 
1007
1059
class cmd_unknowns(Command):
1008
1060
    """List unknown files."""
1009
1061
    @display_command
1010
1062
    def run(self):
1011
1063
        from bzrlib.osutils import quotefn
1012
 
        for f in Branch.open_containing('.')[0].unknowns():
 
1064
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1013
1065
            print quotefn(f)
1014
1066
 
1015
1067
 
1016
 
 
1017
1068
class cmd_ignore(Command):
1018
1069
    """Ignore a command or pattern.
1019
1070
 
1039
1090
        from bzrlib.atomicfile import AtomicFile
1040
1091
        import os.path
1041
1092
 
1042
 
        b, relpath = Branch.open_containing('.')
1043
 
        ifn = b.abspath('.bzrignore')
 
1093
        tree, relpath = WorkingTree.open_containing(u'.')
 
1094
        ifn = tree.abspath('.bzrignore')
1044
1095
 
1045
1096
        if os.path.exists(ifn):
1046
1097
            f = open(ifn, 'rt')
1065
1116
        finally:
1066
1117
            f.close()
1067
1118
 
1068
 
        inv = b.working_tree().inventory
 
1119
        inv = tree.inventory
1069
1120
        if inv.path2id('.bzrignore'):
1070
1121
            mutter('.bzrignore is already versioned')
1071
1122
        else:
1072
1123
            mutter('need to make new .bzrignore file versioned')
1073
 
            b.add(['.bzrignore'])
1074
 
 
 
1124
            tree.add(['.bzrignore'])
1075
1125
 
1076
1126
 
1077
1127
class cmd_ignored(Command):
1080
1130
    See also: bzr ignore"""
1081
1131
    @display_command
1082
1132
    def run(self):
1083
 
        tree = Branch.open_containing('.')[0].working_tree()
 
1133
        tree = WorkingTree.open_containing(u'.')[0]
1084
1134
        for path, file_class, kind, file_id, entry in tree.list_files():
1085
1135
            if file_class != 'I':
1086
1136
                continue
1105
1155
        except ValueError:
1106
1156
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1107
1157
 
1108
 
        print Branch.open_containing('.')[0].get_rev_id(revno)
 
1158
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1109
1159
 
1110
1160
 
1111
1161
class cmd_export(Command):
1118
1168
    is found exports to a directory (equivalent to --format=dir).
1119
1169
 
1120
1170
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1121
 
    is given, the top directory will be the root name of the file."""
1122
 
    # TODO: list known exporters
 
1171
    is given, the top directory will be the root name of the file.
 
1172
 
 
1173
    Note: export of tree with non-ascii filenames to zip is not supported.
 
1174
 
 
1175
    Supported formats       Autodetected by extension
 
1176
    -----------------       -------------------------
 
1177
         dir                            -
 
1178
         tar                          .tar
 
1179
         tbz2                    .tar.bz2, .tbz2
 
1180
         tgz                      .tar.gz, .tgz
 
1181
         zip                          .zip
 
1182
    """
1123
1183
    takes_args = ['dest']
1124
1184
    takes_options = ['revision', 'format', 'root']
1125
1185
    def run(self, dest, revision=None, format=None, root=None):
1126
1186
        import os.path
1127
 
        b = Branch.open_containing('.')[0]
 
1187
        from bzrlib.export import export
 
1188
        tree = WorkingTree.open_containing(u'.')[0]
 
1189
        b = tree.branch
1128
1190
        if revision is None:
 
1191
            # should be tree.last_revision  FIXME
1129
1192
            rev_id = b.last_revision()
1130
1193
        else:
1131
1194
            if len(revision) != 1:
1132
1195
                raise BzrError('bzr export --revision takes exactly 1 argument')
1133
1196
            rev_id = revision[0].in_history(b).rev_id
1134
1197
        t = b.revision_tree(rev_id)
1135
 
        arg_root, ext = os.path.splitext(os.path.basename(dest))
1136
 
        if ext in ('.gz', '.bz2'):
1137
 
            new_root, new_ext = os.path.splitext(arg_root)
1138
 
            if new_ext == '.tar':
1139
 
                arg_root = new_root
1140
 
                ext = new_ext + ext
1141
 
        if root is None:
1142
 
            root = arg_root
1143
 
        if not format:
1144
 
            if ext in (".tar",):
1145
 
                format = "tar"
1146
 
            elif ext in (".tar.gz", ".tgz"):
1147
 
                format = "tgz"
1148
 
            elif ext in (".tar.bz2", ".tbz2"):
1149
 
                format = "tbz2"
1150
 
            else:
1151
 
                format = "dir"
1152
 
        t.export(dest, format, root)
 
1198
        try:
 
1199
            export(t, dest, format, root)
 
1200
        except errors.NoSuchExportFormat, e:
 
1201
            raise BzrCommandError('Unsupported export format: %s' % e.format)
1153
1202
 
1154
1203
 
1155
1204
class cmd_cat(Command):
1160
1209
 
1161
1210
    @display_command
1162
1211
    def run(self, filename, revision=None):
1163
 
        if revision is None:
1164
 
            raise BzrCommandError("bzr cat requires a revision number")
1165
 
        elif len(revision) != 1:
 
1212
        if revision is not None and len(revision) != 1:
1166
1213
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1167
 
        b, relpath = Branch.open_containing(filename)
1168
 
        b.print_file(relpath, revision[0].in_history(b).revno)
 
1214
        tree = None
 
1215
        try:
 
1216
            tree, relpath = WorkingTree.open_containing(filename)
 
1217
            b = tree.branch
 
1218
        except NotBranchError:
 
1219
            pass
 
1220
 
 
1221
        if tree is None:
 
1222
            b, relpath = Branch.open_containing(filename)
 
1223
        if revision is None:
 
1224
            revision_id = b.last_revision()
 
1225
        else:
 
1226
            revision_id = revision[0].in_history(b).rev_id
 
1227
        b.print_file(relpath, revision_id)
1169
1228
 
1170
1229
 
1171
1230
class cmd_local_time_offset(Command):
1216
1275
            unchanged=False, strict=False):
1217
1276
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1218
1277
                StrictCommitFailed)
1219
 
        from bzrlib.msgeditor import edit_commit_message
 
1278
        from bzrlib.msgeditor import edit_commit_message, \
 
1279
                make_commit_message_template
1220
1280
        from bzrlib.status import show_status
1221
 
        from cStringIO import StringIO
1222
 
 
1223
 
        b, selected_list = branch_files(selected_list)
 
1281
        from tempfile import TemporaryFile
 
1282
        import codecs
 
1283
 
 
1284
        # TODO: Need a blackbox test for invoking the external editor; may be
 
1285
        # slightly problematic to run this cross-platform.
 
1286
 
 
1287
        # TODO: do more checks that the commit will succeed before 
 
1288
        # spending the user's valuable time typing a commit message.
 
1289
        #
 
1290
        # TODO: if the commit *does* happen to fail, then save the commit 
 
1291
        # message to a temporary file where it can be recovered
 
1292
        tree, selected_list = tree_files(selected_list)
1224
1293
        if message is None and not file:
1225
 
            catcher = StringIO()
1226
 
            show_status(b, specific_files=selected_list,
1227
 
                        to_file=catcher)
1228
 
            message = edit_commit_message(catcher.getvalue())
1229
 
 
 
1294
            template = make_commit_message_template(tree, selected_list)
 
1295
            message = edit_commit_message(template)
1230
1296
            if message is None:
1231
1297
                raise BzrCommandError("please specify a commit message"
1232
1298
                                      " with either --message or --file")
1241
1307
                raise BzrCommandError("empty commit message specified")
1242
1308
            
1243
1309
        try:
1244
 
            b.working_tree().commit(message, specific_files=selected_list,
1245
 
                     allow_pointless=unchanged, strict=strict)
 
1310
            tree.commit(message, specific_files=selected_list,
 
1311
                        allow_pointless=unchanged, strict=strict)
1246
1312
        except PointlessCommit:
1247
1313
            # FIXME: This should really happen before the file is read in;
1248
1314
            # perhaps prepare the commit; get the message; then actually commit
1254
1320
        except StrictCommitFailed:
1255
1321
            raise BzrCommandError("Commit refused because there are unknown "
1256
1322
                                  "files in the working tree.")
 
1323
        note('Committed revision %d.' % (tree.branch.revno(),))
1257
1324
 
1258
1325
 
1259
1326
class cmd_check(Command):
1262
1329
    This command checks various invariants about the branch storage to
1263
1330
    detect data corruption or bzr bugs.
1264
1331
    """
1265
 
    takes_args = ['dir?']
 
1332
    takes_args = ['branch?']
1266
1333
    takes_options = ['verbose']
1267
1334
 
1268
 
    def run(self, dir='.', verbose=False):
 
1335
    def run(self, branch=None, verbose=False):
1269
1336
        from bzrlib.check import check
1270
 
        check(Branch.open_containing(dir)[0], verbose)
 
1337
        if branch is None:
 
1338
            tree = WorkingTree.open_containing()[0]
 
1339
            branch = tree.branch
 
1340
        else:
 
1341
            branch = Branch.open(branch)
 
1342
        check(branch, verbose)
1271
1343
 
1272
1344
 
1273
1345
class cmd_scan_cache(Command):
1275
1347
    def run(self):
1276
1348
        from bzrlib.hashcache import HashCache
1277
1349
 
1278
 
        c = HashCache('.')
 
1350
        c = HashCache(u'.')
1279
1351
        c.read()
1280
1352
        c.scan()
1281
1353
            
1301
1373
    """
1302
1374
    takes_args = ['dir?']
1303
1375
 
1304
 
    def run(self, dir='.'):
 
1376
    def run(self, dir=u'.'):
1305
1377
        from bzrlib.upgrade import upgrade
1306
1378
        upgrade(dir)
1307
1379
 
1313
1385
    @display_command
1314
1386
    def run(self, email=False):
1315
1387
        try:
1316
 
            b = bzrlib.branch.Branch.open_containing('.')[0]
 
1388
            b = WorkingTree.open_containing(u'.')[0].branch
1317
1389
            config = bzrlib.config.BranchConfig(b)
1318
1390
        except NotBranchError:
1319
1391
            config = bzrlib.config.GlobalConfig()
1331
1403
    """
1332
1404
    takes_args = ['nickname?']
1333
1405
    def run(self, nickname=None):
1334
 
        branch = Branch.open_containing('.')[0]
 
1406
        branch = Branch.open_containing(u'.')[0]
1335
1407
        if nickname is None:
1336
1408
            self.printme(branch)
1337
1409
        else:
1364
1436
    def run(self, testspecs_list=None, verbose=False, one=False,
1365
1437
            keep_output=False):
1366
1438
        import bzrlib.ui
1367
 
        from bzrlib.selftest import selftest
 
1439
        from bzrlib.tests import selftest
1368
1440
        # we don't want progress meters from the tests to go to the
1369
1441
        # real output; and we don't want log messages cluttering up
1370
1442
        # the real logs.
1389
1461
            bzrlib.ui.ui_factory = save_ui
1390
1462
 
1391
1463
 
 
1464
def _get_bzr_branch():
 
1465
    """If bzr is run from a branch, return Branch or None"""
 
1466
    import bzrlib.errors
 
1467
    from bzrlib.branch import Branch
 
1468
    from bzrlib.osutils import abspath
 
1469
    from os.path import dirname
 
1470
    
 
1471
    try:
 
1472
        branch = Branch.open(dirname(abspath(dirname(__file__))))
 
1473
        return branch
 
1474
    except bzrlib.errors.BzrError:
 
1475
        return None
 
1476
    
 
1477
 
1392
1478
def show_version():
1393
1479
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
1394
1480
    # is bzrlib itself in a branch?
1395
 
    bzrrev = bzrlib.get_bzr_revision()
1396
 
    if bzrrev:
1397
 
        print "  (bzr checkout, revision %d {%s})" % bzrrev
 
1481
    branch = _get_bzr_branch()
 
1482
    if branch:
 
1483
        rh = branch.revision_history()
 
1484
        revno = len(rh)
 
1485
        print "  bzr checkout, revision %d" % (revno,)
 
1486
        print "  nick: %s" % (branch.nick,)
 
1487
        if rh:
 
1488
            print "  revid: %s" % (rh[-1],)
1398
1489
    print bzrlib.__copyright__
1399
1490
    print "http://bazaar-ng.org/"
1400
1491
    print
1496
1587
        if merge_type is None:
1497
1588
            merge_type = ApplyMerge3
1498
1589
        if branch is None:
1499
 
            branch = Branch.open_containing('.')[0].get_parent()
 
1590
            branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
1500
1591
            if branch is None:
1501
1592
                raise BzrCommandError("No merge location known or specified.")
1502
1593
            else:
1552
1643
        from bzrlib.merge_core import ApplyMerge3
1553
1644
        if merge_type is None:
1554
1645
            merge_type = ApplyMerge3
1555
 
        b, file_list = branch_files(file_list)
1556
 
        b.lock_write()
 
1646
        tree, file_list = tree_files(file_list)
 
1647
        tree.lock_write()
1557
1648
        try:
1558
 
            pending_merges = b.working_tree().pending_merges() 
 
1649
            pending_merges = tree.pending_merges() 
1559
1650
            if len(pending_merges) != 1:
1560
1651
                raise BzrCommandError("Sorry, remerge only works after normal"
1561
1652
                                      + " merges.  Not cherrypicking or"
1562
1653
                                      + "multi-merges.")
1563
 
            this_tree = b.working_tree()
1564
 
            base_revision = common_ancestor(b.last_revision(), 
1565
 
                                            pending_merges[0], b)
1566
 
            base_tree = b.revision_tree(base_revision)
1567
 
            other_tree = b.revision_tree(pending_merges[0])
 
1654
            base_revision = common_ancestor(tree.branch.last_revision(), 
 
1655
                                            pending_merges[0], tree.branch)
 
1656
            base_tree = tree.branch.revision_tree(base_revision)
 
1657
            other_tree = tree.branch.revision_tree(pending_merges[0])
1568
1658
            interesting_ids = None
1569
1659
            if file_list is not None:
1570
1660
                interesting_ids = set()
1571
1661
                for filename in file_list:
1572
 
                    file_id = this_tree.path2id(filename)
 
1662
                    file_id = tree.path2id(filename)
1573
1663
                    interesting_ids.add(file_id)
1574
 
                    if this_tree.kind(file_id) != "directory":
 
1664
                    if tree.kind(file_id) != "directory":
1575
1665
                        continue
1576
1666
                    
1577
 
                    for name, ie in this_tree.inventory.iter_entries(file_id):
 
1667
                    for name, ie in tree.inventory.iter_entries(file_id):
1578
1668
                        interesting_ids.add(ie.file_id)
1579
 
            transform_tree(this_tree, b.basis_tree(), interesting_ids)
 
1669
            transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1580
1670
            if file_list is None:
1581
 
                restore_files = list(this_tree.iter_conflicts())
 
1671
                restore_files = list(tree.iter_conflicts())
1582
1672
            else:
1583
1673
                restore_files = file_list
1584
1674
            for filename in restore_files:
1585
1675
                try:
1586
 
                    restore(this_tree.abspath(filename))
 
1676
                    restore(tree.abspath(filename))
1587
1677
                except NotConflicted:
1588
1678
                    pass
1589
 
            conflicts =  merge_inner(b, other_tree, base_tree, 
 
1679
            conflicts =  merge_inner(tree.branch, other_tree, base_tree, 
1590
1680
                                     interesting_ids = interesting_ids, 
1591
1681
                                     other_rev_id=pending_merges[0], 
1592
1682
                                     merge_type=merge_type, 
1593
1683
                                     show_base=show_base,
1594
1684
                                     reprocess=reprocess)
1595
1685
        finally:
1596
 
            b.unlock()
 
1686
            tree.unlock()
1597
1687
        if conflicts > 0:
1598
1688
            return 1
1599
1689
        else:
1620
1710
            file_list = []
1621
1711
        if revision is None:
1622
1712
            revno = -1
1623
 
            b = Branch.open_containing('.')[0]
1624
 
            rev_id = b.last_revision()
 
1713
            tree = WorkingTree.open_containing(u'.')[0]
 
1714
            # FIXME should be tree.last_revision
 
1715
            rev_id = tree.branch.last_revision()
1625
1716
        elif len(revision) != 1:
1626
1717
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1627
1718
        else:
1628
 
            b, file_list = branch_files(file_list)
1629
 
            rev_id = revision[0].in_history(b).rev_id
1630
 
        b.working_tree().revert(file_list, b.revision_tree(rev_id),
 
1719
            tree, file_list = tree_files(file_list)
 
1720
            rev_id = revision[0].in_history(tree.branch).rev_id
 
1721
        tree.revert(file_list, tree.branch.revision_tree(rev_id),
1631
1722
                                not no_backup)
1632
1723
 
1633
1724
 
1691
1782
 
1692
1783
 
1693
1784
class cmd_missing(Command):
1694
 
    """What is missing in this branch relative to other branch.
1695
 
    """
1696
 
    # TODO: rewrite this in terms of ancestry so that it shows only
1697
 
    # unmerged things
1698
 
    
1699
 
    takes_args = ['remote?']
1700
 
    aliases = ['mis', 'miss']
1701
 
    # We don't have to add quiet to the list, because 
1702
 
    # unknown options are parsed as booleans
1703
 
    takes_options = ['verbose', 'quiet']
1704
 
 
1705
 
    @display_command
1706
 
    def run(self, remote=None, verbose=False, quiet=False):
1707
 
        from bzrlib.errors import BzrCommandError
1708
 
        from bzrlib.missing import show_missing
1709
 
 
1710
 
        if verbose and quiet:
1711
 
            raise BzrCommandError('Cannot pass both quiet and verbose')
1712
 
 
1713
 
        b = Branch.open_containing('.')[0]
1714
 
        parent = b.get_parent()
1715
 
        if remote is None:
1716
 
            if parent is None:
 
1785
    """Show unmerged/unpulled revisions between two branches.
 
1786
 
 
1787
    OTHER_BRANCH may be local or remote."""
 
1788
    takes_args = ['other_branch?']
 
1789
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
 
1790
                     Option('mine-only', 
 
1791
                            'Display changes in the local branch only'),
 
1792
                     Option('theirs-only', 
 
1793
                            'Display changes in the remote branch only'), 
 
1794
                     'line',
 
1795
                     'long', 
 
1796
                     'short',
 
1797
                     'show-ids',
 
1798
                     'verbose'
 
1799
                     ]
 
1800
 
 
1801
    def run(self, other_branch=None, reverse=False, mine_only=False,
 
1802
            theirs_only=False, long=True, short=False, line=False, 
 
1803
            show_ids=False, verbose=False):
 
1804
        from bzrlib.missing import find_unmerged, iter_log_data
 
1805
        from bzrlib.log import log_formatter
 
1806
        local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
 
1807
        parent = local_branch.get_parent()
 
1808
        if other_branch is None:
 
1809
            other_branch = parent
 
1810
            if other_branch is None:
1717
1811
                raise BzrCommandError("No missing location known or specified.")
1718
 
            else:
1719
 
                if not quiet:
1720
 
                    print "Using last location: %s" % parent
1721
 
                remote = parent
1722
 
        elif parent is None:
1723
 
            # We only update parent if it did not exist, missing
1724
 
            # should not change the parent
1725
 
            b.set_parent(remote)
1726
 
        br_remote = Branch.open_containing(remote)[0]
1727
 
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
 
1812
            print "Using last location: " + local_branch.get_parent()
 
1813
        remote_branch = bzrlib.branch.Branch.open(other_branch)
 
1814
        local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
 
1815
        log_format = get_log_format(long=long, short=short, line=line)
 
1816
        lf = log_formatter(log_format, sys.stdout,
 
1817
                           show_ids=show_ids,
 
1818
                           show_timezone='original')
 
1819
        if reverse is False:
 
1820
            local_extra.reverse()
 
1821
            remote_extra.reverse()
 
1822
        if local_extra and not theirs_only:
 
1823
            print "You have %d extra revision(s):" % len(local_extra)
 
1824
            for data in iter_log_data(local_extra, local_branch, verbose):
 
1825
                lf.show(*data)
 
1826
            printed_local = True
 
1827
        else:
 
1828
            printed_local = False
 
1829
        if remote_extra and not mine_only:
 
1830
            if printed_local is True:
 
1831
                print "\n\n"
 
1832
            print "You are missing %d revision(s):" % len(remote_extra)
 
1833
            for data in iter_log_data(remote_extra, remote_branch, verbose):
 
1834
                lf.show(*data)
 
1835
        if not remote_extra and not local_extra:
 
1836
            status_code = 0
 
1837
            print "Branches are up to date."
 
1838
        else:
 
1839
            status_code = 1
 
1840
        if parent is None and other_branch is not None:
 
1841
            local_branch.set_parent(other_branch)
 
1842
        return status_code
1728
1843
 
1729
1844
 
1730
1845
class cmd_plugins(Command):
1734
1849
    def run(self):
1735
1850
        import bzrlib.plugin
1736
1851
        from inspect import getdoc
1737
 
        for plugin in bzrlib.plugin.all_plugins:
 
1852
        for name, plugin in bzrlib.plugin.all_plugins().items():
1738
1853
            if hasattr(plugin, '__path__'):
1739
1854
                print plugin.__path__[0]
1740
1855
            elif hasattr(plugin, '__file__'):
1752
1867
    takes_options = ['revision', 'long']
1753
1868
    takes_args = ['branch?']
1754
1869
    @display_command
1755
 
    def run(self, branch='.', revision=None, long=False):
 
1870
    def run(self, branch=u'.', revision=None, long=False):
1756
1871
        from bzrlib.testament import Testament
1757
 
        b = Branch.open_containing(branch)[0]
 
1872
        b = WorkingTree.open_containing(branch)[0].branch
1758
1873
        b.lock_read()
1759
1874
        try:
1760
1875
            if revision is None:
1792
1907
    @display_command
1793
1908
    def run(self, filename, all=False, long=False):
1794
1909
        from bzrlib.annotate import annotate_file
1795
 
        b, relpath = Branch.open_containing(filename)
1796
 
        b.lock_read()
 
1910
        tree, relpath = WorkingTree.open_containing(filename)
 
1911
        branch = tree.branch
 
1912
        branch.lock_read()
1797
1913
        try:
1798
 
            tree = WorkingTree(b.base, b)
1799
 
            tree = b.revision_tree(b.last_revision())
1800
1914
            file_id = tree.inventory.path2id(relpath)
 
1915
            tree = branch.revision_tree(branch.last_revision())
1801
1916
            file_version = tree.inventory[file_id].revision
1802
 
            annotate_file(b, file_version, file_id, long, all, sys.stdout)
 
1917
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1803
1918
        finally:
1804
 
            b.unlock()
 
1919
            branch.unlock()
1805
1920
 
1806
1921
 
1807
1922
class cmd_re_sign(Command):
1819
1934
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1820
1935
        if revision_id is None and revision is None:
1821
1936
            raise BzrCommandError('You must supply either --revision or a revision_id')
1822
 
        b = Branch.open_containing('.')[0]
 
1937
        b = WorkingTree.open_containing(u'.')[0].branch
1823
1938
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1824
1939
        if revision_id is not None:
1825
1940
            b.sign_revision(revision_id, gpg_strategy)
1843
1958
                raise BzrCommandError('Please supply either one revision, or a range.')
1844
1959
 
1845
1960
 
 
1961
class cmd_uncommit(bzrlib.commands.Command):
 
1962
    """Remove the last committed revision.
 
1963
 
 
1964
    By supplying the --all flag, it will not only remove the entry 
 
1965
    from revision_history, but also remove all of the entries in the
 
1966
    stores.
 
1967
 
 
1968
    --verbose will print out what is being removed.
 
1969
    --dry-run will go through all the motions, but not actually
 
1970
    remove anything.
 
1971
    
 
1972
    In the future, uncommit will create a changeset, which can then
 
1973
    be re-applied.
 
1974
 
 
1975
    TODO: jam 20060108 Add an option to allow uncommit to remove unreferenced
 
1976
              information in 'branch-as-repostory' branches.
 
1977
    TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
 
1978
              information in shared branches as well.
 
1979
    """
 
1980
    takes_options = ['verbose', 'revision',
 
1981
                    Option('dry-run', help='Don\'t actually make changes'),
 
1982
                    Option('force', help='Say yes to all questions.')]
 
1983
    takes_args = ['location?']
 
1984
    aliases = []
 
1985
 
 
1986
    def run(self, location=None, 
 
1987
            dry_run=False, verbose=False,
 
1988
            revision=None, force=False):
 
1989
        from bzrlib.branch import Branch
 
1990
        from bzrlib.log import log_formatter
 
1991
        import sys
 
1992
        from bzrlib.uncommit import uncommit
 
1993
 
 
1994
        if location is None:
 
1995
            location = u'.'
 
1996
        b, relpath = Branch.open_containing(location)
 
1997
 
 
1998
        if revision is None:
 
1999
            revno = b.revno()
 
2000
            rev_id = b.last_revision()
 
2001
        else:
 
2002
            revno, rev_id = revision[0].in_history(b)
 
2003
        if rev_id is None:
 
2004
            print 'No revisions to uncommit.'
 
2005
 
 
2006
        for r in range(revno, b.revno()+1):
 
2007
            rev_id = b.get_rev_id(r)
 
2008
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
 
2009
            lf.show(r, b.get_revision(rev_id), None)
 
2010
 
 
2011
        if dry_run:
 
2012
            print 'Dry-run, pretending to remove the above revisions.'
 
2013
            if not force:
 
2014
                val = raw_input('Press <enter> to continue')
 
2015
        else:
 
2016
            print 'The above revision(s) will be removed.'
 
2017
            if not force:
 
2018
                val = raw_input('Are you sure [y/N]? ')
 
2019
                if val.lower() not in ('y', 'yes'):
 
2020
                    print 'Canceled'
 
2021
                    return 0
 
2022
 
 
2023
        uncommit(b, dry_run=dry_run, verbose=verbose,
 
2024
                revno=revno)
 
2025
 
 
2026
 
1846
2027
# these get imported and then picked up by the scan for cmd_*
1847
2028
# TODO: Some more consistent way to split command definitions across files;
1848
2029
# we do need to load at least some information about them to know of