~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2005-11-28 05:13:41 UTC
  • mfrom: (1185.33.54 merge-recovered)
  • Revision ID: robertc@robertcollins.net-20051128051341-059936f2f29a12c8
Merge from Martin. Adjust check to work with HTTP again.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
from bzrlib.commands import Command, display_command
28
28
from bzrlib.branch import Branch
29
29
from bzrlib.revision import common_ancestor
 
30
import bzrlib.errors as errors
30
31
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
31
32
                           NotBranchError, DivergedBranches, NotConflicted,
32
 
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
 
33
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
33
34
from bzrlib.option import Option
34
35
from bzrlib.revisionspec import RevisionSpec
35
36
import bzrlib.trace
36
 
from bzrlib.trace import mutter, note, log_error, warning
 
37
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
37
38
from bzrlib.workingtree import WorkingTree
38
39
 
39
40
 
40
 
def branch_files(file_list, default_branch='.'):
 
41
def tree_files(file_list, default_branch='.'):
41
42
    try:
42
 
        return inner_branch_files(file_list, default_branch)
 
43
        return internal_tree_files(file_list, default_branch)
43
44
    except FileInWrongBranch, e:
44
45
        raise BzrCommandError("%s is not in the same branch as %s" %
45
46
                             (e.path, file_list[0]))
46
47
 
47
 
def inner_branch_files(file_list, default_branch='.'):
 
48
def internal_tree_files(file_list, default_branch='.'):
48
49
    """\
49
50
    Return a branch and list of branch-relative paths.
50
51
    If supplied file_list is empty or None, the branch default will be used,
51
52
    and returned file_list will match the original.
52
53
    """
53
54
    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)
 
55
        return WorkingTree.open_containing(default_branch)[0], file_list
 
56
    tree = WorkingTree.open_containing(file_list[0])[0]
62
57
    new_list = []
63
58
    for filename in file_list:
64
59
        try:
65
60
            new_list.append(tree.relpath(filename))
66
61
        except NotBranchError:
67
 
            raise FileInWrongBranch(b, filename)
68
 
    return b, new_list
 
62
            raise FileInWrongBranch(tree.branch, filename)
 
63
    return tree, new_list
69
64
 
70
65
 
71
66
# TODO: Make sure no commands unconditionally use the working directory as a
122
117
    
123
118
    @display_command
124
119
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
125
 
        b, file_list = branch_files(file_list)
 
120
        tree, file_list = tree_files(file_list)
126
121
            
127
122
        from bzrlib.status import show_status
128
 
        show_status(b, show_unchanged=all, show_ids=show_ids,
 
123
        show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
129
124
                    specific_files=file_list, revision=revision)
130
125
 
131
126
 
147
142
            raise BzrCommandError('You can only supply one of revision_id or --revision')
148
143
        if revision_id is None and revision is None:
149
144
            raise BzrCommandError('You must supply either --revision or a revision_id')
150
 
        b = Branch.open_containing('.')[0]
 
145
        b = WorkingTree.open_containing('.')[0].branch
151
146
        if revision_id is not None:
152
 
            sys.stdout.write(b.get_revision_xml_file(revision_id).read())
 
147
            sys.stdout.write(b.get_revision_xml(revision_id))
153
148
        elif revision is not None:
154
149
            for rev in revision:
155
150
                if rev is None:
156
151
                    raise BzrCommandError('You cannot specify a NULL revision.')
157
152
                revno, rev_id = rev.in_history(b)
158
 
                sys.stdout.write(b.get_revision_xml_file(rev_id).read())
 
153
                sys.stdout.write(b.get_revision_xml(rev_id))
159
154
    
160
155
 
161
156
class cmd_revno(Command):
185
180
        if len(revs) == 0:
186
181
            raise BzrCommandError('You must supply a revision identifier')
187
182
 
188
 
        b = Branch.open_containing('.')[0]
 
183
        b = WorkingTree.open_containing('.')[0].branch
189
184
 
190
185
        for rev in revs:
191
186
            revinfo = rev.in_history(b)
219
214
    get added when you add a file in the directory.
