~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2005-10-11 08:31:29 UTC
  • Revision ID: robertc@lifelesslap.robertcollins.net-20051011083129-fa720bc6cd6c039f
inline and simplify branch.find_branch_root, it should just try to create a branch at each step, which is simpler than probing for a specific dir and has less round trips.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
import bzrlib
22
22
import bzrlib.trace
23
23
from bzrlib.trace import mutter, note, log_error, warning
24
 
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
25
 
from bzrlib.branch import find_branch
 
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
 
25
from bzrlib.errors import DivergedBranches
 
26
from bzrlib.branch import Branch
26
27
from bzrlib import BZRDIR
27
28
from bzrlib.commands import Command
28
29
 
63
64
    files or directories is reported.  If a directory is given, status
64
65
    is reported for everything inside that directory.
65
66
 
66
 
    If a revision is specified, the changes since that revision are shown.
 
67
    If a revision argument is given, the status is calculated against
 
68
    that revision, or between two revisions if two are provided.
67
69
    """
 
70
    # XXX: FIXME: bzr status should accept a -r option to show changes
 
71
    # relative to a revision, or between revisions
 
72
 
68
73
    takes_args = ['file*']
69
 
    takes_options = ['all', 'show-ids', 'revision']
 
74
    takes_options = ['all', 'show-ids']
70
75
    aliases = ['st', 'stat']
71
76
    
72
 
    def run(self, all=False, show_ids=False, file_list=None):
 
77
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
73
78
        if file_list:
74
 
            b = find_branch(file_list[0])
 
79
            b = Branch.open_containing(file_list[0])
75
80
            file_list = [b.relpath(x) for x in file_list]
76
81
            # special case: only one path was given and it's the root
77
82
            # of the branch
78
83
            if file_list == ['']:
79
84
                file_list = None
80
85
        else:
81
 
            b = find_branch('.')
 
86
            b = Branch.open_containing('.')
82
87
            
83
88
        from bzrlib.status import show_status
84
89
        show_status(b, show_unchanged=all, show_ids=show_ids,
85
 
                    specific_files=file_list)
 
90
                    specific_files=file_list, revision=revision)
86
91
 
87
92
 
88
93
class cmd_cat_revision(Command):
89
 
    """Write out metadata for a revision."""
 
94
    """Write out metadata for a revision.
 
95
    
 
96
    The revision to print can either be specified by a specific
 
97
    revision identifier, or you can use --revision.
 
98
    """
90
99
 
91
100
    hidden = True
92
 
    takes_args = ['revision_id']
 
101
    takes_args = ['revision_id?']
 
102
    takes_options = ['revision']
93
103
    
94
 
    def run(self, revision_id):
95
 
        b = find_branch('.')
96
 
        sys.stdout.write(b.get_revision_xml_file(revision_id).read())
 
104
    def run(self, revision_id=None, revision=None):
 
105
        from bzrlib.revisionspec import RevisionSpec
97
106
 
 
107
        if revision_id is not None and revision is not None:
 
108
            raise BzrCommandError('You can only supply one of revision_id or --revision')
 
109
        if revision_id is None and revision is None:
 
110
            raise BzrCommandError('You must supply either --revision or a revision_id')
 
111
        b = Branch.open_containing('.')
 
112
        if revision_id is not None:
 
113
            sys.stdout.write(b.get_revision_xml_file(revision_id).read())
 
114
        elif revision is not None:
 
115
            for rev in revision:
 
116
                if rev is None:
 
117
                    raise BzrCommandError('You cannot specify a NULL revision.')
 
118
                revno, rev_id = rev.in_history(b)
 
119
                sys.stdout.write(b.get_revision_xml_file(rev_id).read())
 
120
    
98
121
 
99
122
class cmd_revno(Command):
100
123
    """Show current revision number.
101
124
 
