~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2005-10-16 08:26:43 UTC
  • mto: This revision was merged to the branch mainline in revision 1459.
  • Revision ID: robertc@lifelesslap.robertcollins.net-20051016082643-a2300b765aea49b4
unify __contains__ for TransportStore classes

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
 
22
import bzrlib.trace
 
23
from bzrlib.trace import mutter, note, log_error, warning
 
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
 
from bzrlib.commands import Command, display_command
28
 
from bzrlib.branch import Branch
29
 
from bzrlib.revision import common_ancestor
30
 
import bzrlib.errors as errors
31
 
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
32
 
                           NotBranchError, DivergedBranches, NotConflicted,
33
 
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
34
 
from bzrlib.option import Option
35
 
from bzrlib.revisionspec import RevisionSpec
36
 
import bzrlib.trace
37
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
38
 
from bzrlib.workingtree import WorkingTree
39
 
 
40
 
 
41
 
def tree_files(file_list, default_branch='.'):
42
 
    try:
43
 
        return internal_tree_files(file_list, default_branch)
44
 
    except FileInWrongBranch, e:
45
 
        raise BzrCommandError("%s is not in the same branch as %s" %
46
 
                             (e.path, file_list[0]))
47
 
 
48
 
def internal_tree_files(file_list, default_branch='.'):
49
 
    """\
50
 
    Return a branch and list of branch-relative paths.
51
 
    If supplied file_list is empty or None, the branch default will be used,
52
 
    and returned file_list will match the original.
53
 
    """
54
 
    if file_list is None or len(file_list) == 0:
55
 
        return WorkingTree.open_containing(default_branch)[0], file_list
56
 
    tree = WorkingTree.open_containing(file_list[0])[0]
57
 
    new_list = []
58
 
    for filename in file_list:
59
 
        try:
60
 
            new_list.append(tree.relpath(filename))
61
 
        except NotBranchError:
62
 
            raise FileInWrongBranch(tree.branch, filename)
63
 
    return tree, new_list
64
 
 
65
 
 
66
 
# TODO: Make sure no commands unconditionally use the working directory as a
67
 
# branch.  If a filename argument is used, the first of them should be used to
68
 
# specify the branch.  (Perhaps this can be factored out into some kind of
69
 
# Argument class, representing a file in a branch, where the first occurrence
70
 
# opens the branch?)
 
28
from bzrlib.commands import Command
 
29
 
71
30
 
72
31
class cmd_status(Command):
73
32
    """Display status summary.
108
67
    If a revision argument is given, the status is calculated against
109
68
    that revision, or between two revisions if two are provided.
110
69
    """
111
 
    
112
 
    # TODO: --no-recurse, --recurse options
113
 
    
 
70
    # XXX: FIXME: bzr status should accept a -r option to show changes
 
71
    # relative to a revision, or between revisions
 
72
 
114
73
    takes_args = ['file*']
115
 
    takes_options = ['all', 'show-ids', 'revision']
 
74
    takes_options = ['all', 'show-ids']
116
75
    aliases = ['st', 'stat']
117
76
    
118
 
    @display_command
119
77
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
120
 
        tree, file_list = tree_files(file_list)
 
78
        if file_list:
 
79
            b = Branch.open_containing(file_list[0])
 
80
            file_list = [b.relpath(x) for x in file_list]
 
81
            # special case: only one path was given and it's the root
 
82
            # of the branch
 
83
            if file_list == ['']:
 
84
                file_list = None
 
85
        else:
 
86
            b = Branch.open_containing('.')
121
87
            
122
88
        from bzrlib.status import show_status
123
 
        show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
 
89
        show_status(b, show_unchanged=all, show_ids=show_ids,
124
90
                    specific_files=file_list, revision=revision)
125
91
 
126
92
 
135
101
    takes_args = ['revision_id?']
136
102
    takes_options = ['revision']
137
103
    
138
 
    @display_command
139
104
    def run(self, revision_id=None, revision=None):
 
105
        from bzrlib.revisionspec import RevisionSpec
140
106
 
141
107
        if revision_id is not None and revision is not None:
142
108
            raise BzrCommandError('You can only supply one of revision_id or --revision')
143
109
        if revision_id is None and revision is None:
144
110
            raise BzrCommandError('You must supply either --revision or a revision_id')
145
 
        b = WorkingTree.open_containing('.')[0].branch
 
111
        b = Branch.open_containing('.')
146
112
        if revision_id is not None:
147
 
            sys.stdout.write(b.get_revision_xml(revision_id))
 
113
            sys.stdout.write(b.get_revision_xml_file(revision_id).read())
148
114
        elif revision is not None:
149
115
            for rev in revision:
150
116
                if rev is None:
151
117
                    raise BzrCommandError('You cannot specify a NULL revision.')
152
118
                revno, rev_id = rev.in_history(b)
153
 
                sys.stdout.write(b.get_revision_xml(rev_id))
 
119
                sys.stdout.write(b.get_revision_xml_file(rev_id).read())
154
120
    
155
121
 
156
122
class cmd_revno(Command):
157
123
    """Show current revision number.
158
124
 
159
125
    This is equal to the number of revisions on this branch."""
160
 
    @display_command
161
126
    def run(self):
162
 
        print Branch.open_containing('.')[0].revno()
 
127
        print Branch.open_containing('.').revno()
163
128
 
164
129
 
165
130
class cmd_revision_info(Command):
168
133
    hidden = True
169
134
    takes_args = ['revision_info*']
170
135
    takes_options = ['revision']
171
 
    @display_command
172
136
    def run(self, revision=None, revision_info_list=[]):
 
137
        from bzrlib.revisionspec import RevisionSpec
173
138
 
174
139
        revs = []
175
140
        if revision is not None:
180
145
        if len(revs) == 0:
181
146
            raise BzrCommandError('You must supply a revision identifier')
182
147
 
183
 
        b = WorkingTree.open_containing('.')[0].branch
 
148
        b = Branch.open_containing('.')
184
149
 
185
150
        for rev in revs:
186
151
            revinfo = rev.in_history(b)
214
179
    get added when you add a file in the directory.
215
180
    """
216
181
    takes_args = ['file*']
217
 
    takes_options = ['no-recurse']
 
182
    takes_options = ['no-recurse', 'quiet']
218
183
    
219
 
    def run(self, file_list, no_recurse=False):
 
184
    def run(self, file_list, no_recurse=False, quiet=False):
220
185
        from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
221
 
        if is_quiet():
 
186
        if quiet:
222
187
            reporter = add_reporter_null
223
188
        else:
224
189
            reporter = add_reporter_print
233
198
    takes_args = ['dir+']
234
199
 
235
200
    def run(self, dir_list):
 
201
        b = None
 
202
        
236
203
        for d in dir_list:
237
204
            os.mkdir(d)
238
 
            wt, dd = WorkingTree.open_containing(d)
239
 
            wt.add([dd])
 
205
            if not b:
 
206
                b = Branch.open_containing(d)
 
207
            b.add([d])
240
208
            print 'added', d
241
209
 
242
210
 
245
213
    takes_args = ['filename']
246
214
    hidden = True
247
215
    
248
 
    @display_command
249
216
    def run(self, filename):
250
 
        tree, relpath = WorkingTree.open_containing(filename)
251
 
        print relpath
 
217
        print Branch.open_containing(filename).relpath(filename)
 
218
 
252
219
 
253
220
 
254
221
class cmd_inventory(Command):
255
 
    """Show inventory of the current working copy or a revision.
256
 
 
257
 
    It is possible to limit the output to a particular entry
258
 
    type using the --kind option.  For example; --kind file.
259
 
    """
260
 
    takes_options = ['revision', 'show-ids', 'kind']
 
222
    """Show inventory of the current working copy or a revision."""
 
223
    takes_options = ['revision', 'show-ids']
261
224
    
262
 
    @display_command
263
 
    def run(self, revision=None, show_ids=False, kind=None):
264
 
        if kind and kind not in ['file', 'directory', 'symlink']:
265
 
            raise BzrCommandError('invalid kind specified')
266
 
        tree = WorkingTree.open_containing('.')[0]
 
225
    def run(self, revision=None, show_ids=False):
 
226
        b = Branch.open_containing('.')
267
227
        if revision is None:
268
 
            inv = tree.read_working_inventory()
 
228
            inv = b.read_working_inventory()
269
229
        else:
270
230
            if len(revision) > 1:
271
231
                raise BzrCommandError('bzr inventory --revision takes'
272
232
                    ' exactly one revision identifier')
273
 
            inv = tree.branch.get_revision_inventory(
274
 
                revision[0].in_history(tree.branch).rev_id)
 
233
            inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
275
234
 
276
235
        for path, entry in inv.entries():
277
 
            if kind and kind != entry.kind:
278
 
                continue
279
236
            if show_ids:
280
237
                print '%-50s %s' % (path, entry.file_id)
281
238
            else:
292
249
    """