220
215
    """
221
216
    takes_args = ['file*']
222
 
    takes_options = ['no-recurse', 'quiet']
 
217
    takes_options = ['no-recurse']
223
218
    
224
 
    def run(self, file_list, no_recurse=False, quiet=False):
 
219
    def run(self, file_list, no_recurse=False):
225
220
        from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
226
 
        if quiet:
 
221
        if is_quiet():
227
222
            reporter = add_reporter_null
228
223
        else:
229
224
            reporter = add_reporter_print
238
233
    takes_args = ['dir+']
239
234
 
240
235
    def run(self, dir_list):
241
 
        b = None
242
 
        
243
236
        for d in dir_list:
244
237
            os.mkdir(d)
245
 
            b, dd = Branch.open_containing(d)
246
 
            b.add([dd])
 
238
            wt, dd = WorkingTree.open_containing(d)
 
239
            wt.add([dd])
247
240
            print 'added', d
248
241
 
249
242
 
254
247
    
255
248
    @display_command
256
249
    def run(self, filename):
257
 
        branch, relpath = Branch.open_containing(filename)
 
250
        tree, relpath = WorkingTree.open_containing(filename)
258
251
        print relpath
259
252
 
260
253
 
270
263
    def run(self, revision=None, show_ids=False, kind=None):
271
264
        if kind and kind not in ['file', 'directory', 'symlink']:
272
265
            raise BzrCommandError('invalid kind specified')
273
 
        b = Branch.open_containing('.')[0]
 
266
        tree = WorkingTree.open_containing('.')[0]
274
267
        if revision is None:
275
 
            inv = b.working_tree().read_working_inventory()
 
268
            inv = tree.read_working_inventory()
276
269
        else:
277
270
            if len(revision) > 1:
278
271
                raise BzrCommandError('bzr inventory --revision takes'
279
272
                    ' exactly one revision identifier')
280
 
            inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
 
273
            inv = tree.branch.get_revision_inventory(
 
274
                revision[0].in_history(tree.branch).rev_id)
281
275
 
282
276
        for path, entry in inv.entries():
283
277
            if kind and kind != entry.kind:
298
292
    """
299
293
    takes_args = ['source$', 'dest']
300
294
    def run(self, source_list, dest):
301
 
        b, source_list = branch_files(source_list)
302
 
 
 
295
        tree, source_list = tree_files(source_list)
303
296
        # TODO: glob expansion on windows?
304
 
        tree = WorkingTree(b.base, b)
305
 
        b.move(source_list, tree.relpath(dest))
 
297
        tree.move(source_list, tree.relpath(dest))
306
298
 
307
299
 
308
300
class cmd_rename(Command):
322
314
    takes_args = ['from_name', 'to_name']
323
315
    
324
316
    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)
 
317
        tree, (from_name, to_name) = tree_files((from_name, to_name))
 
318
        tree.rename_one(from_name, to_name)
327
319
 
328
320
 
329
321
class cmd_mv(Command):
343
335
    def run(self, names_list):
344
336
        if len(names_list) < 2:
345
337
            raise BzrCommandError("missing file argument")
346
 
        b, rel_names = branch_files(names_list)
 
338
        tree, rel_names = tree_files(names_list)
347
339
        
348
340
        if os.path.isdir(names_list[-1]):
349
341
            # move into existing directory
350
 
            for pair in b.move(rel_names[:-1], rel_names[-1]):
 
342
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
351
343
                print "%s => %s" % pair
352
344
        else:
353
345
            if len(names_list) != 2:
354
346
                raise BzrCommandError('to mv multiple files the destination '
355
347
                                      'must be a versioned directory')
356
 
            b.rename_one(rel_names[0], rel_names[1])
 
348
            tree.rename_one(rel_names[0], rel_names[1])
357
349
            print "%s => %s" % (rel_names[0], rel_names[1])
358
350
            
359
351
    
382
374
        from bzrlib.merge import merge
383
375
        from shutil import rmtree
384
376
        import errno
385
 
        
386
 
        br_to = Branch.open_containing('.')[0]
387
 
        stored_loc = br_to.get_parent()
 
377
        # FIXME: too much stuff is in the command class        
 
378
        tree_to = WorkingTree.open_containing('.')[0]
 
379
        stored_loc = tree_to.branch.get_parent()
388
380
        if location is None:
389
381
            if stored_loc is None:
390
382
                raise BzrCommandError("No pull location known or specified.")
392
384
                print "Using saved location: %s" % stored_loc
393
385
                location = stored_loc
394
386
        br_from = Branch.open(location)
 
387
        br_to = tree_to.branch
395
388
        try:
396
389
            old_rh = br_to.revision_history()
397
 
            br_to.working_tree().pull(br_from, overwrite)
 
390
            count = tree_to.pull(br_from, overwrite)
398
391
        except DivergedBranches:
 
392
            # FIXME: Just make DivergedBranches display the right message
 
393
            # itself.
399
394
            raise BzrCommandError("These branches have diverged."
400
395
                                  "  Try merge.")
401
396
        if br_to.get_parent() is None or remember:
402
397
            br_to.set_parent(location)
403
 
 
 
398
        note('%d revision(s) pulled.', count)
404
399
        if verbose:
405
 
            new_rh = br_to.revision_history()
 
400
            new_rh = tree_to.branch.revision_history()
406
401
            if old_rh != new_rh:
407
402
                # Something changed
408
403
                from bzrlib.log import show_changed_revisions
409
 
                show_changed_revisions(br_to, old_rh, new_rh)
 
404
                show_changed_revisions(tree_to.branch, old_rh, new_rh)
410
405
 
411
406
 
412
407
class cmd_push(Command):
440
435
 
441
436
    def run(self, location=None, remember=False, overwrite=False,
442
437
            create_prefix=False, verbose=False):
 
438
        # FIXME: Way too big!  Put this into a function called from the
 
439
        # command.
443
440
        import errno
444
441
        from shutil import rmtree
445
442
        from bzrlib.transport import get_transport