102
125
    This is equal to the number of revisions on this branch."""
103
126
    def run(self):
104
 
        print find_branch('.').revno()
 
127
        print Branch.open_containing('.').revno()
105
128
 
106
129
 
107
130
class cmd_revision_info(Command):
110
133
    hidden = True
111
134
    takes_args = ['revision_info*']
112
135
    takes_options = ['revision']
113
 
    def run(self, revision=None, revision_info_list=None):
114
 
        from bzrlib.branch import find_branch
 
136
    def run(self, revision=None, revision_info_list=[]):
 
137
        from bzrlib.revisionspec import RevisionSpec
115
138
 
116
139
        revs = []
117
140
        if revision is not None:
118
141
            revs.extend(revision)
119
142
        if revision_info_list is not None:
120
 
            revs.extend(revision_info_list)
 
143
            for rev in revision_info_list:
 
144
                revs.append(RevisionSpec(rev))
121
145
        if len(revs) == 0:
122
146
            raise BzrCommandError('You must supply a revision identifier')
123
147
 
124
 
        b = find_branch('.')
 
148
        b = Branch.open_containing('.')
125
149
 
126
150
        for rev in revs:
127
 
            print '%4d %s' % b.get_revision_info(rev)
 
151
            revinfo = rev.in_history(b)
 
152
            if revinfo.revno is None:
 
153
                print '     %s' % revinfo.rev_id
 
154
            else:
 
155
                print '%4d %s' % (revinfo.revno, revinfo.rev_id)
128
156
 
129
157
    
130
158
class cmd_add(Command):
145
173
    Therefore simply saying 'bzr add' will version all files that
146
174
    are currently unknown.
147
175
 
148
 
    TODO: Perhaps adding a file whose directly is not versioned should
149
 
    recursively add that parent, rather than giving an error?
 
176
    Adding a file whose parent directory is not versioned will
 
177
    implicitly add the parent, and so on up to the root. This means
 
178
    you should never need to explictly add a directory, they'll just
 
179
    get added when you add a file in the directory.
150
180
    """
151
181
    takes_args = ['file*']
152
182
    takes_options = ['verbose', 'no-recurse']
171
201
        for d in dir_list:
172
202
            os.mkdir(d)
173
203
            if not b:
174
 
                b = find_branch(d)
 
204
                b = Branch.open_containing(d)
175
205
            b.add([d])
176
206
            print 'added', d
177
207
 
182
212
    hidden = True
183
213
    
184
214
    def run(self, filename):
185
 
        print find_branch(filename).relpath(filename)
 
215
        print Branch.open_containing(filename).relpath(filename)
186
216
 
187
217
 
188
218
 
191
221
    takes_options = ['revision', 'show-ids']
192
222
    
193
223
    def run(self, revision=None, show_ids=False):
194
 
        b = find_branch('.')
195
 
        if revision == None:
 
224
        b = Branch.open_containing('.')
 
225
        if revision is None:
196
226
            inv = b.read_working_inventory()
197
227
        else:
198
228
            if len(revision) > 1:
199
229
                raise BzrCommandError('bzr inventory --revision takes'
200
230
                    ' exactly one revision identifier')
201
 
            inv = b.get_revision_inventory(b.lookup_revision(revision[0]))
 
231
            inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
202
232
 
203
233
        for path, entry in inv.entries():
204
234
            if show_ids:
217
247
    """
218
248
    takes_args = ['source$', 'dest']
219
249
    def run(self, source_list, dest):
220
 
        b = find_branch('.')
 
250
        b = Branch.open_containing('.')
221
251
 
222
252
        # TODO: glob expansion on windows?
223
253
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
240
270
    takes_args = ['from_name', 'to_name']
241
271
    
242
272
    def run(self, from_name, to_name):
243
 
        b = find_branch('.')
 
273
        b = Branch.open_containing('.')
244
274
        b.rename_one(b.relpath(from_name), b.relpath(to_name))
245
275
 
246
276
 
262
292
    def run(self, names_list):
263
293
        if len(names_list) < 2:
264
294
            raise BzrCommandError("missing file argument")
265
 
        b = find_branch(names_list[0])
 
295
        b = Branch.open_containing(names_list[0])
266
296
 
267
297
        rel_names = [b.relpath(x) for x in names_list]
268
298
        
274
304
            if len(names_list) != 2:
275
305
                raise BzrCommandError('to mv multiple files the destination '
276
306
                                      'must be a versioned directory')
277
 
            for pair in b.move(rel_names[0], rel_names[1]):
278
 
                print "%s => %s" % pair
 
307
            b.rename_one(rel_names[0], rel_names[1])
 
308
            print "%s => %s" % (rel_names[0], rel_names[1])
279
309
            
280
310
    
281
311
 
294
324
    If branches have diverged, you can use 'bzr merge' to pull the text changes
295
325
    from one into the other.
296
326
    """
 
327
    takes_options = ['remember']
297
328
    takes_args = ['location?']
298
329
 
299
 
    def run(self, location=None):
 
330
    def run(self, location=None, remember=False):
300
331
        from bzrlib.merge import merge
301
332
        import tempfile
302
333
        from shutil import rmtree
303
334
        import errno
304
 
        from bzrlib.branch import pull_loc
305
335
        
306
 
        br_to = find_branch('.')
307
 
        stored_loc = None
308
 
        try:
309
 
            stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
310
 
        except IOError, e:
311
 
            if e.errno != errno.ENOENT:
312
 
                raise
 
336
        br_to = Branch.open_containing('.')
 
337
        stored_loc = br_to.get_parent()
313
338
        if location is None:
314
339
            if stored_loc is None:
315
340
                raise BzrCommandError("No pull location known or specified.")
316
341
            else:
317
 
                print "Using last location: %s" % stored_loc
 
342
                print "Using saved location: %s" % stored_loc
318
343
                location = stored_loc
319
344
        cache_root = tempfile.mkdtemp()
320
 
        from bzrlib.branch import DivergedBranches
321
 
        br_from = find_branch(location)
322
 
        location = pull_loc(br_from)
323
 
        old_revno = br_to.revno()
 
345
        br_from = Branch.open(location)
 
346
        br_from.lock_read()
324
347
        try:
325
 
            from branch import find_cached_branch, DivergedBranches
326
 
            br_from = find_cached_branch(location, cache_root)
327
 
            location = pull_loc(br_from)
 
348
            br_from.setup_caching(cache_root)
 
349
            location = br_from.base
328
350
            old_revno = br_to.revno()
 
351
            old_revision_history = br_to.revision_history()
329
352
            try:
330
353
                br_to.update_revisions(br_from)
331
354
            except DivergedBranches:
332
355
                raise BzrCommandError("These branches have diverged."
333
356
                    "  Try merge.")
334
 
                
335
 
            merge(('.', -1), ('.', old_revno), check_clean=False)
336
 
            if location != stored_loc:
337
 
                br_to.controlfile("x-pull", "wb").write(location + "\n")
 
357
            new_revision_history = br_to.revision_history()
 
358
            if new_revision_history != old_revision_history:
 
359
                merge(('.', -1), ('.', old_revno), check_clean=False)
 
360
            if stored_loc is None or remember:
 
361
                br_to.set_parent(location)
338
362
        finally:
 
363
            br_from.unlock()
339
364
            rmtree(cache_root)
340
365
 
341
366
 
348
373
 
349
374
    To retrieve the branch as of a particular revision, supply the --revision
350
375
    parameter, as in "branch foo/bar -r 5".
 
376
 
 
377
    --basis is to speed up branching from remote branches.  When specified, it
 
378
    copies all the file-contents, inventory and revision data from the basis
 
379
    branch before copying anything from the remote branch.
351
380
    """
352
381
    takes_args = ['from_location', 'to_location?']
353
 
    takes_options = ['revision']
 
382
    takes_options = ['revision', 'basis']
354
383
    aliases = ['get', 'clone']
355
384
 
356
 
    def run(self, from_location, to_location=None, revision=None):
357
 
        from bzrlib.branch import copy_branch, find_cached_branch
 
385
    def run(self, from_location, to_location=None, revision=None, basis=None):
 
386
        from bzrlib.clone import copy_branch
358
387
        import tempfile
359
388
        import errno
360
389
        from shutil import rmtree
366
395
                raise BzrCommandError(
367
396
                    'bzr branch --revision takes exactly 1 revision value')
368
397
            try:
369
 
                br_from = find_cached_branch(from_location, cache_root)
 
398
                br_from = Branch.open(from_location)
370
399
            except OSError, e:
371
400
                if e.errno == errno.ENOENT:
372
401
                    raise BzrCommandError('Source location "%s" does not'
373
402
                                          ' exist.' % to_location)
374
403
                else:
375
404
                    raise
 
405
            br_from.setup_caching(cache_root)
 
406
            if basis is not None:
 
407
                basis_branch = Branch.open_containing(basis)
 
408
            else:
 
409
                basis_branch = None
 
410
            if len(revision) == 1 and revision[0] is not None:
 
411
                revision_id = revision[0].in_history(br_from)[1]
 
412
            else:
 
413
                revision_id = None
376
414
            if to_location is None:
377
415
                to_location = os.path.basename(from_location.rstrip("/\\"))
378
416
            try:
387
425
                else:
388
426
                    raise
389
427
            try:
390
 
                copy_branch(br_from, to_location, revision[0])
 
428
                copy_branch(br_from, to_location, revision_id, basis_branch)
391
429
            except bzrlib.errors.NoSuchRevision:
392
430
                rmtree(to_location)
393
431
                msg = "The branch %s has no revision %d." % (from_location, revision[0])
394
432
                raise BzrCommandError(msg)
 
433
            except bzrlib.errors.UnlistableBranch:
 
434
                msg = "The branch %s cannot be used as a --basis"
395
435
        finally:
396
436
            rmtree(cache_root)
397
437
 
406
446
    takes_args = ['dir?']
407
447
 
408
448
    def run(self, dir='.'):
409
 
        b = find_branch(dir)
 
449
        b = Branch.open_containing(dir)
410
450
        old_inv = b.basis_tree().inventory
411
451
        new_inv = b.read_working_inventory()
412
452
 
422
462
    
423
463
    def run(self, branch=None):
424
464
        import info
425
 
 
426
 
        b = find_branch(branch)
 
465
        b = Branch.open_containing(branch)
427
466
        info.show_info(b)
428
467
 
429
468
 
435
474
    """