293
250
    takes_args = ['source$', 'dest']
294
251
    def run(self, source_list, dest):
295
 
        tree, source_list = tree_files(source_list)
 
252
        b = Branch.open_containing('.')
 
253
 
296
254
        # TODO: glob expansion on windows?
297
 
        tree.move(source_list, tree.relpath(dest))
 
255
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
298
256
 
299
257
 
300
258
class cmd_rename(Command):
314
272
    takes_args = ['from_name', 'to_name']
315
273
    
316
274
    def run(self, from_name, to_name):
317
 
        tree, (from_name, to_name) = tree_files((from_name, to_name))
318
 
        tree.rename_one(from_name, to_name)
 
275
        b = Branch.open_containing('.')
 
276
        b.rename_one(b.relpath(from_name), b.relpath(to_name))
 
277
 
319
278
 
320
279
 
321
280
class cmd_mv(Command):
335
294
    def run(self, names_list):
336
295
        if len(names_list) < 2:
337
296
            raise BzrCommandError("missing file argument")
338
 
        tree, rel_names = tree_files(names_list)
 
297
        b = Branch.open_containing(names_list[0])
 
298
 
 
299
        rel_names = [b.relpath(x) for x in names_list]
339
300
        
340
301
        if os.path.isdir(names_list[-1]):
341
302
            # move into existing directory
342
 
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
 
303
            for pair in b.move(rel_names[:-1], rel_names[-1]):
343
304
                print "%s => %s" % pair
344
305
        else:
345
306
            if len(names_list) != 2:
346
307
                raise BzrCommandError('to mv multiple files the destination '
347
308
                                      'must be a versioned directory')
348
 
            tree.rename_one(rel_names[0], rel_names[1])
 
309
            b.rename_one(rel_names[0], rel_names[1])
349
310
            print "%s => %s" % (rel_names[0], rel_names[1])
350
311
            
351
312
    
 
313
 
 
314
 
352
315
class cmd_pull(Command):
353
316
    """Pull any changes from another branch into the current one.
354
317
 
355
 
    If there is no default location set, the first pull will set it.  After
356
 
    that, you can omit the location to use the default.  To change the
357
 
    default, use --remember.
 
318
    If the location is omitted, the last-used location will be used.
 
319
    Both the revision history and the working directory will be
 
320
    updated.
358
321
 
359
322
    This command only works on branches that have not diverged.  Branches are
360
323
    considered diverged if both branches have had commits without first
361
324
    pulling from the other.
362
325
 
363
326
    If branches have diverged, you can use 'bzr merge' to pull the text changes
364
 
    from one into the other.  Once one branch has merged, the other should
365
 
    be able to pull it again.
366
 
 
367
 
    If you want to forget your local changes and just update your branch to
368
 
    match the remote one, use --overwrite.
 
327
    from one into the other.
369
328
    """
370
 
    takes_options = ['remember', 'overwrite', 'verbose']
 
329
    takes_options = ['remember']
371
330
    takes_args = ['location?']
372
331
 
373
 
    def run(self, location=None, remember=False, overwrite=False, verbose=False):
 
332
    def run(self, location=None, remember=False):
374
333
        from bzrlib.merge import merge
 
334
        import tempfile
375
335
        from shutil import rmtree
376
336
        import errno
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()
 
337
        
 
338
        br_to = Branch.open_containing('.')
 
339
        stored_loc = br_to.get_parent()
380
340
        if location is None:
381
341
            if stored_loc is None:
382
342
                raise BzrCommandError("No pull location known or specified.")
383
343
            else:
384
344
                print "Using saved location: %s" % stored_loc
385
345
                location = stored_loc
 
346
        cache_root = tempfile.mkdtemp()
386
347
        br_from = Branch.open(location)
387
 
        br_to = tree_to.branch
388
 
        try:
389
 
            old_rh = br_to.revision_history()
390
 
            count = tree_to.pull(br_from, overwrite)
391
 
        except DivergedBranches:
392
 
            # FIXME: Just make DivergedBranches display the right message
393
 
            # itself.
394
 
            raise BzrCommandError("These branches have diverged."
395
 
                                  "  Try merge.")
396
 
        if br_to.get_parent() is None or remember:
397
 
            br_to.set_parent(location)
398
 
        note('%d revision(s) pulled.', count)
399
 
        if verbose:
400
 
            new_rh = tree_to.branch.revision_history()
401
 
            if old_rh != new_rh:
402
 
                # Something changed
403
 
                from bzrlib.log import show_changed_revisions
404
 
                show_changed_revisions(tree_to.branch, old_rh, new_rh)
405
 
 
406
 
 
407
 
class cmd_push(Command):
408
 
    """Push this branch into another branch.
409
 
    
410
 
    The remote branch will not have its working tree populated because this
411
 
    is both expensive, and may not be supported on the remote file system.
412
 
    
413
 
    Some smart servers or protocols *may* put the working tree in place.
414
 
 
415
 
    If there is no default push location set, the first push will set it.
416
 
    After that, you can omit the location to use the default.  To change the
417
 
    default, use --remember.
418
 
 
419
 
    This command only works on branches that have not diverged.  Branches are
420
 
    considered diverged if the branch being pushed to is not an older version
421
 
    of this branch.
422
 
 
423
 
    If branches have diverged, you can use 'bzr push --overwrite' to replace
424
 
    the other branch completely.
425
 
    
426
 
    If you want to ensure you have the different changes in the other branch,
427
 
    do a merge (see bzr help merge) from the other branch, and commit that
428
 
    before doing a 'push --overwrite'.
429
 
    """
430
 
    takes_options = ['remember', 'overwrite', 
431
 
                     Option('create-prefix', 
432
 
                            help='Create the path leading up to the branch '
433
 
                                 'if it does not already exist')]
434
 
    takes_args = ['location?']
435
 
 
436
 
    def run(self, location=None, remember=False, overwrite=False,
437
 
            create_prefix=False, verbose=False):
438
 
        # FIXME: Way too big!  Put this into a function called from the
439
 
        # command.
440
 
        import errno
441
 
        from shutil import rmtree
442
 
        from bzrlib.transport import get_transport
443
 
        
444
 
        tree_from = WorkingTree.open_containing('.')[0]
445
 
        br_from = tree_from.branch
446
 
        stored_loc = tree_from.branch.get_push_location()
447
 
        if location is None:
448
 
            if stored_loc is None:
449
 
                raise BzrCommandError("No push location known or specified.")
450
 
            else:
451
 
                print "Using saved location: %s" % stored_loc
452
 
                location = stored_loc
453
 
        try:
454
 
            br_to = Branch.open(location)
455
 
        except NotBranchError:
456
 
            # create a branch.
457
 
            transport = get_transport(location).clone('..')
458
 
            if not create_prefix:
459
 
                try:
460
 
                    transport.mkdir(transport.relpath(location))
461
 
                except NoSuchFile:
462
 
                    raise BzrCommandError("Parent directory of %s "
463
 
                                          "does not exist." % location)
464
 
            else:
465
 
                current = transport.base
466
 
                needed = [(transport, transport.relpath(location))]
467
 
                while needed:
468
 
                    try:
469
 
                        transport, relpath = needed[-1]
470
 
                        transport.mkdir(relpath)
471
 
                        needed.pop()
472
 
                    except NoSuchFile:
473
 
                        new_transport = transport.clone('..')
474
 
                        needed.append((new_transport,
475
 
                                       new_transport.relpath(transport.base)))
476
 
                        if new_transport.base == transport.base:
477
 
                            raise BzrCommandError("Could not creeate "
478
 
                                                  "path prefix.")
479
 
            br_to = Branch.initialize(location)
480
 
        try:
481
 
            old_rh = br_to.revision_history()
482
 
            count = br_to.pull(br_from, overwrite)
483
 
        except DivergedBranches:
484
 
            raise BzrCommandError("These branches have diverged."
485
 
                                  "  Try a merge then push with overwrite.")
