~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2005-10-17 11:56:54 UTC
  • mfrom: (1185.16.59)
  • Revision ID: robertc@robertcollins.net-20051017115654-662239e1587524a8
mergeĀ fromĀ martin.

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
 
# DO NOT change this to cStringIO - it results in control files 
18
 
# written as UCS4
19
 
# FIXIT! (Only deal with byte streams OR unicode at any one layer.)
20
 
# RBC 20051018
21
 
from StringIO import StringIO
 
17
 
22
18
import sys
23
19
import os
24
20
 
25
21
import bzrlib
26
22
from bzrlib import BZRDIR
27
 
from bzrlib.commands import Command, display_command
 
23
from bzrlib.commands import Command
28
24
from bzrlib.branch import Branch
29
25
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
30
26
from bzrlib.errors import DivergedBranches
35
31
from bzrlib.workingtree import WorkingTree
36
32
 
37
33
 
38
 
def branch_files(file_list, default_branch='.'):
39
 
    """\
40
 
    Return a branch and list of branch-relative paths.
41
 
    If supplied file_list is empty or None, the branch default will be used,
42
 
    and returned file_list will match the original.
43
 
    """
44
 
    if file_list is None or len(file_list) == 0:
45
 
        return Branch.open_containing(default_branch)[0], file_list
46
 
    b = Branch.open_containing(file_list[0])[0]
47
 
    
48
 
    # note that if this is a remote branch, we would want
49
 
    # relpath against the transport. RBC 20051018
50
 
    # Most branch ops can't meaningfully operate on files in remote branches;
51
 
    # the above comment was in cmd_status.  ADHB 20051026
52
 
    tree = WorkingTree(b.base, b)
53
 
    new_list = []
54
 
    for filename in file_list:
55
 
        try:
56
 
            new_list.append(tree.relpath(filename))
57
 
        except NotBranchError:
58
 
            raise BzrCommandError("%s is not in the same branch as %s" % 
59
 
                                  (filename, file_list[0]))
60
 
    return b, new_list
61
 
 
62
 
 
63
 
# TODO: Make sure no commands unconditionally use the working directory as a
64
 
# branch.  If a filename argument is used, the first of them should be used to
65
 
# specify the branch.  (Perhaps this can be factored out into some kind of
66
 
# Argument class, representing a file in a branch, where the first occurrence
67
 
# opens the branch?)
68
 
 
69
34
class cmd_status(Command):
70
35
    """Display status summary.
71
36
 
105
70
    If a revision argument is given, the status is calculated against
106
71
    that revision, or between two revisions if two are provided.
107
72
    """
108
 
    
109
73
    # XXX: FIXME: bzr status should accept a -r option to show changes
110
74
    # relative to a revision, or between revisions
111
75
 
112
 
    # TODO: --no-recurse, --recurse options
113
 
    
114
76
    takes_args = ['file*']
115
77
    takes_options = ['all', 'show-ids']
116
78
    aliases = ['st', 'stat']
117
79
    
118
 
    @display_command
119
80
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
120
 
        b, file_list = branch_files(file_list)
 
81
        if file_list:
 
82
            b = Branch.open_containing(file_list[0])
 
83
            tree = WorkingTree(b.base, b)
 
84
            file_list = [tree.relpath(x) for x in file_list]
 
85
            # special case: only one path was given and it's the root
 
86
            # of the branch
 
87
            if file_list == ['']:
 
88
                file_list = None
 
89
        else:
 
90
            b = Branch.open_containing('.')
121
91
            
122
92
        from bzrlib.status import show_status