436
475
    takes_args = ['file+']
437
476
    takes_options = ['verbose']
 
477
    aliases = ['rm']
438
478
    
439
479
    def run(self, file_list, verbose=False):
440
 
        b = find_branch(file_list[0])
 
480
        b = Branch.open_containing(file_list[0])
441
481
        b.remove([b.relpath(f) for f in file_list], verbose=verbose)
442
482
 
443
483
 
451
491
    hidden = True
452
492
    takes_args = ['filename']
453
493
    def run(self, filename):
454
 
        b = find_branch(filename)
 
494
        b = Branch.open_containing(filename)
455
495
        i = b.inventory.path2id(b.relpath(filename))
456
496
        if i == None:
457
497
            raise BzrError("%r is not a versioned file" % filename)
467
507
    hidden = True
468
508
    takes_args = ['filename']
469
509
    def run(self, filename):
470
 
        b = find_branch(filename)
 
510
        b = Branch.open_containing(filename)
471
511
        inv = b.inventory
472
512
        fid = inv.path2id(b.relpath(filename))
473
513
        if fid == None:
480
520
    """Display list of revision ids on this branch."""
481
521
    hidden = True
482
522
    def run(self):
483
 
        for patchid in find_branch('.').revision_history():
 
523
        for patchid in Branch.open_containing('.').revision_history():
484
524
            print patchid
485
525
 
486
526
 
 
527
class cmd_ancestry(Command):
 
528
    """List all revisions merged into this branch."""
 
529
    hidden = True
 
530
    def run(self):
 
531
        b = find_branch('.')
 
532
        for revision_id in b.get_ancestry(b.last_revision()):
 
533
            print revision_id
 
534
 
 
535
 
487
536
class cmd_directories(Command):
488
537
    """Display list of versioned directories in this branch."""
489
538
    def run(self):
490
 
        for name, ie in find_branch('.').read_working_inventory().directories():
 
539
        for name, ie in Branch.open_containing('.').read_working_inventory().directories():
491
540
            if name == '':
492
541
                print '.'
493
542
            else:
508
557
        bzr commit -m 'imported project'
509
558
    """
510
559
    def run(self):
511
 
        from bzrlib.branch import Branch
512
 
        Branch('.', init=True)
 
560
        Branch.initialize('.')
513
561
 
514
562
 
515
563
class cmd_diff(Command):
536
584
    examples:
537
585
        bzr diff
538
586
        bzr diff -r1
539
 
        bzr diff -r1:2
 
587
        bzr diff -r1..2
540
588
    """
541
589
    
542
590
    takes_args = ['file*']
547
595
        from bzrlib.diff import show_diff
548
596
 
549
597
        if file_list:
550
 
            b = find_branch(file_list[0])
 
598
            b = Branch.open_containing(file_list[0])
551
599
            file_list = [b.relpath(f) for f in file_list]
552
600
            if file_list == ['']:
553
601
                # just pointing to top-of-tree
554
602
                file_list = None
555
603
        else:
556
 
            b = find_branch('.')
 
604
            b = Branch.open_containing('.')
557
605
 
558
606
        if revision is not None:
559
607
            if len(revision) == 1:
578
626
    TODO: Show files deleted since a previous revision, or between two revisions.
579
627
    """
580
628
    def run(self, show_ids=False):
581
 
        b = find_branch('.')
 
629
        b = Branch.open_containing('.')
582
630
        old = b.basis_tree()
583
631
        new = b.working_tree()
584
632
 
601
649
    def run(self):
602
650
        from bzrlib.delta import compare_trees
603
651
 
604
 
        b = find_branch('.')
 
652
        b = Branch.open_containing('.')
605
653
        td = compare_trees(b.basis_tree(), b.working_tree())
606
654
 
607
 
        for path, id, kind in td.modified:
 
655
        for path, id, kind, text_modified, meta_modified in td.modified:
608
656
            print path
609
657
 
610
658
 
613
661
    """List files added in working tree."""
614
662
    hidden = True
615
663
    def run(self):
616
 
        b = find_branch('.')
 
664
        b = Branch.open_containing('.')
617
665
        wt = b.working_tree()
618
666
        basis_inv = b.basis_tree().inventory
619
667
        inv = wt.inventory
635
683
    takes_args = ['filename?']
636
684
    def run(self, filename=None):
637
685
        """Print the branch root."""
638
 
        b = find_branch(filename)
639
 
        print getattr(b, 'base', None) or getattr(b, 'baseurl')
 
686
        b = Branch.open_containing(filename)
 
687
        print b.base
640
688
 
641
689
 
642
690
class cmd_log(Command):
648
696
 
649
697
    --message allows you to give a regular expression, which will be evaluated
650
698
    so that only matching entries will be displayed.
651
 
 
652
 
    TODO: Make --revision support uuid: and hash: [future tag:] notation.
653
 
  
654
699
    """