486
 
        if br_from.get_push_location() is None or remember:
487
 
            br_from.set_push_location(location)
488
 
        note('%d revision(s) pushed.' % (count,))
489
 
        if verbose:
490
 
            new_rh = br_to.revision_history()
491
 
            if old_rh != new_rh:
492
 
                # Something changed
493
 
                from bzrlib.log import show_changed_revisions
494
 
                show_changed_revisions(br_to, old_rh, new_rh)
 
348
        br_from.lock_read()
 
349
        try:
 
350
            br_from.setup_caching(cache_root)
 
351
            location = br_from.base
 
352
            old_revno = br_to.revno()
 
353
            old_revision_history = br_to.revision_history()
 
354
            try:
 
355
                br_to.update_revisions(br_from)
 
356
            except DivergedBranches:
 
357
                raise BzrCommandError("These branches have diverged."
 
358
                    "  Try merge.")
 
359
            new_revision_history = br_to.revision_history()
 
360
            if new_revision_history != old_revision_history:
 
361
                merge(('.', -1), ('.', old_revno), check_clean=False)
 
362
            if stored_loc is None or remember:
 
363
                br_to.set_parent(location)
 
364
        finally:
 
365
            br_from.unlock()
 
366
            rmtree(cache_root)
 
367
 
495
368
 
496
369
 
497
370
class cmd_branch(Command):
513
386
 
514
387
    def run(self, from_location, to_location=None, revision=None, basis=None):
515
388
        from bzrlib.clone import copy_branch
 
389
        import tempfile
516
390
        import errno
517
391
        from shutil import rmtree
 
392
        cache_root = tempfile.mkdtemp()
518
393
        if revision is None:
519
394
            revision = [None]
520
395
        elif len(revision) > 1:
530
405
                raise
531
406
        br_from.lock_read()
532
407
        try:
 
408
            br_from.setup_caching(cache_root)
533
409
            if basis is not None:
534
 
                basis_branch = WorkingTree.open_containing(basis)[0].branch
 
410
                basis_branch = Branch.open_containing(basis)
535
411
            else:
536
412
                basis_branch = None
537
413
            if len(revision) == 1 and revision[0] is not None:
540
416
                revision_id = None
541
417
            if to_location is None:
542
418
                to_location = os.path.basename(from_location.rstrip("/\\"))
543
 
                name = None
544
 
            else:
545
 
                name = os.path.basename(to_location) + '\n'
546
419
            try:
547
420
                os.mkdir(to_location)
548
421
            except OSError, e:
558
431
                copy_branch(br_from, to_location, revision_id, basis_branch)
559
432
            except bzrlib.errors.NoSuchRevision:
560
433
                rmtree(to_location)
561
 
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
 
434
                msg = "The branch %s has no revision %d." % (from_location, revision[0])
562
435
                raise BzrCommandError(msg)
563
436
            except bzrlib.errors.UnlistableBranch:
564
 
                rmtree(to_location)
565
437
                msg = "The branch %s cannot be used as a --basis"
566
 
                raise BzrCommandError(msg)
567
 
            branch = Branch.open(to_location)
568
 
            if name:
569
 
                name = StringIO(name)
570
 
                branch.put_controlfile('branch-name', name)
571
 
            note('Branched %d revision(s).' % branch.revno())
572
438
        finally:
573
439
            br_from.unlock()
 
440
            rmtree(cache_root)
574
441
 
575
442
 
576
443
class cmd_renames(Command):
581
448
    # TODO: Only show renames under dir, rather than in the whole branch.
582
449
    takes_args = ['dir?']
583
450
 
584
 
    @display_command
585
451
    def run(self, dir='.'):
586
 
        tree = WorkingTree.open_containing(dir)[0]
587
 
        old_inv = tree.branch.basis_tree().inventory
588
 
        new_inv = tree.read_working_inventory()
 
452
        b = Branch.open_containing(dir)
 
453
        old_inv = b.basis_tree().inventory
 
454
        new_inv = b.read_working_inventory()
589
455
 
590
456
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
591
457
        renames.sort()
597
463
    """Show statistical information about a branch."""
598
464
    takes_args = ['branch?']
599
465
    
600
 
    @display_command
601
466
    def run(self, branch=None):
602
467
        import info
603
 
        b = WorkingTree.open_containing(branch)[0].branch
 
468
        b = Branch.open_containing(branch)
604
469
        info.show_info(b)
605
470
 
606
471
 
615
480
    aliases = ['rm']
616
481
    
617
482
    def run(self, file_list, verbose=False):
618
 
        tree, file_list = tree_files(file_list)
619
 
        tree.remove(file_list, verbose=verbose)
 
483
        b = Branch.open_containing(file_list[0])
 
484
        b.remove([b.relpath(f) for f in file_list], verbose=verbose)
620
485
 
621
486
 
622
487
class cmd_file_id(Command):
628
493
    """
629
494
    hidden = True
630
495
    takes_args = ['filename']
631
 
    @display_command
632
496
    def run(self, filename):
633
 
        tree, relpath = WorkingTree.open_containing(filename)
634
 
        i = tree.inventory.path2id(relpath)
 
497
        b = Branch.open_containing(filename)
 
498
        i = b.inventory.path2id(b.relpath(filename))
635
499
        if i == None:
636
500
            raise BzrError("%r is not a versioned file" % filename)
637
501
        else:
645
509
    starting at the branch root."""
646
510
    hidden = True
647
511
    takes_args = ['filename']
648
 
    @display_command
649
512
    def run(self, filename):
650
 
        tree, relpath = WorkingTree.open_containing(filename)
651
 
        inv = tree.inventory
652
 
        fid = inv.path2id(relpath)
 
513
        b = Branch.open_containing(filename)
 
514
        inv = b.inventory
 
515
        fid = inv.path2id(b.relpath(filename))
653
516
        if fid == None:
654
517
            raise BzrError("%r is not a versioned file" % filename)
655
518
        for fip in inv.get_idpath(fid):
659
522
class cmd_revision_history(Command):
660
523
    """Display list of revision ids on this branch."""
661
524
    hidden = True
662
 
    @display_command
663
525
    def run(self):
664
 
        branch = WorkingTree.open_containing('.')[0].branch
665
 
        for patchid in branch.revision_history():
 
526
        for patchid in Branch.open_containing('.').revision_history():
666
527
            print patchid
667
528
 
668
529
 
669
530
class cmd_ancestry(Command):
670
531
    """List all revisions merged into this branch."""
671
532
    hidden = True
672
 
    @display_command
673
533
    def run(self):
674
 
        tree = WorkingTree.open_containing('.')[0]
675
 
        b = tree.branch
676
 
        # FIXME. should be tree.last_revision
 
534
        b = find_branch('.')
677
535
        for revision_id in b.get_ancestry(b.last_revision()):
678
536
            print revision_id
679
537
 
680
538
 
 
539
class cmd_directories(Command):
 
540
    """Display list of versioned directories in this branch."""
 
541
    def run(self):
 
542
        for name, ie in Branch.open_containing('.').read_working_inventory().directories():
 
543
            if name == '':
 
544
                print '.'
 
545
            else:
 
546
                print name
 
547
 
 
548
 
681
549
class cmd_init(Command):
682
550
    """Make a directory into a versioned branch.
683
551
 
687
555
    Recipe for importing a tree of files:
688
556
        cd ~/project
689
557
        bzr init
690
 
        bzr add .
 
558
        bzr add -v .
691
559
        bzr status
692
560
        bzr commit -m 'imported project'
693
561
    """
694
 
    takes_args = ['location?']
695
 
    def run(self, location=None):
696
 
        from bzrlib.branch import Branch
697
 
        if location is None:
698
 
            location = '.'
699
 
        else:
700
 
            # The path has to exist to initialize a
701
 
            # branch inside of it.
702
 
            # Just using os.mkdir, since I don't
703
 
            # believe that we want to create a bunch of
704
 
            # locations if the user supplies an extended path
705
 
            if not os.path.exists(location):
706
 
                os.mkdir(location)
707
 
        Branch.initialize(location)
 
562
    def run(self):
 
563
        Branch.initialize('.')
708
564
 
709
565
 
710
566
class cmd_diff(Command):
736
592
    takes_options = ['revision', 'diff-options']
737
593
    aliases = ['di', 'dif']
738
594
 
739
 
    @display_command
740
595
    def run(self, revision=None, file_list=None, diff_options=None):