446
443
        
447
 
        br_from = Branch.open_containing('.')[0]
448
 
        stored_loc = br_from.get_push_location()
 
444
        tree_from = WorkingTree.open_containing('.')[0]
 
445
        br_from = tree_from.branch
 
446
        stored_loc = tree_from.branch.get_push_location()
449
447
        if location is None:
450
448
            if stored_loc is None:
451
449
                raise BzrCommandError("No push location known or specified.")
478
476
                        if new_transport.base == transport.base:
479
477
                            raise BzrCommandError("Could not creeate "
480
478
                                                  "path prefix.")
481
 
                        
482
 
            NoSuchFile
483
479
            br_to = Branch.initialize(location)
484
480
        try:
485
481
            old_rh = br_to.revision_history()
486
 
            br_to.pull(br_from, overwrite)
 
482
            count = br_to.pull(br_from, overwrite)
487
483
        except DivergedBranches:
488
484
            raise BzrCommandError("These branches have diverged."
489
485
                                  "  Try a merge then push with overwrite.")
490
486
        if br_from.get_push_location() is None or remember:
491
487
            br_from.set_push_location(location)
492
 
 
 
488
        note('%d revision(s) pushed.' % (count,))
493
489
        if verbose:
494
490
            new_rh = br_to.revision_history()
495
491
            if old_rh != new_rh:
497
493
                from bzrlib.log import show_changed_revisions
498
494
                show_changed_revisions(br_to, old_rh, new_rh)
499
495
 
 
496
 