655
700
 
 
701
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
 
702
 
656
703
    takes_args = ['filename?']
657
704
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
658
705
                     'long', 'message', 'short',]
671
718
        direction = (forward and 'forward') or 'reverse'
672
719
        
673
720
        if filename:
674
 
            b = find_branch(filename)
 
721
            b = Branch.open_containing(filename)
675
722
            fp = b.relpath(filename)
676
723
            if fp:
677
724
                file_id = b.read_working_inventory().path2id(fp)
678
725
            else:
679
726
                file_id = None  # points to branch root
680
727
        else:
681
 
            b = find_branch('.')
 
728
            b = Branch.open_containing('.')
682
729
            file_id = None
683
730
 
684
731
        if revision is None:
685
732
            rev1 = None
686
733
            rev2 = None
687
734
        elif len(revision) == 1:
688
 
            rev1 = rev2 = b.get_revision_info(revision[0])[0]
 
735
            rev1 = rev2 = revision[0].in_history(b).revno
689
736
        elif len(revision) == 2:
690
 
            rev1 = b.get_revision_info(revision[0])[0]
691
 
            rev2 = b.get_revision_info(revision[1])[0]
 
737
            rev1 = revision[0].in_history(b).revno
 
738
            rev2 = revision[1].in_history(b).revno
692
739
        else:
693
740
            raise BzrCommandError('bzr log --revision takes one or two values.')
694
741
 
730
777
    hidden = True
731
778
    takes_args = ["filename"]
732
779
    def run(self, filename):
733
 
        b = find_branch(filename)
 
780
        b = Branch.open_containing(filename)
734
781
        inv = b.read_working_inventory()
735
782
        file_id = inv.path2id(b.relpath(filename))
736
783
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
744
791
    """
745
792
    hidden = True
746
793
    def run(self, revision=None, verbose=False):
747
 
        b = find_branch('.')
 
794
        b = Branch.open_containing('.')
748
795
        if revision == None:
749
796
            tree = b.working_tree()
750
797
        else:
751
 
            tree = b.revision_tree(b.lookup_revision(revision))
752
 
 
753
 
        for fp, fc, kind, fid in tree.list_files():
 
798
            tree = b.revision_tree(revision.in_history(b).rev_id)
 
799
        for fp, fc, kind, fid, entry in tree.list_files():
754
800
            if verbose:
755
 
                if kind == 'directory':
756
 
                    kindch = '/'
757
 
                elif kind == 'file':
758
 
                    kindch = ''
759
 
                else:
760
 
                    kindch = '???'
761
 
 
 
801
                kindch = entry.kind_character()
762
802
                print '%-8s %s%s' % (fc, fp, kindch)
763
803
            else:
764
804
                print fp
769
809
    """List unknown files."""
770
810
    def run(self):
771
811
        from bzrlib.osutils import quotefn
772
 
        for f in find_branch('.').unknowns():
 
812
        for f in Branch.open_containing('.').unknowns():
773
813
            print quotefn(f)
774
814
 
775
815
 
797
837
        from bzrlib.atomicfile import AtomicFile
798
838
        import os.path
799
839
 
800
 
        b = find_branch('.')
 
840
        b = Branch.open_containing('.')
801
841
        ifn = b.abspath('.bzrignore')
802
842
 
803
843
        if os.path.exists(ifn):
837
877
 
838
878
    See also: bzr ignore"""
839
879
    def run(self):
840
 
        tree = find_branch('.').working_tree()
841
 
        for path, file_class, kind, file_id in tree.list_files():
 
880
        tree = Branch.open_containing('.').working_tree()
 
881
        for path, file_class, kind, file_id, entry in tree.list_files():
842
882
            if file_class != 'I':
843
883
                continue
844
884
            ## XXX: Slightly inefficient since this was already calculated
861
901
        except ValueError:
862
902
            raise BzrCommandError("not a valid revision-number: %r" % revno)
863
903
 