741
596
        from bzrlib.diff import show_diff
742
 
        try:
743
 
            tree, file_list = internal_tree_files(file_list)
744
 
            b = None
745
 
            b2 = None
746
 
        except FileInWrongBranch:
747
 
            if len(file_list) != 2:
748
 
                raise BzrCommandError("Files are in different branches")
749
 
 
750
 
            b, file1 = Branch.open_containing(file_list[0])
751
 
            b2, file2 = Branch.open_containing(file_list[1])
752
 
            if file1 != "" or file2 != "":
753
 
                # FIXME diff those two files. rbc 20051123
754
 
                raise BzrCommandError("Files are in different branches")
755
 
            file_list = None
 
597
 
 
598
        if file_list:
 
599
            b = Branch.open_containing(file_list[0])
 
600
            file_list = [b.relpath(f) for f in file_list]
 
601
            if file_list == ['']:
 
602
                # just pointing to top-of-tree
 
603
                file_list = None
 
604
        else:
 
605
            b = Branch.open_containing('.')
 
606
 
756
607
        if revision is not None:
757
 
            if b2 is not None:
758
 
                raise BzrCommandError("Can't specify -r with two branches")
759
608
            if len(revision) == 1:
760
 
                return show_diff(tree.branch, revision[0], specific_files=file_list,
761
 
                                 external_diff_options=diff_options)
 
609
                show_diff(b, revision[0], specific_files=file_list,
 
610
                          external_diff_options=diff_options)
762
611
            elif len(revision) == 2:
763
 
                return show_diff(tree.branch, revision[0], specific_files=file_list,
764
 
                                 external_diff_options=diff_options,
765
 
                                 revision2=revision[1])
 
612
                show_diff(b, revision[0], specific_files=file_list,
 
613
                          external_diff_options=diff_options,
 
614
                          revision2=revision[1])
766
615
            else:
767
616
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
768
617
        else:
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)
 
618
            show_diff(b, None, specific_files=file_list,
 
619
                      external_diff_options=diff_options)
 
620
 
 
621
        
775
622
 
776
623
 
777
624
class cmd_deleted(Command):
783
630
    # directories with readdir, rather than stating each one.  Same
784
631
    # level of effort but possibly much less IO.  (Or possibly not,
785
632
    # if the directories are very large...)
786
 
    @display_command
787
633
    def run(self, show_ids=False):
788
 
        tree = WorkingTree.open_containing('.')[0]
789
 
        old = tree.branch.basis_tree()
 
634
        b = Branch.open_containing('.')
 
635
        old = b.basis_tree()
 
636
        new = b.working_tree()
790
637
        for path, ie in old.inventory.iter_entries():
791
 
            if not tree.has_id(ie.file_id):
 
638
            if not new.has_id(ie.file_id):
792
639
                if show_ids:
793
640
                    print '%-50s %s' % (path, ie.file_id)
794
641
                else:
798
645
class cmd_modified(Command):
799
646
    """List files modified in working tree."""
800
647
    hidden = True
801
 
    @display_command
802
648
    def run(self):
803
649
        from bzrlib.delta import compare_trees
804
650
 
805
 
        tree = WorkingTree.open_containing('.')[0]
806
 
        td = compare_trees(tree.branch.basis_tree(), tree)
 
651
        b = Branch.open_containing('.')
 
652
        td = compare_trees(b.basis_tree(), b.working_tree())
807
653
 
808
654
        for path, id, kind, text_modified, meta_modified in td.modified:
809
655
            print path
813
659
class cmd_added(Command):
814
660
    """List files added in working tree."""
815
661
    hidden = True
816
 
    @display_command
817
662
    def run(self):
818
 
        wt = WorkingTree.open_containing('.')[0]
819
 
        basis_inv = wt.branch.basis_tree().inventory
 
663
        b = Branch.open_containing('.')
 
664
        wt = b.working_tree()
 
665
        basis_inv = b.basis_tree().inventory
820
666
        inv = wt.inventory
821
667
        for file_id in inv:
822
668
            if file_id in basis_inv:
834
680
    The root is the nearest enclosing directory with a .bzr control
835
681
    directory."""
836
682
    takes_args = ['filename?']
837
 
    @display_command
838
683
    def run(self, filename=None):
839
684
        """Print the branch root."""
840
 
        tree = WorkingTree.open_containing(filename)[0]
841
 
        print tree.basedir
 
685
        b = Branch.open_containing(filename)
 
686
        print b.base
842
687
 
843
688
 
844
689
class cmd_log(Command):
845
690
    """Show log of this branch.
846
691
 
847
 
    To request a range of logs, you can use the command -r begin..end
848
 
    -r revision requests a specific revision, -r ..end or -r begin.. are
 
692
    To request a range of logs, you can use the command -r begin:end
 
693
    -r revision requests a specific revision, -r :end or -r begin: are
849
694
    also valid.
 
695
 
 
696
    --message allows you to give a regular expression, which will be evaluated
 
697
    so that only matching entries will be displayed.
850
698
    """
851
699
 
852
700
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
853
701
 
854
702
    takes_args = ['filename?']
855
 
    takes_options = [Option('forward', 
856
 
                            help='show from oldest to newest'),
857
 
                     'timezone', 'verbose', 
858
 
                     'show-ids', 'revision',
859
 
                     Option('line', help='format with one line per revision'),
860
 
                     'long', 
861
 
                     Option('message',
862
 
                            help='show revisions whose message matches this regexp',
863
 
                            type=str),
864
 
                     Option('short', help='use moderately short format'),
865
 
                     ]
866
 
    @display_command
 
703
    takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
 
704
                     'long', 'message', 'short',]
 
705
    
867
706
    def run(self, filename=None, timezone='original',
868
707
            verbose=False,
869
708
            show_ids=False,
871
710
            revision=None,
872
711
            message=None,
873
712
            long=False,
874
 
            short=False,
875
 
            line=False):
 
713
            short=False):
876
714
        from bzrlib.log import log_formatter, show_log
877
715
        import codecs
878
 
        assert message is None or isinstance(message, basestring), \
879
 
            "invalid message argument %r" % message
 
716
 
880
717
        direction = (forward and 'forward') or 'reverse'
881
718
        
882
719
        if 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())
896
 
            if fp != '':
897
 
                file_id = inv.path2id(fp)
 
720
            b = Branch.open_containing(filename)
 
721
            fp = b.relpath(filename)
 
722
            if fp:
 
723
                file_id = b.read_working_inventory().path2id(fp)
898
724
            else:
899
725
                file_id = None  # points to branch root
900
726
        else:
901
 
            tree, relpath = WorkingTree.open_containing('.')
902
 
            b = tree.branch
 
727
            b = Branch.open_containing('.')
903
728
            file_id = None
904
729
 
905
730
        if revision is None:
913
738
        else:
914
739
            raise BzrCommandError('bzr log --revision takes one or two values.')
915
740
 
916
 
        # By this point, the revision numbers are converted to the +ve
917
 
        # form if they were supplied in the -ve form, so we can do
918
 
        # this comparison in relative safety
919
 
        if rev1 > rev2:
920
 
            (rev2, rev1) = (rev1, rev2)
 
741
        if rev1 == 0:
 
742
            rev1 = None
 
743
        if rev2 == 0:
 
744
            rev2 = None
921
745
 
922
 
        mutter('encoding log as %r', bzrlib.user_encoding)
 
746
        mutter('encoding log as %r' % bzrlib.user_encoding)
923
747
 
924
748
        # use 'replace' so that we don't abort if trying to write out
925
749
        # in e.g. the default C locale.
926
750
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
927
751
 
928
 
        log_format = 'long'
929
 
        if short:
 
752
        if not short:
 
753
            log_format = 'long'
 
754
        else:
930
755
            log_format = 'short'
931
 
        if line:
932
 
            log_format = 'line'
933
756
        lf = log_formatter(log_format,
934
757
                           show_ids=show_ids,
935
758
                           to_file=outf,
952
775
    A more user-friendly interface is "bzr log FILE"."""
953
776
    hidden = True
954
777
    takes_args = ["filename"]
955
 
    @display_command
956
778
    def run(self, filename):
957
 
        tree, relpath = WorkingTree.open_containing(filename)
958
 
        b = tree.branch
959
 
        inv = tree.read_working_inventory()
960
 
        file_id = inv.path2id(relpath)
 
779
        b = Branch.open_containing(filename)
 