500
497
class cmd_branch(Command):
501
498
    """Create a new copy of a branch.
502
499
 
534
531
        br_from.lock_read()
535
532
        try:
536
533
            if basis is not None:
537
 
                basis_branch = Branch.open_containing(basis)[0]
 
534
                basis_branch = WorkingTree.open_containing(basis)[0].branch
538
535
            else:
539
536
                basis_branch = None
540
537
            if len(revision) == 1 and revision[0] is not None:
567
564
                rmtree(to_location)
568
565
                msg = "The branch %s cannot be used as a --basis"
569
566
                raise BzrCommandError(msg)
 
567
            branch = Branch.open(to_location)
570
568
            if name:
571
 
                branch = Branch.open(to_location)
572
569
                name = StringIO(name)
573
570
                branch.put_controlfile('branch-name', name)
 
571
            note('Branched %d revision(s).' % branch.revno())
574
572
        finally:
575
573
            br_from.unlock()
576
574
 
585
583
 
586
584
    @display_command
587
585
    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()
 
586
        tree = WorkingTree.open_containing(dir)[0]
 
587
        old_inv = tree.branch.basis_tree().inventory
 
588
        new_inv = tree.read_working_inventory()
591
589
 
592
590
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
593
591
        renames.sort()
602
600
    @display_command
603
601
    def run(self, branch=None):
604
602
        import info
605
 
        b = Branch.open_containing(branch)[0]
 
603
        b = WorkingTree.open_containing(branch)[0].branch
606
604
        info.show_info(b)
607
605
 
608
606
 
617
615
    aliases = ['rm']
618
616
    
619
617
    def run(self, file_list, verbose=False):
620
 
        b, file_list = branch_files(file_list)
621
 
        tree = b.working_tree()
 
618
        tree, file_list = tree_files(file_list)
622
619
        tree.remove(file_list, verbose=verbose)
623
620
 
624
621
 
633
630
    takes_args = ['filename']
634
631
    @display_command
635
632
    def run(self, filename):
636
 
        b, relpath = Branch.open_containing(filename)
637
 
        i = b.working_tree().inventory.path2id(relpath)
 
633
        tree, relpath = WorkingTree.open_containing(filename)
 
634
        i = tree.inventory.path2id(relpath)
638
635
        if i == None:
639
636
            raise BzrError("%r is not a versioned file" % filename)
640
637
        else:
650
647
    takes_args = ['filename']
651
648
    @display_command
652
649
    def run(self, filename):
653
 
        b, relpath = Branch.open_containing(filename)
654
 
        inv = b.inventory
 
650
        tree, relpath = WorkingTree.open_containing(filename)
 
651
        inv = tree.inventory
655
652
        fid = inv.path2id(relpath)
656
653
        if fid == None:
657
654
            raise BzrError("%r is not a versioned file" % filename)
664
661
    hidden = True
665
662
    @display_command
666
663
    def run(self):
667
 
        for patchid in Branch.open_containing('.')[0].revision_history():
 
664
        branch = WorkingTree.open_containing('.')[0].branch
 
665
        for patchid in branch.revision_history():
668
666
            print patchid
669
667
 
670
668
 
673
671
    hidden = True
674
672
    @display_command
675
673
    def run(self):
676
 
        b = Branch.open_containing('.')[0]
 
674
        tree = WorkingTree.open_containing('.')[0]
 
675
        b = tree.branch
 
676
        # FIXME. should be tree.last_revision
677
677
        for revision_id in b.get_ancestry(b.last_revision()):
678
678
            print revision_id
679
679
 
740
740
    def run(self, revision=None, file_list=None, diff_options=None):
741
741
        from bzrlib.diff import show_diff
742
742
        try:
743
 
            b, file_list = inner_branch_files(file_list)
 
743
            tree, file_list = internal_tree_files(file_list)
 
744
            b = None
744
745
            b2 = None
745
746
        except FileInWrongBranch:
746
747
            if len(file_list) != 2:
749
750
            b, file1 = Branch.open_containing(file_list[0])
750
751
            b2, file2 = Branch.open_containing(file_list[1])
751
752
            if file1 != "" or file2 != "":
 
753
                # FIXME diff those two files. rbc 20051123
752
754
                raise BzrCommandError("Files are in different branches")
753
755
            file_list = None
754
756
        if revision is not None:
755
757
            if b2 is not None:
756
758
                raise BzrCommandError("Can't specify -r with two branches")
757
759
            if len(revision) == 1:
758
 
                return show_diff(b, revision[0], specific_files=file_list,
 
760
                return show_diff(tree.branch, revision[0], specific_files=file_list,
759
761
                                 external_diff_options=diff_options)
760
762
            elif len(revision) == 2:
761
 
                return show_diff(b, revision[0], specific_files=file_list,
 
763
                return show_diff(tree.branch, revision[0], specific_files=file_list,
762
764
                                 external_diff_options=diff_options,
763
765
                                 revision2=revision[1])
764
766
            else:
765
767
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
766
768
        else:
767
 
            return show_diff(b, None, specific_files=file_list,
768
 
                             external_diff_options=diff_options, b2=b2)
 
769
            if b is not None:
 
770
                return show_diff(b, None, specific_files=file_list,
 
771
                                 external_diff_options=diff_options, b2=b2)
 
772
            else:
 
773
                return show_diff(tree.branch, None, specific_files=file_list,
 
774
                                 external_diff_options=diff_options)
769
775
 
770
776
 
771
777
class cmd_deleted(Command):
779
785
    # if the directories are very large...)
780
786
    @display_command
781
787
    def run(self, show_ids=False):
782
 
        b = Branch.open_containing('.')[0]
783
 
        old = b.basis_tree()
784
 
        new = b.working_tree()
 
788
        tree = WorkingTree.open_containing('.')[0]
 
789
        old = tree.branch.basis_tree()
785
790
        for path, ie in old.inventory.iter_entries():
786
 
            if not new.has_id(ie.file_id):
 
791
            if not tree.has_id(ie.file_id):
787
792
                if show_ids:
788
793
                    print '%-50s %s' % (path, ie.file_id)
789
794
                else:
797
802
    def run(self):
798
803
        from bzrlib.delta import compare_trees
799
804
 
800
 
        b = Branch.open_containing('.')[0]
801
 
        td = compare_trees(b.basis_tree(), b.working_tree())
 
805
        tree = WorkingTree.open_containing('.')[0]
 
806
        td = compare_trees(tree.branch.basis_tree(), tree)
802
807
 
803
808
        for path, id, kind, text_modified, meta_modified in td.modified:
804
809
            print path
810
815
    hidden = True
811
816
    @display_command
812
817
    def run(self):
813
 
        b = Branch.open_containing('.')[0]
814
 
        wt = b.working_tree()
815
 
        basis_inv = b.basis_tree().inventory
 
818
        wt = WorkingTree.open_containing('.')[0]
 
819
        basis_inv = wt.branch.basis_tree().inventory
816
820
        inv = wt.inventory
817
821
        for file_id in inv:
818
822
            if file_id in basis_inv:
833
837
    @display_command
834
838
    def run(self, filename=None):
835
839
        """Print the branch root."""
836
 
        b = Branch.open_containing(filename)[0]
837
 
        print b.base
 
840
        tree = WorkingTree.open_containing(filename)[0]
 
841
        print tree.basedir
838
842
 
839
843
 
840
844
class cmd_log(Command):
876
880
        direction = (forward and 'forward') or 'reverse'
877
881
        
878
882
        if filename:
879
 
            b, fp = Branch.open_containing(filename)
 
883
            # might be a tree:
 
884
            tree = None
 
885
            try:
 
886
                tree, fp = WorkingTree.open_containing(filename)
 
887
                b = tree.branch
 
888
                if fp != '':
 
889
                    inv = tree.read_working_inventory()
 
890
            except NotBranchError:
 
891
                pass
 
892
            if tree is None:
 
893
                b, fp = Branch.open_containing(filename)
 
894
                if fp != '':
 
895
                    inv = b.get_inventory(b.last_revision())
880
896
            if fp != '':
881
 
                try:
882
 
                    inv = b.working_tree().read_working_inventory()
883
 
                except NoWorkingTree:
884
 
                    inv = b.get_inventory(b.last_revision())
885
897
                file_id = inv.path2id(fp)
886
898
            else:
887
899
                file_id = None  # points to branch root
888
900
        else:
889
 
            b, relpath = Branch.open_containing('.')
 
901
            tree, relpath = WorkingTree.open_containing('.')
 
902
            b = tree.branch
890
903
            file_id = None
891
904
 
892
905
        if revision is None:
941
954
    takes_args = ["filename"]
942
955
    @display_command
943
956
    def run(self, filename):
944
 
        b, relpath = Branch.open_containing(filename)[0]
945
 
        inv = b.working_tree().read_working_inventory()
 
957
        tree, relpath = WorkingTree.open_containing(filename)
 
958
        b = tree.branch
 
959
        inv = tree.read_working_inventory()
946
960
        file_id = inv.path2id(relpath)
947
961
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
948
962
            print "%6d %s" % (revno, what)
976
990
 
977
991
        selection = {'I':ignored, '?':unknown, 'V':versioned}
978
992
 
979
 
        b, relpath = Branch.open_containing('.')
 
993
        tree, relpath = WorkingTree.open_containing('.')
980
994
        if from_root:
981
995
            relpath = ''
982
996
        elif relpath:
983
997
            relpath += '/'
984
 
        if revision == None:
985
 
            tree = b.working_tree()
986
 
        else:
987
 
            tree = b.revision_tree(revision[0].in_history(b).rev_id)
 
998
        if revision is not None:
 
999
            tree = tree.branch.revision_tree(
 
1000
                revision[0].in_history(tree.branch).rev_id)
988
1001
        for fp, fc, kind, fid, entry in tree.list_files():
989
1002
            if fp.startswith(relpath):
990
1003
                fp = fp[len(relpath):]
1003
1016
                    print fp
1004
1017
 
1005
1018
 
1006
 
 
1007
1019
class cmd_unknowns(Command):
1008
1020
    """List unknown files."""
1009
1021
    @display_command
1010
1022
    def run(self):
1011
1023
        from bzrlib.osutils import quotefn
1012
 
        for f in Branch.open_containing('.')[0].unknowns():
 
1024
        for f in WorkingTree.open_containing('.')[0].unknowns():
1013
1025
            print quotefn(f)
1014
1026
 
1015
1027
 
1016
 
 
1017
1028
class cmd_ignore(Command):
1018
1029
    """Ignore a command or pattern.