123
93
        show_status(b, show_unchanged=all, show_ids=show_ids,
135
105
    takes_args = ['revision_id?']
136
106
    takes_options = ['revision']
137
107
    
138
 
    @display_command
139
108
    def run(self, revision_id=None, revision=None):
140
109
 
141
110
        if revision_id is not None and revision is not None:
142
111
            raise BzrCommandError('You can only supply one of revision_id or --revision')
143
112
        if revision_id is None and revision is None:
144
113
            raise BzrCommandError('You must supply either --revision or a revision_id')
145
 
        b = Branch.open_containing('.')[0]
 
114
        b = Branch.open_containing('.')
146
115
        if revision_id is not None:
147
116
            sys.stdout.write(b.get_revision_xml_file(revision_id).read())
148
117
        elif revision is not None:
157
126
    """Show current revision number.
158
127
 
159
128
    This is equal to the number of revisions on this branch."""
160
 
    @display_command
161
129
    def run(self):
162
 
        print Branch.open_containing('.')[0].revno()
 
130
        print Branch.open_containing('.').revno()
163
131
 
164
132
 
165
133
class cmd_revision_info(Command):
168
136
    hidden = True
169
137
    takes_args = ['revision_info*']
170
138
    takes_options = ['revision']
171
 
    @display_command
172
139
    def run(self, revision=None, revision_info_list=[]):
173
140
 
174
141
        revs = []
180
147
        if len(revs) == 0:
181
148
            raise BzrCommandError('You must supply a revision identifier')
182
149
 
183
 
        b = Branch.open_containing('.')[0]
 
150
        b = Branch.open_containing('.')
184
151
 
185
152
        for rev in revs:
186
153
            revinfo = rev.in_history(b)
238
205
        for d in dir_list:
239
206
            os.mkdir(d)
240
207
            if not b:
241
 
                b = Branch.open_containing(d)[0]
 
208
                b = Branch.open_containing(d)
242
209
            b.add([d])
243
210
            print 'added', d
244
211
 
248
215
    takes_args = ['filename']
249
216
    hidden = True
250
217
    
251
 
    @display_command
252
218
    def run(self, filename):
253
 
        branch, relpath = Branch.open_containing(filename)
254
 
        print relpath
 
219
        branch = Branch.open_containing(filename)
 
220
        print WorkingTree(branch.base, branch).relpath(filename)
255
221
 
256
222
 
257
223
class cmd_inventory(Command):
258
224
    """Show inventory of the current working copy or a revision."""
259
225
    takes_options = ['revision', 'show-ids']
260
226
    
261
 
    @display_command
262
227
    def run(self, revision=None, show_ids=False):
263
 
        b = Branch.open_containing('.')[0]
 
228
        b = Branch.open_containing('.')
264
229
        if revision is None:
265
230
            inv = b.read_working_inventory()
266
231
        else:
286
251
    """
287
252
    takes_args = ['source$', 'dest']
288
253
    def run(self, source_list, dest):
289
 
        b, source_list = branch_files(source_list)
 
254
        b = Branch.open_containing('.')
290
255
 
291
256
        # TODO: glob expansion on windows?
292
257
        tree = WorkingTree(b.base, b)
293
 
        b.move(source_list, tree.relpath(dest))
 
258
        b.move([tree.relpath(s) for s in source_list], tree.relpath(dest))
294
259
 
295
260
 
296
261
class cmd_rename(Command):
310
275
    takes_args = ['from_name', 'to_name']
311
276
    
312
277
    def run(self, from_name, to_name):
313
 
        b, (from_name, to_name) = branch_files((from_name, to_name))
314
 
        b.rename_one(from_name, to_name)
 
278
        b = Branch.open_containing('.')
 
279
        tree = WorkingTree(b.base, b)
 
280
        b.rename_one(tree.relpath(from_name), tree.relpath(to_name))
315
281
 
316
282
 
317
283
class cmd_mv(Command):
331
297
    def run(self, names_list):
332
298
        if len(names_list) < 2:
333
299
            raise BzrCommandError("missing file argument")
334
 
        b, rel_names = branch_files(names_list)
 
300
        b = Branch.open_containing(names_list[0])
 
301
        tree = WorkingTree(b.base, b)
 
302
        rel_names = [tree.relpath(x) for x in names_list]
335
303
        
336
304
        if os.path.isdir(names_list[-1]):
337
305
            # move into existing directory
345
313
            print "%s => %s" % (rel_names[0], rel_names[1])
346
314
            
347
315
    
 
316
 
 
317
 
348
318
class cmd_pull(Command):
349
319
    """Pull any changes from another branch into the current one.
350
320
 
351
 
    If there is no default location set, the first pull will set it.  After
352
 
    that, you can omit the location to use the default.  To change the
353
 
    default, use --remember.
 
321
    If the location is omitted, the last-used location will be used.
 
322
    Both the revision history and the working directory will be
 
323
    updated.
354
324
 
355
325
    This command only works on branches that have not diverged.  Branches are
356
326
    considered diverged if both branches have had commits without first
357
327
    pulling from the other.
358
328
 
359
329
    If branches have diverged, you can use 'bzr merge' to pull the text changes
360
 
    from one into the other.  Once one branch has merged, the other should
361
 
    be able to pull it again.
362
 
 
363
 
    If you want to forget your local changes and just update your branch to
364
 
    match the remote one, use --overwrite.
 
330
    from one into the other.
365
331
    """
366
 
    takes_options = ['remember', 'overwrite']
 
332
    takes_options = ['remember']
367
333
    takes_args = ['location?']
368
334
 
369
 
    def run(self, location=None, remember=False, overwrite=False):
 
335
    def run(self, location=None, remember=False):
370
336
        from bzrlib.merge import merge
 
337
        import tempfile
371
338
        from shutil import rmtree
372
339
        import errno
373
340
        
374
 
        br_to = Branch.open_containing('.')[0]
 
341
        br_to = Branch.open_containing('.')
375
342
        stored_loc = br_to.get_parent()
376
343
        if location is None:
377
344
            if stored_loc is None:
379
346
            else:
380
347
                print "Using saved location: %s" % stored_loc
381
348
                location = stored_loc
382
 
        if br_to.get_parent() is None or remember:
383
 
            br_to.set_parent(location)
 
349
        cache_root = tempfile.mkdtemp()
384
350
        br_from = Branch.open(location)
385
 
        try:
386
 
            br_to.working_tree().pull(br_from, overwrite)
387
 
        except DivergedBranches:
388
 
            raise BzrCommandError("These branches have diverged."
389
 
                                  "  Try merge.")
390
 
 
391
 
 
392
 
class cmd_push(Command):
393
 
    """Push this branch into another branch.
394
 
    
395
 
    The remote branch will not have its working tree populated because this
396
 
    is both expensive, and may not be supported on the remote file system.
397
 
    
398
 
    Some smart servers or protocols *may* put the working tree in place.
399
 
 
400
 
    If there is no default push location set, the first push will set it.
401
 
    After that, you can omit the location to use the default.  To change the
402
 
    default, use --remember.
403
 
 
404
 
    This command only works on branches that have not diverged.  Branches are
405
 
    considered diverged if the branch being pushed to is not an older version
406
 
    of this branch.
407
 
 
408
 
    If branches have diverged, you can use 'bzr push --overwrite' to replace
409
 
    the other branch completely.
410
 
    
411
 
    If you want to ensure you have the different changes in the other branch,
412
 
    do a merge (see bzr help merge) from the other branch, and commit that
413
 
    before doing a 'push --overwrite'.
414
 
    """
415
 
    takes_options = ['remember', 'overwrite']
416
 
    takes_args = ['location?']
417
 
 
418
 
    def run(self, location=None, remember=False, overwrite=False):
419
 
        import errno
420
 
        from shutil import rmtree
421
 
        from bzrlib.transport import get_transport
422
 
        
423
 
        br_from = Branch.open_containing('.')[0]
424
 
        stored_loc = br_from.get_push_location()
425
 
        if location is None:
426
 
            if stored_loc is None:
427
 
                raise BzrCommandError("No push location known or specified.")
428
 
            else:
429
 
                print "Using saved location: %s" % stored_loc
430
 
                location = stored_loc
431
 
        if br_from.get_push_location() is None or remember:
432
 
            br_from.set_push_location(location)
433
 
        try:
434
 
            br_to = Branch.open(location)
435
 
        except NotBranchError:
436
 
            # create a branch.
437
 
            transport = get_transport(location).clone('..')
438
 
            transport.mkdir(transport.relpath(location))
439
 
            br_to = Branch.initialize(location)
440
 
        try:
441
 
            br_to.pull(br_from, overwrite)
442
 
        except DivergedBranches:
443
 
            raise BzrCommandError("These branches have diverged."
444
 
                                  "  Try a merge then push with overwrite.")
 
351
        br_from.lock_read()
 
352
        try:
 
353
            br_from.setup_caching(cache_root)
 
354
            location = br_from.base
 
355
            old_revno = br_to.revno()
 
356
            old_revision_history = br_to.revision_history()
 
357
            try:
 
358
                br_to.update_revisions(br_from)
 
359
            except DivergedBranches:
 
360
                raise BzrCommandError("These branches have diverged."
 
361
                    "  Try merge.")
 
362
            new_revision_history = br_to.revision_history()
 
363
            if new_revision_history != old_revision_history:
 
364
                merge(('.', -1), ('.', old_revno), check_clean=False)
 
365
            if stored_loc is None or remember:
 
366
                br_to.set_parent(location)
 
367
        finally:
 
368
            br_from.unlock()
 
369
            rmtree(cache_root)
 
370
 
445
371
 
446
372
 
447
373
class cmd_branch(Command):
463
389
 
464
390
    def run(self, from_location, to_location=None, revision=None, basis=None):
465
391
        from bzrlib.clone import copy_branch
 
392
        import tempfile
466
393
        import errno
467
394
        from shutil import rmtree
 
395
        cache_root = tempfile.mkdtemp()
468
396
        if revision is None:
469
397
            revision = [None]
470
398
        elif len(revision) > 1:
480
408
                raise
481
409
        br_from.lock_read()
482
410
        try:
 
411
            br_from.setup_caching(cache_root)
483
412
            if basis is not None:
484
 
                basis_branch = Branch.open_containing(basis)[0]
 
413
                basis_branch = Branch.open_containing(basis)
485
414
            else:
486
415
                basis_branch = None
487
416
            if len(revision) == 1 and revision[0] is not None:
490
419
                revision_id = None
491
420
            if to_location is None:
492
421
                to_location = os.path.basename(from_location.rstrip("/\\"))
493
 
                name = None
494
 
            else:
495
 
                name = os.path.basename(to_location) + '\n'
496
422
            try:
497
423
                os.mkdir(to_location)
498
424
            except OSError, e:
508
434
                copy_branch(br_from, to_location, revision_id, basis_branch)
509
435
            except bzrlib.errors.NoSuchRevision:
510
436
                rmtree(to_location)
511
 
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
 
437
                msg = "The branch %s has no revision %d." % (from_location, revision[0])
512
438
                raise BzrCommandError(msg)
513
439
            except bzrlib.errors.UnlistableBranch:
514
 
                rmtree(to_location)
515
440
                msg = "The branch %s cannot be used as a --basis"
516
 
                raise BzrCommandError(msg)
517
 
            if name:
518
 
                branch = Branch.open(to_location)
519
 
                name = StringIO(name)
520
 
                branch.put_controlfile('branch-name', name)
521
441
        finally:
522
442
            br_from.unlock()
 
443
            rmtree(cache_root)
523
444
 
524
445
 
525
446
class cmd_renames(Command):
530
451
    # TODO: Only show renames under dir, rather than in the whole branch.
531
452
    takes_args = ['dir?']
532
453
 
533
 
    @display_command
534
454
    def run(self, dir='.'):
535
 
        b = Branch.open_containing(dir)[0]
 
455
        b = Branch.open_containing(dir)
536
456
        old_inv = b.basis_tree().inventory
537
457
        new_inv = b.read_working_inventory()
538
458
 
546
466
    """Show statistical information about a branch."""
547
467
    takes_args = ['branch?']
548
468
    
549
 
    @display_command
550
469
    def run(self, branch=None):
551
470
        import info
552
 
        b = Branch.open_containing(branch)[0]
 
471
        b = Branch.open_containing(branch)
553
472
        info.show_info(b)
554
473
 
555
474
 
564
483
    aliases = ['rm']
565
484
    
566
485
    def run(self, file_list, verbose=False):
567
 
        b, file_list = branch_files(file_list)
568
 
        tree = b.working_tree()
569
 
        tree.remove(file_list, verbose=verbose)
 
486
        b = Branch.open_containing(file_list[0])
 
487
        tree = WorkingTree(b.base, b)
 
488
        b.remove([tree.relpath(f) for f in file_list], verbose=verbose)
570
489
 
571
490
 
572
491
class cmd_file_id(Command):
578
497
    """
579
498
    hidden = True
580
499
    takes_args = ['filename']
581
 
    @display_command
582
500
    def run(self, filename):
583
 
        b, relpath = Branch.open_containing(filename)
584
 
        i = b.inventory.path2id(relpath)
 
501
        b = Branch.open_containing(filename)
 
502
        tree = WorkingTree(b.base, b)
 
503
        i = b.inventory.path2id(tree.relpath(filename))
585
504
        if i == None:
586
505
            raise BzrError("%r is not a versioned file" % filename)
587
506
        else:
595
514
    starting at the branch root."""
596
515
    hidden = True
597
516
    takes_args = ['filename']
598
 
    @display_command
599
517
    def run(self, filename):
600
 
        b, relpath = Branch.open_containing(filename)
 
518
        b = Branch.open_containing(filename)
601
519
        inv = b.inventory
602
 
        fid = inv.path2id(relpath)
 
520
        tree = WorkingTree(b.base, b)
 
521
        fid = inv.path2id(tree.relpath(filename))
603
522
        if fid == None:
604
523
            raise BzrError("%r is not a versioned file" % filename)
605
524
        for fip in inv.get_idpath(fid):
609
528
class cmd_revision_history(Command):
610
529
    """Display list of revision ids on this branch."""
611
530
    hidden = True
612
 
    @display_command
613
531
    def run(self):
614
 
        for patchid in Branch.open_containing('.')[0].revision_history():
 
532
        for patchid in Branch.open_containing('.').revision_history():
615
533
            print patchid
616
534
 
617
535
 
618
536
class cmd_ancestry(Command):
619
537
    """List all revisions merged into this branch."""
620
538
    hidden = True
621
 
    @display_command
622
539
    def run(self):
623
 
        b = Branch.open_containing('.')[0]
 
540
        b = find_branch('.')
624
541
        for revision_id in b.get_ancestry(b.last_revision()):
625
542
            print revision_id
626
543
 
627
544
 
628
545
class cmd_directories(Command):
629
546
    """Display list of versioned directories in this branch."""
630
 
    @display_command
631
547
    def run(self):
632
 
        for name, ie in Branch.open_containing('.')[0].read_working_inventory().directories():
 
548
        for name, ie in Branch.open_containing('.').read_working_inventory().directories():
633
549
            if name == '':
634
550
                print '.'
635
551
            else:
645
561
    Recipe for importing a tree of files:
646
562
        cd ~/project
647
563
        bzr init
648
 
        bzr add .
 
564
        bzr add -v .
649
565
        bzr status
650
566
        bzr commit -m 'imported project'
651
567
    """
682
598
    takes_options = ['revision', 'diff-options']
683
599
    aliases = ['di', 'dif']
684
600
 
685
 
    @display_command
686
601
    def run(self, revision=None, file_list=None, diff_options=None):
687
602
        from bzrlib.diff import show_diff
688
 
        
689
 
        b, file_list = branch_files(file_list)
 
603
 
 
604
        if file_list:
 
605
            b = Branch.open_containing(file_list[0])
 
606
            tree = WorkingTree(b.base, b)
 
607
            file_list = [tree.relpath(f) for f in file_list]
 
608
            if file_list == ['']:
 
609
                # just pointing to top-of-tree
 
610
                file_list = None
 
611
        else:
 
612
            b = Branch.open_containing('.')
 
613
 
690
614
        if revision is not None:
691
615
            if len(revision) == 1:
692
 
                return show_diff(b, revision[0], specific_files=file_list,
693
 
                                 external_diff_options=diff_options)
 
616
                show_diff(b, revision[0], specific_files=file_list,
 
617
                          external_diff_options=diff_options)
694
618
            elif len(revision) == 2:
695
 
                return show_diff(b, revision[0], specific_files=file_list,
696
 
                                 external_diff_options=diff_options,
697
 
                                 revision2=revision[1])
 
619
                show_diff(b, revision[0], specific_files=file_list,
 
620
                          external_diff_options=diff_options,
 
621
                          revision2=revision[1])
698
622
            else:
699
623
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
700
624
        else:
701
 
            return show_diff(b, None, specific_files=file_list,
702
 
                             external_diff_options=diff_options)
 
625
            show_diff(b, None, specific_files=file_list,
 
626
                      external_diff_options=diff_options)
 
627
 
 
628
        
703
629
 
704
630
 
705
631
class cmd_deleted(Command):
711
637
    # directories with readdir, rather than stating each one.  Same
712
638
    # level of effort but possibly much less IO.  (Or possibly not,
713
639
    # if the directories are very large...)
714
 
    @display_command
715
640
    def run(self, show_ids=False):
716
 
        b = Branch.open_containing('.')[0]
 
641
        b = Branch.open_containing('.')
717
642
        old = b.basis_tree()
718
643
        new = b.working_tree()
719
644
        for path, ie in old.inventory.iter_entries():
727
652
class cmd_modified(Command):
728
653
    """List files modified in working tree."""
729
654
    hidden = True
730
 
    @display_command
731
655
    def run(self):
732
656
        from bzrlib.delta import compare_trees
733
657
 
734
 
        b = Branch.open_containing('.')[0]
 
658
        b = Branch.open_containing('.')
735
659
        td = compare_trees(b.basis_tree(), b.working_tree())
736
660
 
737
661
        for path, id, kind, text_modified, meta_modified in td.modified:
742
666
class cmd_added(Command):
743
667
    """List files added in working tree."""
744
668
    hidden = True
745
 
    @display_command
746
669
    def run(self):
747
 
        b = Branch.open_containing('.')[0]
 
670
        b = Branch.open_containing('.')
748
671
        wt = b.working_tree()
749
672
        basis_inv = b.basis_tree().inventory
750
673
        inv = wt.inventory
764
687
    The root is the nearest enclosing directory with a .bzr control
765
688
    directory."""
766
689
    takes_args = ['filename?']
767
 
    @display_command
768
690
    def run(self, filename=None):
769
691
        """Print the branch root."""
770
 
        b = Branch.open_containing(filename)[0]
 
692
        b = Branch.open_containing(filename)
771
693
        print b.base
772
694
 
773
695
 
793
715
                            type=str),
794
716
                     Option('short', help='use moderately short format'),
795
717
                     ]
796
 
    @display_command
 
718
    
797
719
    def run(self, filename=None, timezone='original',
798
720
            verbose=False,
799
721
            show_ids=False,
810
732
        direction = (forward and 'forward') or 'reverse'
811
733
        
812
734
        if filename:
813
 
            b, fp = Branch.open_containing(filename)
814
 
            if fp != '':
 
735
            b = Branch.open_containing(filename)
 
736
            tree = WorkingTree(b.base, b)
 
737
            fp = tree.relpath(filename)
 
738
            if fp:
815
739
                file_id = b.read_working_inventory().path2id(fp)
816
740
            else:
817
741
                file_id = None  # points to branch root
818
742
        else:
819
 
            b, relpath = Branch.open_containing('.')
 
743
            b = Branch.open_containing('.')
820
744
            file_id = None
821
745
 
822
746
        if revision is None:
868
792
    A more user-friendly interface is "bzr log FILE"."""
869
793
    hidden = True
870
794
    takes_args = ["filename"]
871
 
    @display_command
872
795
    def run(self, filename):
873
 
        b, relpath = Branch.open_containing(filename)[0]
 
796
        b = Branch.open_containing(filename)
874
797
        inv = b.read_working_inventory()
875
 
        file_id = inv.path2id(relpath)
 
798
        tree = WorkingTree(b.base, b)
 
799
        file_id = inv.path2id(tree.relpath(filename))
876
800
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
877
801
            print "%6d %s" % (revno, what)
878
802
 
882
806
    """
883
807
    # TODO: Take a revision or remote path and list that tree instead.
884
808
    hidden = True
885
 
    takes_options = ['verbose', 'revision',
886
 
                     Option('non-recursive',
887
 
                            help='don\'t recurse into sub-directories'),
888
 
                     Option('from-root',
889
 
                            help='Print all paths from the root of the branch.'),
890
 
                     Option('unknown', help='Print unknown files'),
891
 
                     Option('versioned', help='Print versioned files'),
892
 
                     Option('ignored', help='Print ignored files'),
893
 
 
894
 
                     Option('null', help='Null separate the files'),
895
 
                    ]
896
 
    @display_command
897
 
    def run(self, revision=None, verbose=False, 
898
 
            non_recursive=False, from_root=False,
899
 
            unknown=False, versioned=False, ignored=False,
900
 
            null=False):
901
 
 
902
 
        if verbose and null:
903
 
            raise BzrCommandError('Cannot set both --verbose and --null')
904
 
        all = not (unknown or versioned or ignored)
905
 
 
906
 
        selection = {'I':ignored, '?':unknown, 'V':versioned}
907
 
 
908
 
        b, relpath = Branch.open_containing('.')
909
 
        if from_root:
910
 
            relpath = ''
911
 
        elif relpath:
912
 
            relpath += '/'
 
809
    def run(self, revision=None, verbose=False):
 
810
        b = Branch.open_containing('.')
913
811
        if revision == None:
914
812
            tree = b.working_tree()
915
813
        else:
916
 
            tree = b.revision_tree(revision[0].in_history(b).rev_id)
 
814
            tree = b.revision_tree(revision.in_history(b).rev_id)
917
815
        for fp, fc, kind, fid, entry in tree.list_files():
918
 
            if fp.startswith(relpath):
919
 
                fp = fp[len(relpath):]
920
 
                if non_recursive and '/' in fp:
921
 
                    continue
922
 
                if not all and not selection[fc]:
923
 
                    continue
924
 
                if verbose:
925
 
                    kindch = entry.kind_character()
926
 
                    print '%-8s %s%s' % (fc, fp, kindch)
927
 
                elif null:
928
 
                    sys.stdout.write(fp)
929
 
                    sys.stdout.write('\0')
930
 
                    sys.stdout.flush()
931
 
                else:
932
 
                    print fp
 
816
            if verbose:
 
817
                kindch = entry.kind_character()
 
818
                print '%-8s %s%s' % (fc, fp, kindch)
 
819
            else:
 
820
                print fp
933
821
 
934
822
 
935
823
 
936
824
class cmd_unknowns(Command):
937
825
    """List unknown files."""
938
 
    @display_command
939
826
    def run(self):
940
827
        from bzrlib.osutils import quotefn
941
 
        for f in Branch.open_containing('.')[0].unknowns():
 
828
        for f in Branch.open_containing('.').unknowns():
942
829
            print quotefn(f)
943
830
 
944
831
 
968
855
        from bzrlib.atomicfile import AtomicFile
969
856
        import os.path
970
857
 
971
 
        b, relpath = Branch.open_containing('.')
 
858
        b = Branch.open_containing('.')
972
859
        ifn = b.abspath('.bzrignore')
973
860
 
974
861
        if os.path.exists(ifn):
1007
894
    """List ignored files and the patterns that matched them.
1008
895
 
1009
896
    See also: bzr ignore"""
1010
 
    @display_command
1011
897
    def run(self):
1012
 
        tree = Branch.open_containing('.')[0].working_tree()
 
898
        tree = Branch.open_containing('.').working_tree()
1013
899
        for path, file_class, kind, file_id, entry in tree.list_files():
1014
900
            if file_class != 'I':
1015
901
                continue
1027
913
    hidden = True
1028
914
    takes_args = ['revno']
1029
915
    
1030
 
    @display_command
1031
916
    def run(self, revno):
1032
917
        try:
1033
918
            revno = int(revno)
1034
919
        except ValueError:
1035
920
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1036
921
 
1037
 
        print Branch.open_containing('.')[0].get_rev_id(revno)
 
922
        print Branch.open_containing('.').get_rev_id(revno)
1038
923
 
1039
924
 
1040
925
class cmd_export(Command):
1053
938
    takes_options = ['revision', 'format', 'root']
1054
939
    def run(self, dest, revision=None, format=None, root=None):
1055
940
        import os.path
1056
 
        b = Branch.open_containing('.')[0]
 
941
        b = Branch.open_containing('.')
1057
942
        if revision is None:
1058
943
            rev_id = b.last_revision()
1059
944
        else:
1087
972
    takes_options = ['revision']
1088
973
    takes_args = ['filename']
1089
974
 
1090
 
    @display_command
1091
975
    def run(self, filename, revision=None):
1092
976
        if revision is None:
1093
977
            raise BzrCommandError("bzr cat requires a revision number")
1094
978
        elif len(revision) != 1:
1095
979
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1096
 
        b, relpath = Branch.open_containing(filename)
1097
 
        b.print_file(relpath, revision[0].in_history(b).revno)
 
980
        b = Branch.open_containing('.')
 
981
        tree = WorkingTree(b.base, b)
 
982
        b.print_file(tree.relpath(filename), revision[0].in_history(b).revno)
1098
983
 
1099
984
 
1100
985
class cmd_local_time_offset(Command):
1101
986
    """Show the offset in seconds from GMT to local time."""
1102
987
    hidden = True    
1103
 
    @display_command
1104
988
    def run(self):
1105
989
        print bzrlib.osutils.local_time_offset()
1106
990
 
1121
1005
    """
1122
1006
    # TODO: Run hooks on tree to-be-committed, and after commit.
1123
1007
 
1124
 
    # TODO: Strict commit that fails if there are deleted files.
1125
 
    #       (what does "deleted files" mean ??)
1126
 
 
 
1008
    # TODO: Strict commit that fails if there are unknown or deleted files.
1127
1009
    # TODO: Give better message for -s, --summary, used by tla people
1128
1010
 
1129
1011
    # XXX: verbose currently does nothing
1135
1017
                     Option('file', type=str, 
1136
1018
                            argname='msgfile',
1137
1019
                            help='file containing commit message'),
1138
 
                     Option('strict',
1139
 
                            help="refuse to commit if there are unknown "
1140
 
                            "files in the working tree."),
1141
1020
                     ]