780
        inv = b.read_working_inventory()
 
781
        file_id = inv.path2id(b.relpath(filename))
961
782
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
962
783
            print "%6d %s" % (revno, what)
963
784
 
967
788
    """
968
789
    # TODO: Take a revision or remote path and list that tree instead.
969
790
    hidden = True
970
 
    takes_options = ['verbose', 'revision',
971
 
                     Option('non-recursive',
972
 
                            help='don\'t recurse into sub-directories'),
973
 
                     Option('from-root',
974
 
                            help='Print all paths from the root of the branch.'),
975
 
                     Option('unknown', help='Print unknown files'),
976
 
                     Option('versioned', help='Print versioned files'),
977
 
                     Option('ignored', help='Print ignored files'),
978
 
 
979
 
                     Option('null', help='Null separate the files'),
980
 
                    ]
981
 
    @display_command
982
 
    def run(self, revision=None, verbose=False, 
983
 
            non_recursive=False, from_root=False,
984
 
            unknown=False, versioned=False, ignored=False,
985
 
            null=False):
986
 
 
987
 
        if verbose and null:
988
 
            raise BzrCommandError('Cannot set both --verbose and --null')
989
 
        all = not (unknown or versioned or ignored)
990
 
 
991
 
        selection = {'I':ignored, '?':unknown, 'V':versioned}
992
 
 
993
 
        tree, relpath = WorkingTree.open_containing('.')
994
 
        if from_root:
995
 
            relpath = ''
996
 
        elif relpath:
997
 
            relpath += '/'
998
 
        if revision is not None:
999
 
            tree = tree.branch.revision_tree(
1000
 
                revision[0].in_history(tree.branch).rev_id)
 
791
    def run(self, revision=None, verbose=False):
 
792
        b = Branch.open_containing('.')
 
793
        if revision == None:
 
794
            tree = b.working_tree()
 
795
        else:
 
796
            tree = b.revision_tree(revision.in_history(b).rev_id)
1001
797
        for fp, fc, kind, fid, entry in tree.list_files():
1002
 
            if fp.startswith(relpath):
1003
 
                fp = fp[len(relpath):]
1004
 
                if non_recursive and '/' in fp:
1005
 
                    continue
1006
 
                if not all and not selection[fc]:
1007
 
                    continue
1008
 
                if verbose:
1009
 
                    kindch = entry.kind_character()
1010
 
                    print '%-8s %s%s' % (fc, fp, kindch)
1011
 
                elif null:
1012
 
                    sys.stdout.write(fp)
1013
 
                    sys.stdout.write('\0')
1014
 
                    sys.stdout.flush()
1015
 
                else:
1016
 
                    print fp
 
798
            if verbose:
 
799
                kindch = entry.kind_character()
 
800
                print '%-8s %s%s' % (fc, fp, kindch)
 
801
            else:
 
802
                print fp
 
803
 
1017
804
 
1018
805
 
1019
806
class cmd_unknowns(Command):
1020
807
    """List unknown files."""
1021
 
    @display_command
1022
808
    def run(self):
1023
809
        from bzrlib.osutils import quotefn
1024
 
        for f in WorkingTree.open_containing('.')[0].unknowns():
 
810
        for f in Branch.open_containing('.').unknowns():
1025
811
            print quotefn(f)
1026
812
 
1027
813
 
 
814
 
1028
815
class cmd_ignore(Command):
1029
816
    """Ignore a command or pattern.
1030
817
 
1050
837
        from bzrlib.atomicfile import AtomicFile
1051
838
        import os.path
1052
839
 
1053
 
        tree, relpath = WorkingTree.open_containing('.')
1054
 
        ifn = tree.abspath('.bzrignore')
 
840
        b = Branch.open_containing('.')
 
841
        ifn = b.abspath('.bzrignore')
1055
842
 
1056
843
        if os.path.exists(ifn):
1057
844
            f = open(ifn, 'rt')
1076
863
        finally:
1077
864
            f.close()
1078
865
 
1079
 
        inv = tree.inventory
 
866
        inv = b.working_tree().inventory
1080
867
        if inv.path2id('.bzrignore'):
1081
868
            mutter('.bzrignore is already versioned')
1082
869
        else:
1083
870
            mutter('need to make new .bzrignore file versioned')
1084
 
            tree.add(['.bzrignore'])
 
871
            b.add(['.bzrignore'])
 
872
 
1085
873
 
1086
874
 
1087
875
class cmd_ignored(Command):
1088
876
    """List ignored files and the patterns that matched them.
1089
877
 
1090
878
    See also: bzr ignore"""
1091
 
    @display_command
1092
879
    def run(self):
1093
 
        tree = WorkingTree.open_containing('.')[0]
 
880
        tree = Branch.open_containing('.').working_tree()
1094
881
        for path, file_class, kind, file_id, entry in tree.list_files():
1095
882
            if file_class != 'I':
1096
883
                continue
1108
895
    hidden = True
1109
896
    takes_args = ['revno']
1110
897
    
1111
 
    @display_command
1112
898
    def run(self, revno):
1113
899
        try:
1114
900
            revno = int(revno)
1115
901
        except ValueError:
1116
902
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1117
903
 
1118
 
        print WorkingTree.open_containing('.')[0].branch.get_rev_id(revno)
 
904
        print Branch.open_containing('.').get_rev_id(revno)
1119
905
 
1120
906
 
1121
907
class cmd_export(Command):
1128
914
    is found exports to a directory (equivalent to --format=dir).
1129
915
 
1130
916
    Root may be the top directory for tar, tgz and tbz2 formats. If none
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
 
    """
 
917
    is given, the top directory will be the root name of the file."""
 
918
    # TODO: list known exporters
1143
919
    takes_args = ['dest']
1144
920
    takes_options = ['revision', 'format', 'root']
1145
921
    def run(self, dest, revision=None, format=None, root=None):
1146
922
        import os.path
1147
 
        from bzrlib.export import export
1148
 
        tree = WorkingTree.open_containing('.')[0]
1149
 
        b = tree.branch
 
923
        b = Branch.open_containing('.')
1150
924
        if revision is None:
1151
 
            # should be tree.last_revision  FIXME
1152
925
            rev_id = b.last_revision()
1153
926
        else:
1154
927
            if len(revision) != 1:
1155
928
                raise BzrError('bzr export --revision takes exactly 1 argument')
1156
929
            rev_id = revision[0].in_history(b).rev_id
1157
930
        t = b.revision_tree(rev_id)
1158
 
        try:
1159
 
            export(t, dest, format, root)
1160
 
        except errors.NoSuchExportFormat, e:
1161
 
            raise BzrCommandError('Unsupported export format: %s' % e.format)
 
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
 
939
        if not format:
 
940
            if ext in (".tar",):
 
941
                format = "tar"
 
942
            elif ext in (".tar.gz", ".tgz"):
 
943
                format = "tgz"
 
944
            elif ext in (".tar.bz2", ".tbz2"):
 
945
                format = "tbz2"
 
946
            else:
 
947
                format = "dir"
 
948
        t.export(dest, format, root)
1162
949
 
1163
950
 
1164
951
class cmd_cat(Command):
1167
954
    takes_options = ['revision']
1168
955
    takes_args = ['filename']
1169
956
 
1170
 
    @display_command
1171
957
    def run(self, filename, revision=None):
1172
958
        if revision is None:
1173
959
            raise BzrCommandError("bzr cat requires a revision number")
1174
960
        elif len(revision) != 1:
1175
961
            raise BzrCommandError("bzr cat --revision takes exactly one number")
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)
1184
 
        b.print_file(relpath, revision[0].in_history(b).revno)
 
962
        b = Branch.open_containing('.')
 
963
        b.print_file(b.relpath(filename), revision[0].in_history(b).revno)
1185
964
 
1186
965
 
1187
966
class cmd_local_time_offset(Command):
1188
967
    """Show the offset in seconds from GMT to local time."""
1189
968
    hidden = True    
1190
 
    @display_command
1191
969
    def run(self):
1192
970
        print bzrlib.osutils.local_time_offset()
1193
971
 