1019
1030
 
1039
1050
        from bzrlib.atomicfile import AtomicFile
1040
1051
        import os.path
1041
1052
 
1042
 
        b, relpath = Branch.open_containing('.')
1043
 
        ifn = b.abspath('.bzrignore')
 
1053
        tree, relpath = WorkingTree.open_containing('.')
 
1054
        ifn = tree.abspath('.bzrignore')
1044
1055
 
1045
1056
        if os.path.exists(ifn):
1046
1057
            f = open(ifn, 'rt')
1065
1076
        finally:
1066
1077
            f.close()
1067
1078
 
1068
 
        inv = b.working_tree().inventory
 
1079
        inv = tree.inventory
1069
1080
        if inv.path2id('.bzrignore'):
1070
1081
            mutter('.bzrignore is already versioned')
1071
1082
        else:
1072
1083
            mutter('need to make new .bzrignore file versioned')
1073
 
            b.add(['.bzrignore'])
1074
 
 
 
1084
            tree.add(['.bzrignore'])
1075
1085
 
1076
1086
 
1077
1087
class cmd_ignored(Command):
1080
1090
    See also: bzr ignore"""
1081
1091
    @display_command
1082
1092
    def run(self):
1083
 
        tree = Branch.open_containing('.')[0].working_tree()
 
1093
        tree = WorkingTree.open_containing('.')[0]
1084
1094
        for path, file_class, kind, file_id, entry in tree.list_files():
1085
1095
            if file_class != 'I':
1086
1096
                continue
1105
1115
        except ValueError:
1106
1116
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1107
1117
 
1108
 
        print Branch.open_containing('.')[0].get_rev_id(revno)
 
1118
        print WorkingTree.open_containing('.')[0].branch.get_rev_id(revno)
1109
1119
 
1110
1120
 
1111
1121
class cmd_export(Command):
1118
1128
    is found exports to a directory (equivalent to --format=dir).
1119
1129
 
1120
1130
    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
 
1131
    is given, the top directory will be the root name of the file.
 
1132
 
 
1133
    Note: export of tree with non-ascii filenames to zip is not supported.
 
1134
 
 
1135
    Supported formats       Autodetected by extension
 
1136
    -----------------       -------------------------
 
1137
         dir                            -
 
1138
         tar                          .tar
 
1139
         tbz2                    .tar.bz2, .tbz2
 
1140
         tgz                      .tar.gz, .tgz
 
1141
         zip                          .zip
 
1142
    """
1123
1143
    takes_args = ['dest']
1124
1144
    takes_options = ['revision', 'format', 'root']
1125
1145
    def run(self, dest, revision=None, format=None, root=None):
1126
1146
        import os.path
1127
 
        b = Branch.open_containing('.')[0]
 
1147
        from bzrlib.export import export
 
1148
        tree = WorkingTree.open_containing('.')[0]
 
1149
        b = tree.branch
1128
1150
        if revision is None:
 