864
 
        print find_branch('.').lookup_revision(revno)
 
904
        print Branch.open_containing('.').get_rev_id(revno)
865
905
 
866
906
 
867
907
class cmd_export(Command):
880
920
    takes_options = ['revision', 'format', 'root']
881
921
    def run(self, dest, revision=None, format=None, root=None):
882
922
        import os.path
883
 
        b = find_branch('.')
 
923
        b = Branch.open_containing('.')
884
924
        if revision is None:
885
 
            rev_id = b.last_patch()
 
925
            rev_id = b.last_revision()
886
926
        else:
887
927
            if len(revision) != 1:
888
928
                raise BzrError('bzr export --revision takes exactly 1 argument')
889
 
            revno, rev_id = b.get_revision_info(revision[0])
 
929
            rev_id = revision[0].in_history(b).rev_id
890
930
        t = b.revision_tree(rev_id)
891
 
        root, ext = os.path.splitext(dest)
 
931
        arg_root, ext = os.path.splitext(os.path.basename(dest))
 
932
        if ext in ('.gz', '.bz2'):
 
933
            new_root, new_ext = os.path.splitext(arg_root)
 
934
            if new_ext == '.tar':
 
935
                arg_root = new_root
 
936
                ext = new_ext + ext
 
937
        if root is None:
 
938
            root = arg_root
892
939
        if not format:
893
940
            if ext in (".tar",):
894
941
                format = "tar"
895
 
            elif ext in (".gz", ".tgz"):
 
942
            elif ext in (".tar.gz", ".tgz"):
896
943
                format = "tgz"
897
 
            elif ext in (".bz2", ".tbz2"):
 
944
            elif ext in (".tar.bz2", ".tbz2"):
898
945
                format = "tbz2"
899
946
            else:
900
947
                format = "dir"
908
955
    takes_args = ['filename']
909
956
 
910
957
    def run(self, filename, revision=None):
911
 
        if revision == None:
 
958
        if revision is None:
912
959
            raise BzrCommandError("bzr cat requires a revision number")
913
960
        elif len(revision) != 1:
914
961
            raise BzrCommandError("bzr cat --revision takes exactly one number")
915
 
        b = find_branch('.')
916
 
        b.print_file(b.relpath(filename), revision[0])
 
962
        b = Branch.open_containing('.')
 
963
        b.print_file(b.relpath(filename), revision[0].in_history(b).revno)
917
964
 
918
965
 
919
966
class cmd_local_time_offset(Command):
951
998
    
952
999
    def run(self, message=None, file=None, verbose=True, selected_list=None,
953
1000
            unchanged=False):
954
 
        from bzrlib.errors import PointlessCommit
 
1001
        from bzrlib.errors import PointlessCommit, ConflictsInTree
955
1002
        from bzrlib.msgeditor import edit_commit_message
956
1003
        from bzrlib.status import show_status
957
1004
        from cStringIO import StringIO
958
1005
 
959
 
        b = find_branch('.')
 
1006
        b = Branch.open_containing('.')
960
1007
        if selected_list:
961
1008
            selected_list = [b.relpath(s) for s in selected_list]
 
1009
 
962
1010
            
963
 
        if not message and not file:
 
1011
        if message is None and not file:
964
1012
            catcher = StringIO()
965
1013
            show_status(b, specific_files=selected_list,
966
1014
                        to_file=catcher)
967
1015
            message = edit_commit_message(catcher.getvalue())
968
 
            
 
1016
 
969
1017
            if message is None:
970
1018
                raise BzrCommandError("please specify a commit message"
971
1019
                                      " with either --message or --file")
976
1024
            import codecs
977
1025
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
978
1026
 
 
1027
        if message == "":
 
1028
                raise BzrCommandError("empty commit message specified")
 
1029
            
979
1030
        try:
980
1031
            b.commit(message,
981
1032
                     specific_files=selected_list,
985
1036
            # perhaps prepare the commit; get the message; then actually commit
986
1037
            raise BzrCommandError("no changes to commit",
987
1038
                                  ["use --unchanged to commit anyhow"])
 
1039
        except ConflictsInTree:
 
1040
            raise BzrCommandError("Conflicts detected in working tree.  "
 
1041
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
988
1042
 
989
1043
 
990
1044
class cmd_check(Command):
992
1046
 
993
1047
    This command checks various invariants about the branch storage to
994
1048
    detect data corruption or bzr bugs.
995
 
 
996
 
    If given the --update flag, it will update some optional fields
997
 
    to help ensure data consistency.
998
1049
    """
999
1050
    takes_args = ['dir?']
1000
1051
 
1001
1052
    def run(self, dir='.'):
1002
1053
        from bzrlib.check import check
1003
1054
 
1004
 
        check(find_branch(dir))
 
1055
        check(Branch.open_containing(dir))
1005
1056
 
1006
1057
 
1007
1058
class cmd_scan_cache(Command):
1029
1080
 
1030
1081
    The check command or bzr developers may sometimes advise you to run
1031
1082
    this command.
 
1083
 
 
1084
    This version of this command upgrades from the full-text storage
 
1085
    used by bzr 0.0.8 and earlier to the weave format (v5).
1032
1086
    """
1033
1087
    takes_args = ['dir?']
1034
1088
 
1035
1089
    def run(self, dir='.'):
1036
1090
        from bzrlib.upgrade import upgrade
1037
 
        upgrade(find_branch(dir))
1038
 
 
 
1091
        upgrade(dir)
1039
1092
 
1040
1093
 
1041
1094
class cmd_whoami(Command):
1044
1097
    
1045
1098
    def run(self, email=False):
1046
1099
        try:
1047
 
            b = bzrlib.branch.find_branch('.')
1048
 
        except:
 
1100
            b = bzrlib.branch.Branch.open_containing('.')
 
1101
        except NotBranchError:
1049
1102
            b = None
1050
1103
        
1051
1104
        if email:
1052
 
            print bzrlib.osutils.user_email(b)
 
1105
            print bzrlib.config.user_email(b)
1053
1106
        else:
1054
 
            print bzrlib.osutils.username(b)
 
1107
            print bzrlib.config.username(b)
1055
1108
 
1056
1109
 
1057
1110
class cmd_selftest(Command):
1058
 
    """Run internal test suite"""
 
1111
    """Run internal test suite.
 
1112
    
 
1113
    This creates temporary test directories in the working directory,
 
1114
    but not existing data is affected.  These directories are deleted
 
1115
    if the tests pass, or left behind to help in debugging if they
 
1116
    fail.
 
1117
    
 
1118
    If arguments are given, they are regular expressions that say
 
1119
    which tests should run."""
 
1120
    # TODO: --list should give a list of all available tests
1059
1121
    hidden = True
1060
 
    takes_options = ['verbose', 'pattern']
1061
 
    def run(self, verbose=False, pattern=".*"):
 
1122
    takes_args = ['testspecs*']
 
1123
    takes_options = ['verbose']
 
1124
    def run(self, testspecs_list=None, verbose=False):
1062
1125
        import bzrlib.ui
1063
1126
        from bzrlib.selftest import selftest
1064
1127
        # we don't want progress meters from the tests to go to the
1068
1131
        bzrlib.trace.info('running tests...')
1069
1132
        try:
1070
1133
            bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1071
 
            result = selftest(verbose=verbose, pattern=pattern)
 
1134
            if testspecs_list is not None:
 
1135
                pattern = '|'.join(testspecs_list)
 
1136
            else:
 
1137
                pattern = ".*"
 
1138
            result = selftest(verbose=verbose, 
 
1139
                              pattern=pattern)
1072
1140
            if result:
1073
1141
                bzrlib.trace.info('tests passed')
1074
1142
            else:
1116
1184
    def run(self, branch, other):
1117
1185
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
1118
1186
        
1119
 
        branch1 = find_branch(branch)
1120
 
        branch2 = find_branch(other)
 
1187
        branch1 = Branch.open_containing(branch)
 
1188
        branch2 = Branch.open_containing(other)
1121
1189
 
1122
1190
        history_1 = branch1.revision_history()
1123
1191
        history_2 = branch2.revision_history()
1124
1192
 
1125
 
        last1 = branch1.last_patch()
1126
 
        last2 = branch2.last_patch()
 
1193
        last1 = branch1.last_revision()
 
1194
        last2 = branch2.last_revision()
1127
1195
 
1128
1196
        source = MultipleRevisionSources(branch1, branch2)
1129
1197
        
1174
1242
    takes_args = ['branch?']
1175
1243
    takes_options = ['revision', 'force', 'merge-type']
1176
1244
 
1177
 
    def run(self, branch='.', revision=None, force=False, 
 
1245
    def run(self, branch=None, revision=None, force=False, 
1178
1246
            merge_type=None):
1179
1247
        from bzrlib.merge import merge
1180
1248
        from bzrlib.merge_core import ApplyMerge3
1181
1249
        if merge_type is None:
1182
1250
            merge_type = ApplyMerge3
1183
 
 
 
1251
        if branch is None:
 
1252
            branch = Branch.open_containing('.').get_parent()
 
1253
            if branch is None:
 
1254
                raise BzrCommandError("No merge location known or specified.")
 
1255
            else:
 
1256
                print "Using saved location: %s" % branch 
1184
1257
        if revision is None or len(revision) < 1:
1185
1258
            base = [None, None]
1186
1259
            other = [branch, -1]
1187
1260
        else:
1188
1261
            if len(revision) == 1:
1189
 
                other = [branch, revision[0]]
1190
1262
                base = [None, None]
 
1263
                other = [branch, revision[0].in_history(branch).revno]
1191
1264
            else:
1192
1265
                assert len(revision) == 2
1193
1266
                if None in revision:
1194
1267
                    raise BzrCommandError(
1195
1268
                        "Merge doesn't permit that revision specifier.")
1196
 
                base = [branch, revision[0]]
1197
 
                other = [branch, revision[1]]
 
1269
                b = Branch.open(branch)
 
1270
 
 
1271
                base = [branch, revision[0].in_history(b).revno]
 
1272
                other = [branch, revision[1].in_history(b).revno]
1198
1273
 
1199
1274
        try:
1200
1275
            merge(other, base, check_clean=(not force), merge_type=merge_type)
1221
1296
 
1222
1297
    def run(self, revision=None, no_backup=False, file_list=None):
1223
1298
        from bzrlib.merge import merge
1224
 
        from bzrlib.branch import Branch
1225
1299
        from bzrlib.commands import parse_spec
1226
1300
 
1227
1301
        if file_list is not None:
1228
1302
            if len(file_list) == 0:
1229
1303
                raise BzrCommandError("No files specified")
1230
1304
        if revision is None:
1231
 
            revision = [-1]
 
1305
            revno = -1
1232
1306
        elif len(revision) != 1:
1233
1307
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1234
 
        merge(('.', revision[0]), parse_spec('.'),
 
1308
        else:
 
1309
            b = Branch.open_containing('.')
 
1310
            revno = revision[0].in_history(b).revno
 
1311
        merge(('.', revno), parse_spec('.'),
1235
1312
              check_clean=False,
1236
1313
              ignore_zero=True,
1237
1314
              backup_files=not no_backup,
1238
1315
              file_list=file_list)
1239
1316
        if not file_list:
1240
 
            Branch('.').set_pending_merges([])
 
1317
            Branch.open_containing('.').set_pending_merges([])
1241
1318
 
1242
1319
 
1243
1320
class cmd_assert_fail(Command):
1275
1352
        shellcomplete.shellcomplete(context)
1276
1353
 
1277
1354
 
 
1355
class cmd_fetch(Command):
 
1356
    """Copy in history from another branch but don't merge it.
 
1357
 
 
1358
    This is an internal method used for pull and merge."""
 
1359
    hidden = True
 
1360
    takes_args = ['from_branch', 'to_branch']
 
1361
    def run(self, from_branch, to_branch):
 
1362
        from bzrlib.fetch import Fetcher
 
1363
        from bzrlib.branch import Branch
 
1364
        from_b = Branch(from_branch)
 
1365
        to_b = Branch(to_branch)
 
1366
        Fetcher(to_b, from_b)
 
1367
        
 
1368
 
 
1369
 
1278
1370
class cmd_missing(Command):
1279
1371
    """What is missing in this branch relative to other branch.
1280
1372
    """
 
1373
    # TODO: rewrite this in terms of ancestry so that it shows only
 
1374
    # unmerged things
 
1375
    
1281
1376
    takes_args = ['remote?']
1282
1377
    aliases = ['mis', 'miss']
1283
1378
    # We don't have to add quiet to the list, because 
1291
1386
        if verbose and quiet:
1292
1387
            raise BzrCommandError('Cannot pass both quiet and verbose')
1293
1388
 
1294
 
        b = find_branch('.')
 
1389
        b = Branch.open_containing('.')
1295
1390
        parent = b.get_parent()
1296
1391
        if remote is None:
1297
1392
            if parent is None:
1301
1396
                    print "Using last location: %s" % parent
1302
1397
                remote = parent
1303
1398
        elif parent is None:
1304
 
            # We only update x-pull if it did not exist, missing should not change the parent
1305
 
            b.controlfile('x-pull', 'wb').write(remote + '\n')
1306
 
        br_remote = find_branch(remote)
1307
 
 
 
1399
            # We only update parent if it did not exist, missing
 
1400
            # should not change the parent
 
1401
            b.set_parent(remote)
 
1402
        br_remote = Branch.open_containing(remote)
1308
1403
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1309
1404
 
1310
1405
 
1311
 
 
1312
1406
class cmd_plugins(Command):
1313
1407
    """List plugins"""
1314
1408
    hidden = True