1208
986
    """
1209
987
    # TODO: Run hooks on tree to-be-committed, and after commit.
1210
988
 
1211
 
    # TODO: Strict commit that fails if there are deleted files.
1212
 
    #       (what does "deleted files" mean ??)
1213
 
 
 
989
    # TODO: Strict commit that fails if there are unknown or deleted files.
1214
990
    # TODO: Give better message for -s, --summary, used by tla people
1215
991
 
1216
992
    # XXX: verbose currently does nothing
1217
993
 
1218
994
    takes_args = ['selected*']
1219
 
    takes_options = ['message', 'verbose', 
1220
 
                     Option('unchanged',
1221
 
                            help='commit even if nothing has changed'),
1222
 
                     Option('file', type=str, 
1223
 
                            argname='msgfile',
1224
 
                            help='file containing commit message'),
1225
 
                     Option('strict',
1226
 
                            help="refuse to commit if there are unknown "
1227
 
                            "files in the working tree."),
1228
 
                     ]
 
995
    takes_options = ['message', 'file', 'verbose', 'unchanged']
1229
996
    aliases = ['ci', 'checkin']
1230
997
 
1231
998
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1232
 
            unchanged=False, strict=False):
1233
 
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1234
 
                StrictCommitFailed)
 
999
            unchanged=False):
 
1000
        from bzrlib.errors import PointlessCommit, ConflictsInTree
1235
1001
        from bzrlib.msgeditor import edit_commit_message
1236
1002
        from bzrlib.status import show_status
1237
1003
        from cStringIO import StringIO
1238
1004
 
1239
 
        tree, selected_list = tree_files(selected_list)
 
1005
        b = Branch.open_containing('.')
 
1006
        if selected_list:
 
1007
            selected_list = [b.relpath(s) for s in selected_list]
 
1008
 
 
1009
            
1240
1010
        if message is None and not file:
1241
1011
            catcher = StringIO()
1242
 
            show_status(tree.branch, specific_files=selected_list,
 
1012
            show_status(b, specific_files=selected_list,
1243
1013
                        to_file=catcher)
1244
1014
            message = edit_commit_message(catcher.getvalue())
1245
1015
 
1257
1027
                raise BzrCommandError("empty commit message specified")
1258
1028
            
1259
1029
        try:
1260
 
            tree.commit(message, specific_files=selected_list,
1261
 
                        allow_pointless=unchanged, strict=strict)
 
1030
            b.commit(message,
 
1031
                     specific_files=selected_list,
 
1032
                     allow_pointless=unchanged)
1262
1033
        except PointlessCommit:
1263
1034
            # FIXME: This should really happen before the file is read in;
1264
1035
            # perhaps prepare the commit; get the message; then actually commit
1267
1038
        except ConflictsInTree:
1268
1039
            raise BzrCommandError("Conflicts detected in working tree.  "
1269
1040
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1270
 
        except StrictCommitFailed:
1271
 
            raise BzrCommandError("Commit refused because there are unknown "
1272
 
                                  "files in the working tree.")
1273
 
        note('Committed revision %d.' % (tree.branch.revno(),))
1274
 
        
 
1041
 
1275
1042
 
1276
1043
class cmd_check(Command):
1277
1044
    """Validate consistency of branch history.
1284
1051
 
1285
1052
    def run(self, dir='.', verbose=False):
1286
1053
        from bzrlib.check import check
1287
 
        check(WorkingTree.open_containing(dir)[0].branch, verbose)
 
1054
        check(Branch.open_containing(dir), verbose)
1288
1055
 
1289
1056
 
1290
1057
class cmd_scan_cache(Command):
1327
1094
    """Show bzr user id."""
1328
1095
    takes_options = ['email']
1329
1096
    
1330
 
    @display_command
1331
1097
    def run(self, email=False):
1332
1098
        try:
1333
 
            b = WorkingTree.open_containing('.')[0].branch
 
1099
            b = bzrlib.branch.Branch.open_containing('.')
1334
1100
            config = bzrlib.config.BranchConfig(b)
1335
1101
        except NotBranchError:
1336
1102
            config = bzrlib.config.GlobalConfig()
1340
1106
        else:
1341
1107
            print config.username()
1342
1108
 
1343
 
class cmd_nick(Command):
1344
 
    """\
1345
 
    Print or set the branch nickname.  
1346
 
    If unset, the tree root directory name is used as the nickname
1347
 
    To print the current nickname, execute with no argument.  
1348
 
    """
1349
 
    takes_args = ['nickname?']
1350
 
    def run(self, nickname=None):
1351
 
        branch = Branch.open_containing('.')[0]
1352
 
        if nickname is None:
1353
 
            self.printme(branch)
1354
 
        else:
1355
 
            branch.nick = nickname
1356
 
 
1357
 
    @display_command
1358
 
    def printme(self, branch):
1359
 
        print branch.nick 
1360
1109
 
1361
1110
class cmd_selftest(Command):
1362
1111
    """Run internal test suite.
1364
1113
    This creates temporary test directories in the working directory,
1365
1114
    but not existing data is affected.  These directories are deleted
1366
1115
    if the tests pass, or left behind to help in debugging if they
1367
 
    fail and --keep-output is specified.
 
1116
    fail.
1368
1117
    
1369
1118
    If arguments are given, they are regular expressions that say
1370
 
    which tests should run.
1371
 
    """
 
1119
    which tests should run."""
1372
1120
    # TODO: --list should give a list of all available tests
1373
1121
    hidden = True
1374
1122
    takes_args = ['testspecs*']
1375
 
    takes_options = ['verbose', 
1376
 
                     Option('one', help='stop when one test fails'),
1377
 
                     Option('keep-output', 
1378
 
                            help='keep output directories when tests fail')
1379
 
                    ]
1380
 
 
1381
 
    def run(self, testspecs_list=None, verbose=False, one=False,
1382
 
            keep_output=False):
 
1123
    takes_options = ['verbose']
 
1124
    def run(self, testspecs_list=None, verbose=False):
1383
1125
        import bzrlib.ui
1384
 
        from bzrlib.tests import selftest
 
1126
        from bzrlib.selftest import selftest
1385
1127
        # we don't want progress meters from the tests to go to the
1386
1128
        # real output; and we don't want log messages cluttering up
1387
1129
        # the real logs.
1394
1136
            else:
1395
1137
                pattern = ".*"
1396
1138
            result = selftest(verbose=verbose, 
1397
 
                              pattern=pattern,
1398
 
                              stop_on_failure=one, 
1399
 
                              keep_output=keep_output)
 
1139
                              pattern=pattern)
1400
1140
            if result:
1401
1141
                bzrlib.trace.info('tests passed')
1402
1142
            else:
1422
1162
 
1423
1163
class cmd_version(Command):
1424
1164
    """Show version of bzr."""
1425
 
    @display_command
1426
1165
    def run(self):
1427
1166
        show_version()
1428
1167
 
1429
1168
class cmd_rocks(Command):
1430
1169
    """Statement of optimism."""
1431
1170
    hidden = True
1432
 
    @display_command
1433
1171
    def run(self):
1434
1172
        print "it sure does!"
1435
1173
 
1442
1180
    takes_args = ['branch', 'other']
1443
1181
    hidden = True
1444
1182
    
1445
 
    @display_command
1446
1183
    def run(self, branch, other):
1447
1184
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
1448
1185
        
1449
 
        branch1 = Branch.open_containing(branch)[0]
1450
 
        branch2 = Branch.open_containing(other)[0]
 
1186
        branch1 = Branch.open_containing(branch)
 
1187
        branch2 = Branch.open_containing(other)
1451
1188
 
1452
1189
        history_1 = branch1.revision_history()
1453
1190
        history_2 = branch2.revision_history()
1502
1239
    --force is given.
1503
1240
    """
1504
1241
    takes_args = ['branch?']
1505
 
    takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1506
 
                     Option('show-base', help="Show base revision text in "
1507
 
                            "conflicts")]
 
1242
    takes_options = ['revision', 'force', 'merge-type']
1508
1243
 
1509
 
    def run(self, branch=None, revision=None, force=False, merge_type=None,
1510
 
            show_base=False, reprocess=False):
 
1244
    def run(self, branch=None, revision=None, force=False, 
 
1245
            merge_type=None):
1511
1246
        from bzrlib.merge import merge
1512
1247
        from bzrlib.merge_core import ApplyMerge3
1513
1248
        if merge_type is None:
1514
1249
            merge_type = ApplyMerge3
1515
1250
        if branch is None:
1516
 
            branch = WorkingTree.open_containing('.')[0].branch.get_parent()
 
1251
            branch = Branch.open_containing('.').get_parent()
1517
1252
            if branch is None:
1518
1253
                raise BzrCommandError("No merge location known or specified.")
1519
1254
            else:
1524
1259
        else:
1525
1260
            if len(revision) == 1:
1526
1261
                base = [None, None]
1527
 
                other_branch = Branch.open_containing(branch)[0]
1528
 
                revno = revision[0].in_history(other_branch).revno
1529
 
                other = [branch, revno]
 
1262
                other = [branch, revision[0].in_history(branch).revno]
1530
1263
            else:
1531
1264
                assert len(revision) == 2
1532
1265
                if None in revision:
1533
1266
                    raise BzrCommandError(
1534
1267
                        "Merge doesn't permit that revision specifier.")
1535
 
                b = Branch.open_containing(branch)[0]
 
1268
                b = Branch.open(branch)
1536
1269
 
1537
1270
                base = [branch, revision[0].in_history(b).revno]
1538
1271
                other = [branch, revision[1].in_history(b).revno]
1539
1272
 
1540
1273
        try:
1541
 
            conflict_count = merge(other, base, check_clean=(not force),
1542
 
                                   merge_type=merge_type, reprocess=reprocess,
1543
 
                                   show_base=show_base)
1544
 
            if conflict_count != 0:
1545
 
                return 1
1546
 
            else:
1547
 
                return 0
 
1274
            merge(other, base, check_clean=(not force), merge_type=merge_type)
1548
1275
        except bzrlib.errors.AmbiguousBase, e:
1549
1276
            m = ("sorry, bzr can't determine the right merge base yet\n"
1550
1277
                 "candidates are:\n  "
1555
1282
            log_error(m)
1556
1283
 
1557
1284
 
1558
 
class cmd_remerge(Command):
1559
 
    """Redo a merge.
1560
 
    """
1561
 
    takes_args = ['file*']
1562
 
    takes_options = ['merge-type', 'reprocess',
1563
 
                     Option('show-base', help="Show base revision text in "
1564
 
                            "conflicts")]
1565
 
 
1566
 
    def run(self, file_list=None, merge_type=None, show_base=False,
1567
 
            reprocess=False):
1568
 
        from bzrlib.merge import merge_inner, transform_tree
1569
 
        from bzrlib.merge_core import ApplyMerge3
1570
 
        if merge_type is None:
1571
 
            merge_type = ApplyMerge3
1572
 
        tree, file_list = tree_files(file_list)
1573
 
        tree.lock_write()
1574
 
        try:
1575
 
            pending_merges = tree.pending_merges() 
1576
 
            if len(pending_merges) != 1:
1577
 
                raise BzrCommandError("Sorry, remerge only works after normal"
1578
 
                                      + " merges.  Not cherrypicking or"
1579
 
                                      + "multi-merges.")
1580
 
            base_revision = common_ancestor(tree.branch.last_revision(), 
1581
 
                                            pending_merges[0], tree.branch)
1582
 
            base_tree = tree.branch.revision_tree(base_revision)
1583
 
            other_tree = tree.branch.revision_tree(pending_merges[0])
1584
 
            interesting_ids = None
1585
 
            if file_list is not None:
1586
 
                interesting_ids = set()
1587
 
                for filename in file_list:
1588
 
                    file_id = tree.path2id(filename)
1589
 
                    interesting_ids.add(file_id)
1590
 
                    if tree.kind(file_id) != "directory":
1591
 
                        continue
1592
 
                    
1593
 
                    for name, ie in tree.inventory.iter_entries(file_id):
1594
 
                        interesting_ids.add(ie.file_id)
1595
 
            transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1596
 
            if file_list is None:
1597
 
                restore_files = list(tree.iter_conflicts())
1598
 
            else:
1599
 
                restore_files = file_list
1600
 
            for filename in restore_files:
1601
 
                try:
1602
 
                    restore(tree.abspath(filename))
1603
 
                except NotConflicted:
1604
 
                    pass
1605
 
            conflicts =  merge_inner(tree.branch, other_tree, base_tree, 
1606
 
                                     interesting_ids = interesting_ids, 
1607
 
                                     other_rev_id=pending_merges[0], 
1608
 
                                     merge_type=merge_type, 
1609
 
                                     show_base=show_base,
1610
 
                                     reprocess=reprocess)
1611
 
        finally:
1612
 
            tree.unlock()
1613
 
        if conflicts > 0:
1614
 
            return 1
1615
 
        else:
1616
 
            return 0
1617
 
 
1618
1285
class cmd_revert(Command):
1619
1286
    """Reverse all changes since the last commit.
1620
1287
 
1627
1294
    aliases = ['merge-revert']
1628
1295
 
1629
1296
    def run(self, revision=None, no_backup=False, file_list=None):
1630
 
        from bzrlib.merge import merge_inner
 
1297
        from bzrlib.merge import merge
1631
1298
        from bzrlib.commands import parse_spec
 
1299
 
1632
1300
        if file_list is not None:
1633
1301
            if len(file_list) == 0:
1634
1302
                raise BzrCommandError("No files specified")
1635
 
        else:
1636
 
            file_list = []
1637
1303
        if revision is None:
1638
1304
            revno = -1
1639
 
            tree = WorkingTree.open_containing('.')[0]
1640
 
            # FIXME should be tree.last_revision
1641
 
            rev_id = tree.branch.last_revision()
1642
1305
        elif len(revision) != 1:
1643
1306
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1644
1307
        else:
1645
 
            tree, file_list = tree_files(file_list)
1646
 
            rev_id = revision[0].in_history(tree.branch).rev_id
1647
 
        tree.revert(file_list, tree.branch.revision_tree(rev_id),
1648
 
                                not no_backup)
 
1308
            b = Branch.open_containing('.')
 
1309
            revno = revision[0].in_history(b).revno
 
1310
        merge(('.', revno), parse_spec('.'),
 
1311
              check_clean=False,
 
1312
              ignore_zero=True,
 
1313
              backup_files=not no_backup,
 
1314
              file_list=file_list)
 
1315
        if not file_list:
 
1316
            Branch.open_containing('.').set_pending_merges([])
1649
1317
 
1650
1318
 
1651
1319
class cmd_assert_fail(Command):
1663
1331
    takes_args = ['topic?']
1664
1332
    aliases = ['?']
1665
1333
    
1666
 
    @display_command
1667
1334
    def run(self, topic=None, long=False):
1668
1335
        import help
1669
1336
        if topic is None and long:
1679
1346
    aliases = ['s-c']
1680
1347
    hidden = True
1681
1348
    
1682
 
    @display_command
1683
1349
    def run(self, context=None):
1684
1350
        import shellcomplete
1685
1351
        shellcomplete.shellcomplete(context)
1694
1360
    def run(self, from_branch, to_branch):
1695
1361
        from bzrlib.fetch import Fetcher
1696
1362
        from bzrlib.branch import Branch
1697
 
        from_b = Branch.open(from_branch)
1698
 
        to_b = Branch.open(to_branch)
1699
 
        from_b.lock_read()
1700
 
        try:
1701
 
            to_b.lock_write()
1702
 
            try:
1703
 
                Fetcher(to_b, from_b)
1704
 
            finally:
1705
 
                to_b.unlock()
1706
 
        finally:
1707
 
            from_b.unlock()
 
1363
        from_b = Branch(from_branch)
 
1364
        to_b = Branch(to_branch)
 
1365
        Fetcher(to_b, from_b)
 
1366
        
1708
1367
 
1709
1368
 
1710
1369
class cmd_missing(Command):
1715
1374
    
1716
1375
    takes_args = ['remote?']
1717
1376
    aliases = ['mis', 'miss']
1718
 
    takes_options = ['verbose']
 
1377
    # We don't have to add quiet to the list, because 
 
1378
    # unknown options are parsed as booleans
 
1379
    takes_options = ['verbose', 'quiet']
1719
1380
 
1720
 
    @display_command
1721
 
    def run(self, remote=None, verbose=False):
 
1381
    def run(self, remote=None, verbose=False, quiet=False):
1722
1382
        from bzrlib.errors import BzrCommandError
1723
1383
        from bzrlib.missing import show_missing
1724
1384
 
1725
 
        if verbose and is_quiet():
 
1385
        if verbose and quiet:
1726
1386
            raise BzrCommandError('Cannot pass both quiet and verbose')
1727
1387
 
1728
 
        tree = WorkingTree.open_containing('.')[0]
1729
 
        parent = tree.branch.get_parent()
 
1388
        b = Branch.open_containing('.')
 
1389
        parent = b.get_parent()
1730
1390
        if remote is None:
1731
1391
            if parent is None:
1732
1392
                raise BzrCommandError("No missing location known or specified.")
1733
1393
            else:
1734
 
                if not is_quiet():
 
1394
                if not quiet:
1735
1395
                    print "Using last location: %s" % parent
1736
1396
                remote = parent
1737
1397
        elif parent is None:
1738
1398
            # We only update parent if it did not exist, missing
1739
1399
            # should not change the parent
1740
 
            tree.branch.set_parent(remote)
1741
 
        br_remote = Branch.open_containing(remote)[0]
1742
 
        return show_missing(tree.branch, br_remote, verbose=verbose, 
1743
 
                            quiet=is_quiet())
 
1400
            b.set_parent(remote)
 
1401
        br_remote = Branch.open_containing(remote)
 
1402
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1744
1403
 
1745
1404
 
1746
1405
class cmd_plugins(Command):
1747
1406
    """List plugins"""
1748
1407
    hidden = True
1749
 
    @display_command
1750
1408
    def run(self):
1751
1409
        import bzrlib.plugin
1752
1410
        from inspect import getdoc
1767
1425
    """Show testament (signing-form) of a revision."""
1768
1426
    takes_options = ['revision', 'long']
1769
1427
    takes_args = ['branch?']
1770
 
    @display_command
1771
1428
    def run(self, branch='.', revision=None, long=False):
1772
1429
        from bzrlib.testament import Testament
1773
 
        b = WorkingTree.open_containing(branch)[0].branch
 
1430
        b = Branch.open_containing(branch)
1774
1431
        b.lock_read()
1775
1432
        try:
1776
1433
            if revision is None:
1789
1446
class cmd_annotate(Command):
1790
1447
    """Show the origin of each line in a file.
1791
1448
 
1792
 
    This prints out the given file with an annotation on the left side
1793
 
    indicating which revision, author and date introduced the change.
1794
 
 
1795
 
    If the origin is the same for a run of consecutive lines, it is 
1796
 
    shown only at the top, unless the --all option is given.
 
1449
    This prints out the given file with an annotation on the 
 
1450
    left side indicating which revision, author and date introduced the 
 
1451
    change.
1797
1452
    """
1798
1453
    # TODO: annotate directories; showing when each file was last changed
1799
1454
    # TODO: annotate a previous version of a file
1800
 
    # TODO: if the working copy is modified, show annotations on that 
1801
 
    #       with new uncommitted lines marked
1802
1455
    aliases = ['blame', 'praise']
1803
1456
    takes_args = ['filename']
1804
 
    takes_options = [Option('all', help='show annotations on all lines'),
1805
 
                     Option('long', help='show date in annotations'),
1806
 
                     ]
1807
1457
 
1808
 
    @display_command
1809
 
    def run(self, filename, all=False, long=False):
 
1458
    def run(self, filename):
1810
1459
        from bzrlib.annotate import annotate_file
1811
 
        tree, relpath = WorkingTree.open_containing(filename)
1812
 
        branch = tree.branch
1813
 
        branch.lock_read()
 
1460
        b = Branch.open_containing(filename)
 
1461
        b.lock_read()
1814
1462
        try:
1815
 
            file_id = tree.inventory.path2id(relpath)
1816
 
            tree = branch.revision_tree(branch.last_revision())
 
1463
            rp = b.relpath(filename)
 
1464
            tree = b.revision_tree(b.last_revision())
 
1465
            file_id = tree.inventory.path2id(rp)
1817
1466
            file_version = tree.inventory[file_id].revision
1818
 
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
 
1467
            annotate_file(b, file_version, file_id, sys.stdout)
1819
1468
        finally:
1820
 
            branch.unlock()
1821
 
 
1822
 
 
1823
 
class cmd_re_sign(Command):
1824
 
    """Create a digital signature for an existing revision."""
1825
 
    # TODO be able to replace existing ones.
1826
 
 
1827
 
    hidden = True # is this right ?
1828
 
    takes_args = ['revision_id?']
1829
 
    takes_options = ['revision']
1830
 
    
1831
 
    def run(self, revision_id=None, revision=None):
1832
 
        import bzrlib.config as config
1833
 
        import bzrlib.gpg as gpg
1834
 
        if revision_id is not None and revision is not None:
1835
 
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1836
 
        if revision_id is None and revision is None:
1837
 
            raise BzrCommandError('You must supply either --revision or a revision_id')
1838
 
        b = WorkingTree.open_containing('.')[0].branch
1839
 
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1840
 
        if revision_id is not None:
1841
 
            b.sign_revision(revision_id, gpg_strategy)
1842
 
        elif revision is not None:
1843
 
            if len(revision) == 1:
1844
 
                revno, rev_id = revision[0].in_history(b)
1845
 
                b.sign_revision(rev_id, gpg_strategy)
1846
 
            elif len(revision) == 2:
1847
 
                # are they both on rh- if so we can walk between them
1848
 
                # might be nice to have a range helper for arbitrary
1849
 
                # revision paths. hmm.
1850
 
                from_revno, from_revid = revision[0].in_history(b)
1851
 
                to_revno, to_revid = revision[1].in_history(b)
1852
 
                if to_revid is None:
1853
 
                    to_revno = b.revno()
1854
 
                if from_revno is None or to_revno is None:
1855
 
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1856
 
                for revno in range(from_revno, to_revno + 1):
1857
 
                    b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1858
 
            else:
1859
 
                raise BzrCommandError('Please supply either one revision, or a range.')
1860
 
 
1861
 
 
1862
 
class cmd_uncommit(bzrlib.commands.Command):
1863
 
    """Remove the last committed revision.
1864
 
 
1865
 
    By supplying the --all flag, it will not only remove the entry 
1866
 
    from revision_history, but also remove all of the entries in the
1867
 
    stores.
1868
 
 
1869
 
    --verbose will print out what is being removed.
1870
 
    --dry-run will go through all the motions, but not actually
1871
 
    remove anything.
1872
 
    
1873
 
    In the future, uncommit will create a changeset, which can then
1874
 
    be re-applied.
1875
 
    """
1876
 
    takes_options = ['all', 'verbose', 'revision',
1877
 
                    Option('dry-run', help='Don\'t actually make changes'),
1878
 
                    Option('force', help='Say yes to all questions.')]
1879
 
    takes_args = ['location?']
1880
 
    aliases = []
1881
 
 
1882
 
    def run(self, location=None, all=False,
1883
 
            dry_run=False, verbose=False,
1884
 
            revision=None, force=False):
1885
 
        from bzrlib.branch import Branch
1886
 
        from bzrlib.log import log_formatter
1887
 
        import sys
1888
 
        from bzrlib.uncommit import uncommit
1889
 
 
1890
 
        if location is None:
1891
 
            location = '.'
1892
 
        b, relpath = Branch.open_containing(location)
1893
 
 
1894
 
        if revision is None:
1895
 
            revno = b.revno()
1896
 
            rev_id = b.last_revision()
1897
 
        else:
1898
 
            revno, rev_id = revision[0].in_history(b)
1899
 
        if rev_id is None:
1900
 
            print 'No revisions to uncommit.'
1901
 
 
1902
 
        for r in range(revno, b.revno()+1):
1903
 
            rev_id = b.get_rev_id(r)
1904
 
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
1905
 
            lf.show(r, b.get_revision(rev_id), None)
1906
 
 
1907
 
        if dry_run:
1908
 
            print 'Dry-run, pretending to remove the above revisions.'
1909
 
            if not force:
1910
 
                val = raw_input('Press <enter> to continue')
1911
 
        else:
1912
 
            print 'The above revision(s) will be removed.'
1913
 
            if not force:
1914
 
                val = raw_input('Are you sure [y/N]? ')
1915
 
                if val.lower() not in ('y', 'yes'):
1916
 
                    print 'Canceled'
1917
 
                    return 0
1918
 
 
1919
 
        uncommit(b, remove_files=all,
1920
 
                dry_run=dry_run, verbose=verbose,
1921
 
                revno=revno)
1922
 
 
 
1469
            b.unlock()
1923
1470
 
1924
1471
# these get imported and then picked up by the scan for cmd_*
1925
1472
# TODO: Some more consistent way to split command definitions across files;
1926
1473
# we do need to load at least some information about them to know of 
1927
1474
# aliases.
1928
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
 
1475
from bzrlib.conflicts import cmd_resolve, cmd_conflicts