1151
            # should be tree.last_revision  FIXME
1129
1152
            rev_id = b.last_revision()
1130
1153
        else:
1131
1154
            if len(revision) != 1:
1132
1155
                raise BzrError('bzr export --revision takes exactly 1 argument')
1133
1156
            rev_id = revision[0].in_history(b).rev_id
1134
1157
        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)
 
1158
        try:
 
1159
            export(t, dest, format, root)
 
1160
        except errors.NoSuchExportFormat, e:
 
1161
            raise BzrCommandError('Unsupported export format: %s' % e.format)
1153
1162
 
1154
1163
 
1155
1164
class cmd_cat(Command):
1164
1173
            raise BzrCommandError("bzr cat requires a revision number")
1165
1174
        elif len(revision) != 1:
1166
1175
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1167
 
        b, relpath = Branch.open_containing(filename)
 
1176
        tree = None
 
1177
        try:
 
1178
            tree, relpath = WorkingTree.open_containing(filename)
 
1179
            b = tree.branch
 
1180
        except NotBranchError:
 
1181
            pass
 
1182
        if tree is None:
 
1183
            b, relpath = Branch.open_containing(filename)
1168
1184
        b.print_file(relpath, revision[0].in_history(b).revno)
1169
1185
 
1170
1186
 
1220
1236
        from bzrlib.status import show_status
1221
1237
        from cStringIO import StringIO
1222
1238
 
1223
 
        b, selected_list = branch_files(selected_list)
 
1239
        tree, selected_list = tree_files(selected_list)
1224
1240
        if message is None and not file:
1225
1241
            catcher = StringIO()