1142
1021
    aliases = ['ci', 'checkin']
1143
1022
 
1144
1023
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1145
 
            unchanged=False, strict=False):
1146
 
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1147
 
                StrictCommitFailed)
 
1024
            unchanged=False):
 
1025
        from bzrlib.errors import PointlessCommit, ConflictsInTree
1148
1026
        from bzrlib.msgeditor import edit_commit_message
1149
1027
        from bzrlib.status import show_status
1150
1028
        from cStringIO import StringIO
1151
1029
 
1152
 
        b, selected_list = branch_files(selected_list)
 
1030
        b = Branch.open_containing('.')
 
1031
        tree = WorkingTree(b.base, b)
 
1032
        if selected_list:
 
1033
            selected_list = [tree.relpath(s) for s in selected_list]
1153
1034
        if message is None and not file:
1154
1035
            catcher = StringIO()
1155
1036
            show_status(b, specific_files=selected_list,
1170
1051
                raise BzrCommandError("empty commit message specified")
1171
1052
            
1172
1053
        try:
1173
 
            b.commit(message, specific_files=selected_list,
1174
 
                     allow_pointless=unchanged, strict=strict)
 
1054
            b.commit(message,
 
1055
                     specific_files=selected_list,
 
1056
                     allow_pointless=unchanged)
1175
1057
        except PointlessCommit:
1176
1058
            # FIXME: This should really happen before the file is read in;
1177
1059
            # perhaps prepare the commit; get the message; then actually commit
1180
1062
        except ConflictsInTree:
1181
1063
            raise BzrCommandError("Conflicts detected in working tree.  "
1182
1064
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1183
 
        except StrictCommitFailed:
1184
 
            raise BzrCommandError("Commit refused because there are unknown "
1185
 
                                  "files in the working tree.")
1186
1065
 
1187
1066
 
1188
1067
class cmd_check(Command):
1196
1075
 
1197
1076
    def run(self, dir='.', verbose=False):
1198
1077
        from bzrlib.check import check
1199
 
        check(Branch.open_containing(dir)[0], verbose)
 
1078
        check(Branch.open_containing(dir), verbose)
1200
1079
 
1201
1080
 
1202
1081
class cmd_scan_cache(Command):
1239
1118
    """Show bzr user id."""
1240
1119
    takes_options = ['email']
1241
1120
    
1242
 
    @display_command
1243
1121
    def run(self, email=False):
1244
1122
        try:
1245
 
            b = bzrlib.branch.Branch.open_containing('.')[0]
 
1123
            b = bzrlib.branch.Branch.open_containing('.')
1246
1124
            config = bzrlib.config.BranchConfig(b)
1247
1125
        except NotBranchError:
1248
1126
            config = bzrlib.config.GlobalConfig()
1313
1191
 
1314
1192
class cmd_version(Command):
1315
1193
    """Show version of bzr."""
1316
 
    @display_command
1317
1194
    def run(self):
1318
1195
        show_version()
1319
1196
 
1320
1197
class cmd_rocks(Command):
1321
1198
    """Statement of optimism."""
1322
1199
    hidden = True
1323
 
    @display_command
1324
1200
    def run(self):
1325
1201
        print "it sure does!"
1326
1202
 
1333
1209
    takes_args = ['branch', 'other']
1334
1210
    hidden = True
1335
1211
    
1336
 
    @display_command
1337
1212
    def run(self, branch, other):
1338
1213
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
1339
1214
        
1340
 
        branch1 = Branch.open_containing(branch)[0]
1341
 
        branch2 = Branch.open_containing(other)[0]
 
1215
        branch1 = Branch.open_containing(branch)
 
1216
        branch2 = Branch.open_containing(other)
1342
1217
 
1343
1218
        history_1 = branch1.revision_history()
1344
1219
        history_2 = branch2.revision_history()
1393
1268
    --force is given.
1394
1269
    """
1395
1270
    takes_args = ['branch?']
1396
 
    takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1397
 
                     Option('show-base', help="Show base revision text in "
1398
 
                            "conflicts")]
 
1271
    takes_options = ['revision', 'force', 'merge-type']
1399
1272
 
1400
 
    def run(self, branch=None, revision=None, force=False, merge_type=None,
1401
 
            show_base=False, reprocess=False):
 
1273
    def run(self, branch=None, revision=None, force=False, 
 
1274
            merge_type=None):
1402
1275
        from bzrlib.merge import merge
1403
1276
        from bzrlib.merge_core import ApplyMerge3
1404
1277
        if merge_type is None:
1405
1278
            merge_type = ApplyMerge3
1406
1279
        if branch is None:
1407
 
            branch = Branch.open_containing('.')[0].get_parent()
 
1280
            branch = Branch.open_containing('.').get_parent()
1408
1281
            if branch is None:
1409
1282
                raise BzrCommandError("No merge location known or specified.")
1410
1283
            else:
1415
1288
        else:
1416
1289
            if len(revision) == 1:
1417
1290
                base = [None, None]
1418
 
                other_branch = Branch.open_containing(branch)[0]
1419
 
                revno = revision[0].in_history(other_branch).revno
1420
 
                other = [branch, revno]
 
1291
                other = [branch, revision[0].in_history(branch).revno]
1421
1292
            else:
1422
1293
                assert len(revision) == 2
1423
1294
                if None in revision:
1424
1295
                    raise BzrCommandError(
1425
1296
                        "Merge doesn't permit that revision specifier.")
1426
 
                b = Branch.open_containing(branch)[0]
 
1297
                b = Branch.open(branch)
1427
1298
 
1428
1299
                base = [branch, revision[0].in_history(b).revno]
1429
1300
                other = [branch, revision[1].in_history(b).revno]
1430
1301
 
1431
1302
        try:
1432
 
            conflict_count = merge(other, base, check_clean=(not force),
1433
 
                                   merge_type=merge_type, reprocess=reprocess,
1434
 
                                   show_base=show_base)
1435
 
            if conflict_count != 0:
1436
 
                return 1
1437
 
            else:
1438
 
                return 0
 
1303
            merge(other, base, check_clean=(not force), merge_type=merge_type)
1439
1304
        except bzrlib.errors.AmbiguousBase, e:
1440
1305
            m = ("sorry, bzr can't determine the right merge base yet\n"
1441
1306
                 "candidates are:\n  "
1469
1334
        elif len(revision) != 1:
1470
1335
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1471
1336
        else:
1472
 
            b, file_list = branch_files(file_list)
 
1337
            b = Branch.open_containing('.')
1473
1338
            revno = revision[0].in_history(b).revno
1474
1339
        merge(('.', revno), parse_spec('.'),
1475
1340
              check_clean=False,
1477
1342
              backup_files=not no_backup,
1478
1343
              file_list=file_list)
1479
1344
        if not file_list:
1480
 
            Branch.open_containing('.')[0].set_pending_merges([])
 
1345
            Branch.open_containing('.').set_pending_merges([])
1481
1346
 
1482
1347
 
1483
1348
class cmd_assert_fail(Command):
1495
1360
    takes_args = ['topic?']
1496
1361
    aliases = ['?']
1497
1362
    
1498
 
    @display_command
1499
1363
    def run(self, topic=None, long=False):
1500
1364
        import help
1501
1365
        if topic is None and long:
1511
1375
    aliases = ['s-c']
1512
1376
    hidden = True
1513
1377
    
1514
 
    @display_command
1515
1378
    def run(self, context=None):
1516
1379
        import shellcomplete
1517
1380
        shellcomplete.shellcomplete(context)
1526
1389
    def run(self, from_branch, to_branch):
1527
1390
        from bzrlib.fetch import Fetcher
1528
1391
        from bzrlib.branch import Branch
1529
 
        from_b = Branch.open(from_branch)
1530
 
        to_b = Branch.open(to_branch)
1531
 
        from_b.lock_read()
1532
 
        try:
1533
 
            to_b.lock_write()
1534
 
            try:
1535
 
                Fetcher(to_b, from_b)
1536
 
            finally:
1537
 
                to_b.unlock()
1538
 
        finally:
1539
 
            from_b.unlock()
 
1392
        from_b = Branch(from_branch)
 
1393
        to_b = Branch(to_branch)
 
1394
        Fetcher(to_b, from_b)
 
1395
        
1540
1396
 
1541
1397
 
1542
1398
class cmd_missing(Command):
1551
1407
    # unknown options are parsed as booleans
1552
1408
    takes_options = ['verbose', 'quiet']
1553
1409
 
1554
 
    @display_command
1555
1410
    def run(self, remote=None, verbose=False, quiet=False):
1556
1411
        from bzrlib.errors import BzrCommandError
1557
1412
        from bzrlib.missing import show_missing
1559
1414
        if verbose and quiet:
1560
1415
            raise BzrCommandError('Cannot pass both quiet and verbose')
1561
1416
 
1562
 
        b = Branch.open_containing('.')[0]
 
1417
        b = Branch.open_containing('.')
1563
1418
        parent = b.get_parent()
1564
1419
        if remote is None:
1565
1420
            if parent is None:
1572
1427
            # We only update parent if it did not exist, missing
1573
1428
            # should not change the parent
1574
1429
            b.set_parent(remote)
1575
 
        br_remote = Branch.open_containing(remote)[0]
 
1430
        br_remote = Branch.open_containing(remote)
1576
1431
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1577
1432
 
1578
1433
 
1579
1434
class cmd_plugins(Command):
1580
1435
    """List plugins"""
1581
1436
    hidden = True
1582
 
    @display_command
1583
1437
    def run(self):
1584
1438
        import bzrlib.plugin
1585
1439
        from inspect import getdoc
1600
1454
    """Show testament (signing-form) of a revision."""
1601
1455
    takes_options = ['revision', 'long']
1602
1456
    takes_args = ['branch?']
1603
 
    @display_command
1604
1457
    def run(self, branch='.', revision=None, long=False):
1605
1458
        from bzrlib.testament import Testament
1606
 
        b = Branch.open_containing(branch)[0]
 
1459
        b = Branch.open_containing(branch)
1607
1460
        b.lock_read()
1608
1461
        try:
1609
1462
            if revision is None:
1638
1491
                     Option('long', help='show date in annotations'),
1639
1492
                     ]
1640
1493
 
1641
 
    @display_command
1642
1494
    def run(self, filename, all=False, long=False):
1643
1495
        from bzrlib.annotate import annotate_file
1644
 
        b, relpath = Branch.open_containing(filename)
 
1496
        b = Branch.open_containing(filename)
1645
1497
        b.lock_read()
1646
1498
        try:
1647
1499
            tree = WorkingTree(b.base, b)
 
1500
            rp = tree.relpath(filename)
1648
1501
            tree = b.revision_tree(b.last_revision())
1649
 
            file_id = tree.inventory.path2id(relpath)
 
1502
            file_id = tree.inventory.path2id(rp)
1650
1503
            file_version = tree.inventory[file_id].revision
1651
1504
            annotate_file(b, file_version, file_id, long, all, sys.stdout)
1652
1505
        finally:
1668
1521
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1669
1522
        if revision_id is None and revision is None:
1670
1523
            raise BzrCommandError('You must supply either --revision or a revision_id')
1671
 
        b = Branch.open_containing('.')[0]
 
1524
        b = Branch.open_containing('.')
1672
1525
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1673
1526
        if revision_id is not None:
1674
1527
            b.sign_revision(revision_id, gpg_strategy)
1675
1528
        elif revision is not None:
1676
 
            if len(revision) == 1:
1677
 
                revno, rev_id = revision[0].in_history(b)
 
1529
            for rev in revision:
 
1530
                if rev is None:
 
1531
                    raise BzrCommandError('You cannot specify a NULL revision.')
 
1532
                revno, rev_id = rev.in_history(b)
1678
1533
                b.sign_revision(rev_id, gpg_strategy)
1679
 
            elif len(revision) == 2:
1680
 
                # are they both on rh- if so we can walk between them
1681
 
                # might be nice to have a range helper for arbitrary
1682
 
                # revision paths. hmm.
1683
 
                from_revno, from_revid = revision[0].in_history(b)
1684
 
                to_revno, to_revid = revision[1].in_history(b)
1685
 
                if to_revid is None:
1686
 
                    to_revno = b.revno()
1687
 
                if from_revno is None or to_revno is None:
1688
 
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1689
 
                for revno in range(from_revno, to_revno + 1):
1690
 
                    b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1691
 
            else:
1692
 
                raise BzrCommandError('Please supply either one revision, or a range.')
1693
1534
 
1694
1535
 
1695
1536
# these get imported and then picked up by the scan for cmd_*