1226
 
            show_status(b, specific_files=selected_list,
 
1242
            show_status(tree.branch, specific_files=selected_list,
1227
1243
                        to_file=catcher)
1228
1244
            message = edit_commit_message(catcher.getvalue())
1229
1245
 
1241
1257
                raise BzrCommandError("empty commit message specified")
1242
1258
            
1243
1259
        try:
1244
 
            b.working_tree().commit(message, specific_files=selected_list,
1245
 
                     allow_pointless=unchanged, strict=strict)
 
1260
            tree.commit(message, specific_files=selected_list,
 
1261
                        allow_pointless=unchanged, strict=strict)
1246
1262
        except PointlessCommit:
1247
1263
            # FIXME: This should really happen before the file is read in;
1248
1264
            # perhaps prepare the commit; get the message; then actually commit
1254
1270
        except StrictCommitFailed:
1255
1271
            raise BzrCommandError("Commit refused because there are unknown "
1256
1272
                                  "files in the working tree.")
1257
 
 
 
1273
        note('Committed revision %d.' % (tree.branch.revno(),))
 
1274
        
1258
1275
 
1259
1276
class cmd_check(Command):
1260
1277
    """Validate consistency of branch history.
1262
1279
    This command checks various invariants about the branch storage to
1263
1280
    detect data corruption or bzr bugs.
1264
1281
    """
1265
 
    takes_args = ['dir?']
 
1282
    takes_args = ['branch?']
1266
1283
    takes_options = ['verbose']
1267
1284
 
1268
 
    def run(self, dir='.', verbose=False):
 
1285
    def run(self, branch=None, verbose=False):
1269
1286
        from bzrlib.check import check
1270
 
        check(Branch.open_containing(dir)[0], verbose)
 
1287
        if branch is None:
 
1288
            tree = WorkingTree.open_containing()[0]
 
1289
            branch = tree.branch
 
1290
        else:
 
1291
            branch = Branch.open(branch)
 
1292
        check(branch, verbose)
1271
1293
 
1272
1294
 
1273
1295
class cmd_scan_cache(Command):
1313
1335
    @display_command
1314
1336
    def run(self, email=False):
1315
1337
        try:
1316
 
            b = bzrlib.branch.Branch.open_containing('.')[0]
 
1338
            b = WorkingTree.open_containing('.')[0].branch
1317
1339
            config = bzrlib.config.BranchConfig(b)
1318
1340
        except NotBranchError:
1319
1341
            config = bzrlib.config.GlobalConfig()
1364
1386
    def run(self, testspecs_list=None, verbose=False, one=False,
1365
1387
            keep_output=False):
1366
1388
        import bzrlib.ui
1367
 
        from bzrlib.selftest import selftest
 
1389
        from bzrlib.tests import selftest
1368
1390
        # we don't want progress meters from the tests to go to the
1369
1391
        # real output; and we don't want log messages cluttering up
1370
1392
        # the real logs.
1496
1518
        if merge_type is None:
1497
1519
            merge_type = ApplyMerge3
1498
1520
        if branch is None:
1499
 
            branch = Branch.open_containing('.')[0].get_parent()
 
1521
            branch = WorkingTree.open_containing('.')[0].branch.get_parent()
1500
1522
            if branch is None:
1501
1523
                raise BzrCommandError("No merge location known or specified.")
1502
1524
            else:
1552
1574
        from bzrlib.merge_core import ApplyMerge3
1553
1575
        if merge_type is None:
1554
1576
            merge_type = ApplyMerge3
1555
 
        b, file_list = branch_files(file_list)
1556
 
        b.lock_write()
 
1577
        tree, file_list = tree_files(file_list)
 
1578
        tree.lock_write()
1557
1579
        try:
1558
 
            pending_merges = b.working_tree().pending_merges() 
 
1580
            pending_merges = tree.pending_merges() 
1559
1581
            if len(pending_merges) != 1:
1560
1582
                raise BzrCommandError("Sorry, remerge only works after normal"
1561
1583
                                      + " merges.  Not cherrypicking or"
1562
1584
                                      + "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])
 
1585
            base_revision = common_ancestor(tree.branch.last_revision(), 
 
1586
                                            pending_merges[0], tree.branch)
 
1587
            base_tree = tree.branch.revision_tree(base_revision)
 
1588
            other_tree = tree.branch.revision_tree(pending_merges[0])
1568
1589
            interesting_ids = None
1569
1590
            if file_list is not None:
1570
1591
                interesting_ids = set()
1571
1592
                for filename in file_list:
1572
 
                    file_id = this_tree.path2id(filename)
 
1593
                    file_id = tree.path2id(filename)
1573
1594
                    interesting_ids.add(file_id)
1574
 
                    if this_tree.kind(file_id) != "directory":
 
1595
                    if tree.kind(file_id) != "directory":
1575
1596
                        continue
1576
1597
                    
1577
 
                    for name, ie in this_tree.inventory.iter_entries(file_id):
 
1598
                    for name, ie in tree.inventory.iter_entries(file_id):
1578
1599
                        interesting_ids.add(ie.file_id)
1579
 
            transform_tree(this_tree, b.basis_tree(), interesting_ids)
 
1600
            transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1580
1601
            if file_list is None:
1581
 
                restore_files = list(this_tree.iter_conflicts())
 
1602
                restore_files = list(tree.iter_conflicts())
1582
1603
            else:
1583
1604
                restore_files = file_list
1584
1605
            for filename in restore_files:
1585
1606
                try:
1586
 
                    restore(this_tree.abspath(filename))
 
1607
                    restore(tree.abspath(filename))
1587
1608
                except NotConflicted:
1588
1609
                    pass
1589
 
            conflicts =  merge_inner(b, other_tree, base_tree, 
 
1610
            conflicts =  merge_inner(tree.branch, other_tree, base_tree, 
1590
1611
                                     interesting_ids = interesting_ids, 
1591
1612
                                     other_rev_id=pending_merges[0], 
1592
1613
                                     merge_type=merge_type, 
1593
1614
                                     show_base=show_base,
1594
1615
                                     reprocess=reprocess)
1595
1616
        finally:
1596
 
            b.unlock()
 
1617
            tree.unlock()
1597
1618
        if conflicts > 0:
1598
1619
            return 1
1599
1620
        else:
1620
1641
            file_list = []
1621
1642
        if revision is None:
1622
1643
            revno = -1
1623
 
            b = Branch.open_containing('.')[0]
1624
 
            rev_id = b.last_revision()
 
1644
            tree = WorkingTree.open_containing('.')[0]
 
1645
            # FIXME should be tree.last_revision
 
1646
            rev_id = tree.branch.last_revision()
1625
1647
        elif len(revision) != 1:
1626
1648
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1627
1649
        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),
 
1650
            tree, file_list = tree_files(file_list)
 
1651
            rev_id = revision[0].in_history(tree.branch).rev_id
 
1652
        tree.revert(file_list, tree.branch.revision_tree(rev_id),
1631
1653
                                not no_backup)
1632
1654
 
1633
1655
 
1698
1720
    
1699
1721
    takes_args = ['remote?']
1700
1722
    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']
 
1723
    takes_options = ['verbose']
1704
1724
 
1705
1725
    @display_command
1706
 
    def run(self, remote=None, verbose=False, quiet=False):
 
1726
    def run(self, remote=None, verbose=False):
1707
1727
        from bzrlib.errors import BzrCommandError
1708
1728
        from bzrlib.missing import show_missing
1709
1729
 
1710
 
        if verbose and quiet:
 
1730
        if verbose and is_quiet():
1711
1731
            raise BzrCommandError('Cannot pass both quiet and verbose')
1712
1732
 
1713
 
        b = Branch.open_containing('.')[0]
1714
 
        parent = b.get_parent()
 
1733
        tree = WorkingTree.open_containing('.')[0]
 
1734
        parent = tree.branch.get_parent()
1715
1735
        if remote is None:
1716
1736
            if parent is None:
1717
1737
                raise BzrCommandError("No missing location known or specified.")
1718
1738
            else:
1719
 
                if not quiet:
 
1739
                if not is_quiet():
1720
1740
                    print "Using last location: %s" % parent
1721
1741
                remote = parent
1722
1742
        elif parent is None:
1723
1743
            # We only update parent if it did not exist, missing
1724
1744
            # should not change the parent
1725
 
            b.set_parent(remote)
 
1745
            tree.branch.set_parent(remote)
1726
1746
        br_remote = Branch.open_containing(remote)[0]
1727
 
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
 
1747
        return show_missing(tree.branch, br_remote, verbose=verbose, 
 
1748
                            quiet=is_quiet())
1728
1749
 
1729
1750
 
1730
1751
class cmd_plugins(Command):
1754
1775
    @display_command
1755
1776
    def run(self, branch='.', revision=None, long=False):
1756
1777
        from bzrlib.testament import Testament
1757
 
        b = Branch.open_containing(branch)[0]
 
1778
        b = WorkingTree.open_containing(branch)[0].branch
1758
1779
        b.lock_read()
1759
1780
        try:
1760
1781
            if revision is None:
1792
1813
    @display_command
1793
1814
    def run(self, filename, all=False, long=False):
1794
1815
        from bzrlib.annotate import annotate_file
1795
 
        b, relpath = Branch.open_containing(filename)
1796
 
        b.lock_read()
 
1816
        tree, relpath = WorkingTree.open_containing(filename)
 
1817
        branch = tree.branch
 
1818
        branch.lock_read()
1797
1819
        try:
1798
 
            tree = WorkingTree(b.base, b)
1799
 
            tree = b.revision_tree(b.last_revision())
1800
1820
            file_id = tree.inventory.path2id(relpath)
 
1821
            tree = branch.revision_tree(branch.last_revision())
1801
1822
            file_version = tree.inventory[file_id].revision
1802
 
            annotate_file(b, file_version, file_id, long, all, sys.stdout)
 
1823
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1803
1824
        finally:
1804
 
            b.unlock()
 
1825
            branch.unlock()
1805
1826
 
1806
1827
 
1807
1828
class cmd_re_sign(Command):
1819
1840
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1820
1841
        if revision_id is None and revision is None:
1821
1842
            raise BzrCommandError('You must supply either --revision or a revision_id')
1822
 
        b = Branch.open_containing('.')[0]
 
1843
        b = WorkingTree.open_containing('.')[0].branch
1823
1844
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1824
1845
        if revision_id is not None:
1825
1846
            b.sign_revision(revision_id, gpg_strategy)
1843
1864
                raise BzrCommandError('Please supply either one revision, or a range.')
1844
1865
 
1845
1866
 
 
1867
class cmd_uncommit(bzrlib.commands.Command):
 
1868
    """Remove the last committed revision.
 
1869
 
 
1870
    By supplying the --all flag, it will not only remove the entry 
 
1871
    from revision_history, but also remove all of the entries in the
 
1872
    stores.
 
1873
 
 
1874
    --verbose will print out what is being removed.
 
1875
    --dry-run will go through all the motions, but not actually
 
1876
    remove anything.
 
1877
    
 
1878
    In the future, uncommit will create a changeset, which can then
 
1879
    be re-applied.
 
1880
    """
 
1881
    takes_options = ['all', 'verbose', 'revision',
 
1882
                    Option('dry-run', help='Don\'t actually make changes'),
 
1883
                    Option('force', help='Say yes to all questions.')]
 
1884
    takes_args = ['location?']
 
1885
    aliases = []
 
1886
 
 
1887
    def run(self, location=None, all=False,
 
1888
            dry_run=False, verbose=False,
 
1889
            revision=None, force=False):
 
1890
        from bzrlib.branch import Branch
 
1891
        from bzrlib.log import log_formatter
 
1892
        import sys
 
1893
        from bzrlib.uncommit import uncommit
 
1894
 
 
1895
        if location is None:
 
1896
            location = '.'
 
1897
        b, relpath = Branch.open_containing(location)
 
1898
 
 
1899
        if revision is None:
 
1900
            revno = b.revno()
 
1901
            rev_id = b.last_revision()
 
1902
        else:
 
1903
            revno, rev_id = revision[0].in_history(b)
 
1904
        if rev_id is None:
 
1905
            print 'No revisions to uncommit.'
 
1906
 
 
1907
        for r in range(revno, b.revno()+1):
 
1908
            rev_id = b.get_rev_id(r)
 
1909
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
 
1910
            lf.show(r, b.get_revision(rev_id), None)
 
1911
 
 
1912
        if dry_run:
 
1913
            print 'Dry-run, pretending to remove the above revisions.'
 
1914
            if not force:
 
1915
                val = raw_input('Press <enter> to continue')
 
1916
        else:
 
1917
            print 'The above revision(s) will be removed.'
 
1918
            if not force:
 
1919
                val = raw_input('Are you sure [y/N]? ')
 
1920
                if val.lower() not in ('y', 'yes'):
 
1921
                    print 'Canceled'
 
1922
                    return 0
 
1923
 
 
1924
        uncommit(b, remove_files=all,
 
1925
                dry_run=dry_run, verbose=verbose,
 
1926
                revno=revno)
 
1927
 
 
1928
 
1846
1929
# these get imported and then picked up by the scan for cmd_*
1847
1930
# TODO: Some more consistent way to split command definitions across files;
1848
1931
# we do need to load at least some information about them to know of