~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

Update news and readme

- better explanation of dependencies

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
 
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)
 
25
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
 
26
from bzrlib.errors import DivergedBranches
34
27
from bzrlib.option import Option
35
28
from bzrlib.revisionspec import RevisionSpec
36
29
import bzrlib.trace
37
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
 
30
from bzrlib.trace import mutter, note, log_error, warning
38
31
from bzrlib.workingtree import WorkingTree
39
32
 
40
33
 
41
 
def tree_files(file_list, default_branch=u'.'):
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=u'.'):
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 errors.PathNotChild:
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?)
71
 
 
72
34
class cmd_status(Command):
73
35
    """Display status summary.
74
36
 
109
71
    that revision, or between two revisions if two are provided.
110
72
    """
111
73
    
 
74
    # XXX: FIXME: bzr status should accept a -r option to show changes
 
75
    # relative to a revision, or between revisions
 
76
 
112
77
    # TODO: --no-recurse, --recurse options
113
78
    
114
79
    takes_args = ['file*']
115
 
    takes_options = ['all', 'show-ids', 'revision']
 
80
    takes_options = ['all', 'show-ids']
116
81
    aliases = ['st', 'stat']
117
82
    
118
 
    @display_command
119
83
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
120
 
        tree, file_list = tree_files(file_list)
 
84
        if file_list:
 
85
            b, relpath = Branch.open_containing(file_list[0])
 
86
            if relpath == '' and len(file_list) == 1:
 
87
                file_list = None
 
88
            else:
 
89
                # generate relative paths.
 
90
                # note that if this is a remote branch, we would want
 
91
                # relpath against the transport. RBC 20051018
 
92
                tree = WorkingTree(b.base, b)
 
93
                file_list = [tree.relpath(x) for x in file_list]
 
94
        else:
 
95
            b = Branch.open_containing('.')[0]
121
96
            
122
97
        from bzrlib.status import show_status
123
 
        show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
 
98
        show_status(b, show_unchanged=all, show_ids=show_ids,
124
99
                    specific_files=file_list, revision=revision)
125
100
 
126
101
 
135
110
    takes_args = ['revision_id?']
136
111
    takes_options = ['revision']
137
112
    
138
 
    @display_command
139
113
    def run(self, revision_id=None, revision=None):
140
114
 
141
115
        if revision_id is not None and revision is not None:
142
116
            raise BzrCommandError('You can only supply one of revision_id or --revision')
143
117
        if revision_id is None and revision is None:
144
118
            raise BzrCommandError('You must supply either --revision or a revision_id')
145
 
        b = WorkingTree.open_containing(u'.')[0].branch
 
119
        b = Branch.open_containing('.')[0]
146
120
        if revision_id is not None:
147
 
            sys.stdout.write(b.get_revision_xml(revision_id))
 
121
            sys.stdout.write(b.get_revision_xml_file(revision_id).read())
148
122
        elif revision is not None:
149
123
            for rev in revision:
150
124
                if rev is None:
151
125
                    raise BzrCommandError('You cannot specify a NULL revision.')
152
126
                revno, rev_id = rev.in_history(b)
153
 
                sys.stdout.write(b.get_revision_xml(rev_id))
 
127
                sys.stdout.write(b.get_revision_xml_file(rev_id).read())
154
128
    
155
129
 
156
130
class cmd_revno(Command):
157
131
    """Show current revision number.
158
132
 
159
133
    This is equal to the number of revisions on this branch."""
160
 
    takes_args = ['location?']
161
 
    @display_command
162
 
    def run(self, location=u'.'):
163
 
        print Branch.open_containing(location)[0].revno()
 
134
    def run(self):
 
135
        print Branch.open_containing('.')[0].revno()
164
136
 
165
137
 
166
138
class cmd_revision_info(Command):
169
141
    hidden = True
170
142
    takes_args = ['revision_info*']
171
143
    takes_options = ['revision']
172
 
    @display_command
173
144
    def run(self, revision=None, revision_info_list=[]):
174
145
 
175
146
        revs = []
181
152
        if len(revs) == 0:
182
153
            raise BzrCommandError('You must supply a revision identifier')
183
154
 
184
 
        b = WorkingTree.open_containing(u'.')[0].branch
 
155
        b = Branch.open_containing('.')[0]
185
156
 
186
157
        for rev in revs:
187
158
            revinfo = rev.in_history(b)
215
186
    get added when you add a file in the directory.
216
187
    """
217
188
    takes_args = ['file*']
218
 
    takes_options = ['no-recurse']
 
189
    takes_options = ['no-recurse', 'quiet']
219
190
    
220
 
    def run(self, file_list, no_recurse=False):
 
191
    def run(self, file_list, no_recurse=False, quiet=False):
221
192
        from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
222
 
        if is_quiet():
 
193
        if quiet:
223
194
            reporter = add_reporter_null
224
195
        else:
225
196
            reporter = add_reporter_print
234
205
    takes_args = ['dir+']
235
206
 
236
207
    def run(self, dir_list):
 
208
        b = None
 
209
        
237
210
        for d in dir_list:
238
211
            os.mkdir(d)
239
 
            wt, dd = WorkingTree.open_containing(d)
240
 
            wt.add([dd])
 
212
            if not b:
 
213
                b = Branch.open_containing(d)[0]
 
214
            b.add([d])
241
215
            print 'added', d
242
216
 
243
217
 
246
220
    takes_args = ['filename']
247
221
    hidden = True
248
222
    
249
 
    @display_command
250
223
    def run(self, filename):
251
 
        tree, relpath = WorkingTree.open_containing(filename)
 
224
        branch, relpath = Branch.open_containing(filename)
252
225
        print relpath
253
226
 
254
227
 
255
228
class cmd_inventory(Command):
256
 
    """Show inventory of the current working copy or a revision.
257
 
 
258
 
    It is possible to limit the output to a particular entry
259
 
    type using the --kind option.  For example; --kind file.
260
 
    """
261
 
    takes_options = ['revision', 'show-ids', 'kind']
 
229
    """Show inventory of the current working copy or a revision."""
 
230
    takes_options = ['revision', 'show-ids']
262
231
    
263
 
    @display_command
264
 
    def run(self, revision=None, show_ids=False, kind=None):
265
 
        if kind and kind not in ['file', 'directory', 'symlink']:
266
 
            raise BzrCommandError('invalid kind specified')
267
 
        tree = WorkingTree.open_containing(u'.')[0]
 
232
    def run(self, revision=None, show_ids=False):
 
233
        b = Branch.open_containing('.')[0]
268
234
        if revision is None:
269
 
            inv = tree.read_working_inventory()
 
235
            inv = b.read_working_inventory()
270
236
        else:
271
237
            if len(revision) > 1:
272
238
                raise BzrCommandError('bzr inventory --revision takes'
273
239
                    ' exactly one revision identifier')
274
 
            inv = tree.branch.get_revision_inventory(
275
 
                revision[0].in_history(tree.branch).rev_id)
 
240
            inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
276
241
 
277
242
        for path, entry in inv.entries():
278
 
            if kind and kind != entry.kind:
279
 
                continue
280
243
            if show_ids:
281
244
                print '%-50s %s' % (path, entry.file_id)
282
245
            else:
293
256
    """
294
257
    takes_args = ['source$', 'dest']
295
258
    def run(self, source_list, dest):
296
 
        tree, source_list = tree_files(source_list)
 
259
        b = Branch.open_containing('.')[0]
 
260
 
297
261
        # TODO: glob expansion on windows?
298
 
        tree.move(source_list, tree.relpath(dest))
 
262
        tree = WorkingTree(b.base, b)
 
263
        b.move([tree.relpath(s) for s in source_list], tree.relpath(dest))
299
264
 
300
265
 
301
266
class cmd_rename(Command):
315
280
    takes_args = ['from_name', 'to_name']
316
281
    
317
282
    def run(self, from_name, to_name):
318
 
        tree, (from_name, to_name) = tree_files((from_name, to_name))
319
 
        tree.rename_one(from_name, to_name)
 
283
        b = Branch.open_containing('.')[0]
 
284
        tree = WorkingTree(b.base, b)
 
285
        b.rename_one(tree.relpath(from_name), tree.relpath(to_name))
320
286
 
321
287
 
322
288
class cmd_mv(Command):
336
302
    def run(self, names_list):
337
303
        if len(names_list) < 2:
338
304
            raise BzrCommandError("missing file argument")
339
 
        tree, rel_names = tree_files(names_list)
 
305
        b = Branch.open_containing(names_list[0])[0]
 
306
        tree = WorkingTree(b.base, b)
 
307
        rel_names = [tree.relpath(x) for x in names_list]
340
308
        
341
309
        if os.path.isdir(names_list[-1]):
342
310
            # move into existing directory
343
 
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
 
311
            for pair in b.move(rel_names[:-1], rel_names[-1]):
344
312
                print "%s => %s" % pair
345
313
        else:
346
314
            if len(names_list) != 2:
347
315
                raise BzrCommandError('to mv multiple files the destination '
348
316
                                      'must be a versioned directory')
349
 
            tree.rename_one(rel_names[0], rel_names[1])
 
317
            b.rename_one(rel_names[0], rel_names[1])
350
318
            print "%s => %s" % (rel_names[0], rel_names[1])
351
319
            
352
320
    
 
321
 
 
322
 
353
323
class cmd_pull(Command):
354
324
    """Pull any changes from another branch into the current one.
355
325
 
356
 
    If there is no default location set, the first pull will set it.  After
357
 
    that, you can omit the location to use the default.  To change the
358
 
    default, use --remember.
 
326
    If the location is omitted, the last-used location will be used.
 
327
    Both the revision history and the working directory will be
 
328
    updated.
359
329
 
360
330
    This command only works on branches that have not diverged.  Branches are
361
331
    considered diverged if both branches have had commits without first
362
332
    pulling from the other.
363
333
 
364
334
    If branches have diverged, you can use 'bzr merge' to pull the text changes
365
 
    from one into the other.  Once one branch has merged, the other should
366
 
    be able to pull it again.
367
 
 
368
 
    If you want to forget your local changes and just update your branch to
369
 
    match the remote one, use --overwrite.
 
335
    from one into the other.
370
336
    """
371
 
    takes_options = ['remember', 'overwrite', 'verbose']
 
337
    takes_options = ['remember']
372
338
    takes_args = ['location?']
373
339
 
374
 
    def run(self, location=None, remember=False, overwrite=False, verbose=False):
 
340
    def run(self, location=None, remember=False):
375
341
        from bzrlib.merge import merge
 
342
        import tempfile
376
343
        from shutil import rmtree
377
344
        import errno
378
 
        # FIXME: too much stuff is in the command class        
379
 
        tree_to = WorkingTree.open_containing(u'.')[0]
380
 
        stored_loc = tree_to.branch.get_parent()
 
345
        
 
346
        br_to = Branch.open_containing('.')[0]
 
347
        stored_loc = br_to.get_parent()
381
348
        if location is None:
382
349
            if stored_loc is None:
383
350
                raise BzrCommandError("No pull location known or specified.")
384
351
            else:
385
352
                print "Using saved location: %s" % stored_loc
386
353
                location = stored_loc
387
 
 
 
354
        cache_root = tempfile.mkdtemp()
388
355
        br_from = Branch.open(location)
389
 
        br_to = tree_to.branch
390
 
 
391
 
        old_rh = br_to.revision_history()
392
 
        count = tree_to.pull(br_from, overwrite)
393
 
 
394
 
        if br_to.get_parent() is None or remember:
395
 
            br_to.set_parent(location)
396
 
        note('%d revision(s) pulled.' % (count,))
397
 
 
398
 
        if verbose:
399
 
            new_rh = tree_to.branch.revision_history()
400
 
            if old_rh != new_rh:
401
 
                # Something changed
402
 
                from bzrlib.log import show_changed_revisions
403
 
                show_changed_revisions(tree_to.branch, old_rh, new_rh)
404
 
 
405
 
 
406
 
class cmd_push(Command):
407
 
    """Push this branch into another branch.
408
 
    
409
 
    The remote branch will not have its working tree populated because this
410
 
    is both expensive, and may not be supported on the remote file system.
411
 
    
412
 
    Some smart servers or protocols *may* put the working tree in place.
413
 
 
414
 
    If there is no default push location set, the first push will set it.
415
 
    After that, you can omit the location to use the default.  To change the
416
 
    default, use --remember.
417
 
 
418
 
    This command only works on branches that have not diverged.  Branches are
419
 
    considered diverged if the branch being pushed to is not an older version
420
 
    of this branch.
421
 
 
422
 
    If branches have diverged, you can use 'bzr push --overwrite' to replace
423
 
    the other branch completely.
424
 
    
425
 
    If you want to ensure you have the different changes in the other branch,
426
 
    do a merge (see bzr help merge) from the other branch, and commit that
427
 
    before doing a 'push --overwrite'.
428
 
    """
429
 
    takes_options = ['remember', 'overwrite', 
430
 
                     Option('create-prefix', 
431
 
                            help='Create the path leading up to the branch '
432
 
                                 'if it does not already exist')]
433
 
    takes_args = ['location?']
434
 
 
435
 
    def run(self, location=None, remember=False, overwrite=False,
436
 
            create_prefix=False, verbose=False):
437
 
        # FIXME: Way too big!  Put this into a function called from the
438
 
        # command.
439
 
        import errno
440
 
        from shutil import rmtree
441
 
        from bzrlib.transport import get_transport
442
 
        
443
 
        tree_from = WorkingTree.open_containing(u'.')[0]
444
 
        br_from = tree_from.branch
445
 
        stored_loc = tree_from.branch.get_push_location()
446
 
        if location is None:
447
 
            if stored_loc is None:
448
 
                raise BzrCommandError("No push location known or specified.")
449
 
            else:
450
 
                print "Using saved location: %s" % stored_loc
451
 
                location = stored_loc
452
 
        try:
453
 
            br_to = Branch.open(location)
454
 
        except NotBranchError:
455
 
            # create a branch.
456
 
            transport = get_transport(location).clone('..')
457
 
            if not create_prefix:
458
 
                try:
459
 
                    transport.mkdir(transport.relpath(location))
460
 
                except NoSuchFile:
461
 
                    raise BzrCommandError("Parent directory of %s "
462
 
                                          "does not exist." % location)
463
 
            else:
464
 
                current = transport.base
465
 
                needed = [(transport, transport.relpath(location))]
466
 
                while needed:
467
 
                    try:
468
 
                        transport, relpath = needed[-1]
469
 
                        transport.mkdir(relpath)
470
 
                        needed.pop()
471
 
                    except NoSuchFile:
472
 
                        new_transport = transport.clone('..')
473
 
                        needed.append((new_transport,
474
 
                                       new_transport.relpath(transport.base)))
475
 
                        if new_transport.base == transport.base:
476
 
                            raise BzrCommandError("Could not creeate "
477
 
                                                  "path prefix.")
478
 
            br_to = Branch.initialize(location)
479
 
        old_rh = br_to.revision_history()
480
 
        try:
 
356
        br_from.lock_read()
 
357
        try:
 
358
            br_from.setup_caching(cache_root)
 
359
            location = br_from.base
 
360
            old_revno = br_to.revno()
 
361
            old_revision_history = br_to.revision_history()
481
362
            try:
482
 
                tree_to = br_to.working_tree()
483
 
            except NoWorkingTree:
484
 
                # TODO: This should be updated for branches which don't have a
485
 
                # working tree, as opposed to ones where we just couldn't 
486
 
                # update the tree.
487
 
                warning('Unable to update the working tree of: %s' % (br_to.base,))
488
 
                count = br_to.pull(br_from, overwrite)
489
 
            else:
490
 
                count = tree_to.pull(br_from, overwrite)
491
 
        except DivergedBranches:
492
 
            raise BzrCommandError("These branches have diverged."
493
 
                                  "  Try a merge then push with overwrite.")
494
 
        if br_from.get_push_location() is None or remember:
495
 
            br_from.set_push_location(location)
496
 
        note('%d revision(s) pushed.' % (count,))
 
363
                br_to.update_revisions(br_from)
 
364
            except DivergedBranches:
 
365
                raise BzrCommandError("These branches have diverged."
 
366
                    "  Try merge.")
 
367
            new_revision_history = br_to.revision_history()
 
368
            if new_revision_history != old_revision_history:
 
369
                merge(('.', -1), ('.', old_revno), check_clean=False)
 
370
            if stored_loc is None or remember:
 
371
                br_to.set_parent(location)
 
372
        finally:
 
373
            br_from.unlock()
 
374
            rmtree(cache_root)
497
375
 
498
 
        if verbose:
499
 
            new_rh = br_to.revision_history()
500
 
            if old_rh != new_rh:
501
 
                # Something changed
502
 
                from bzrlib.log import show_changed_revisions
503
 
                show_changed_revisions(br_to, old_rh, new_rh)
504
376
 
505
377
 
506
378
class cmd_branch(Command):
522
394
 
523
395
    def run(self, from_location, to_location=None, revision=None, basis=None):
524
396
        from bzrlib.clone import copy_branch
 
397
        import tempfile
525
398
        import errno
526
399
        from shutil import rmtree
 
400
        cache_root = tempfile.mkdtemp()
527
401
        if revision is None:
528
402
            revision = [None]
529
403
        elif len(revision) > 1:
539
413
                raise
540
414
        br_from.lock_read()
541
415
        try:
 
416
            br_from.setup_caching(cache_root)
542
417
            if basis is not None:
543
 
                basis_branch = WorkingTree.open_containing(basis)[0].branch
 
418
                basis_branch = Branch.open_containing(basis)[0]
544
419
            else:
545
420
                basis_branch = None
546
421
            if len(revision) == 1 and revision[0] is not None:
549
424
                revision_id = None
550
425
            if to_location is None:
551
426
                to_location = os.path.basename(from_location.rstrip("/\\"))
552
 
                name = None
553
 
            else:
554
 
                name = os.path.basename(to_location) + '\n'
555
427
            try:
556
428
                os.mkdir(to_location)
557
429
            except OSError, e:
567
439
                copy_branch(br_from, to_location, revision_id, basis_branch)
568
440
            except bzrlib.errors.NoSuchRevision:
569
441
                rmtree(to_location)
570
 
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
 
442
                msg = "The branch %s has no revision %d." % (from_location, revision[0])
571
443
                raise BzrCommandError(msg)
572
444
            except bzrlib.errors.UnlistableBranch:
573
 
                rmtree(to_location)
574
445
                msg = "The branch %s cannot be used as a --basis"
575
 
                raise BzrCommandError(msg)
576
 
            branch = Branch.open(to_location)
577
 
            if name:
578
 
                name = StringIO(name)
579
 
                branch.put_controlfile('branch-name', name)
580
 
            note('Branched %d revision(s).' % branch.revno())
581
446
        finally:
582
447
            br_from.unlock()
 
448
            rmtree(cache_root)
583
449
 
584
450
 
585
451
class cmd_renames(Command):
590
456
    # TODO: Only show renames under dir, rather than in the whole branch.
591
457
    takes_args = ['dir?']
592
458
 
593
 
    @display_command
594
 
    def run(self, dir=u'.'):
595
 
        tree = WorkingTree.open_containing(dir)[0]
596
 
        old_inv = tree.branch.basis_tree().inventory
597
 
        new_inv = tree.read_working_inventory()
 
459
    def run(self, dir='.'):
 
460
        b = Branch.open_containing(dir)[0]
 
461
        old_inv = b.basis_tree().inventory
 
462
        new_inv = b.read_working_inventory()
598
463
 
599
464
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
600
465
        renames.sort()
606
471
    """Show statistical information about a branch."""
607
472
    takes_args = ['branch?']
608
473
    
609
 
    @display_command
610
474
    def run(self, branch=None):
611
475
        import info
612
 
        b = WorkingTree.open_containing(branch)[0].branch
 
476
        b = Branch.open_containing(branch)[0]
613
477
        info.show_info(b)
614
478
 
615
479
 
624
488
    aliases = ['rm']
625
489
    
626
490
    def run(self, file_list, verbose=False):
627
 
        tree, file_list = tree_files(file_list)
628
 
        tree.remove(file_list, verbose=verbose)
 
491
        b = Branch.open_containing(file_list[0])[0]
 
492
        tree = WorkingTree(b.base, b)
 
493
        tree.remove([tree.relpath(f) for f in file_list], verbose=verbose)
629
494
 
630
495
 
631
496
class cmd_file_id(Command):
637
502
    """
638
503
    hidden = True
639
504
    takes_args = ['filename']
640
 
    @display_command
641
505
    def run(self, filename):
642
 
        tree, relpath = WorkingTree.open_containing(filename)
643
 
        i = tree.inventory.path2id(relpath)
 
506
        b, relpath = Branch.open_containing(filename)
 
507
        i = b.inventory.path2id(relpath)
644
508
        if i == None:
645
509
            raise BzrError("%r is not a versioned file" % filename)
646
510
        else:
654
518
    starting at the branch root."""
655
519
    hidden = True
656
520
    takes_args = ['filename']
657
 
    @display_command
658
521
    def run(self, filename):
659
 
        tree, relpath = WorkingTree.open_containing(filename)
660
 
        inv = tree.inventory
 
522
        b, relpath = Branch.open_containing(filename)
 
523
        inv = b.inventory
661
524
        fid = inv.path2id(relpath)
662
525
        if fid == None:
663
526
            raise BzrError("%r is not a versioned file" % filename)
668
531
class cmd_revision_history(Command):
669
532
    """Display list of revision ids on this branch."""
670
533
    hidden = True
671
 
    @display_command
672
534
    def run(self):
673
 
        branch = WorkingTree.open_containing(u'.')[0].branch
674
 
        for patchid in branch.revision_history():
 
535
        for patchid in Branch.open_containing('.')[0].revision_history():
675
536
            print patchid
676
537
 
677
538
 
678
539
class cmd_ancestry(Command):
679
540
    """List all revisions merged into this branch."""
680
541
    hidden = True
681
 
    @display_command
682
542
    def run(self):
683
 
        tree = WorkingTree.open_containing(u'.')[0]
684
 
        b = tree.branch
685
 
        # FIXME. should be tree.last_revision
 
543
        b = find_branch('.')
686
544
        for revision_id in b.get_ancestry(b.last_revision()):
687
545
            print revision_id
688
546
 
689
547
 
 
548
class cmd_directories(Command):
 
549
    """Display list of versioned directories in this branch."""
 
550
    def run(self):
 
551
        for name, ie in Branch.open_containing('.')[0].read_working_inventory().directories():
 
552
            if name == '':
 
553
                print '.'
 
554
            else:
 
555
                print name
 
556
 
 
557
 
690
558
class cmd_init(Command):
691
559
    """Make a directory into a versioned branch.
692
560
 
696
564
    Recipe for importing a tree of files:
697
565
        cd ~/project
698
566
        bzr init
699
 
        bzr add .
 
567
        bzr add -v .
700
568
        bzr status
701
569
        bzr commit -m 'imported project'
702
570
    """
703
 
    takes_args = ['location?']
704
 
    def run(self, location=None):
705
 
        from bzrlib.branch import Branch
706
 
        if location is None:
707
 
            location = u'.'
708
 
        else:
709
 
            # The path has to exist to initialize a
710
 
            # branch inside of it.
711
 
            # Just using os.mkdir, since I don't
712
 
            # believe that we want to create a bunch of
713
 
            # locations if the user supplies an extended path
714
 
            if not os.path.exists(location):
715
 
                os.mkdir(location)
716
 
        Branch.initialize(location)
 
571
    def run(self):
 
572
        Branch.initialize('.')
717
573
 
718
574
 
719
575
class cmd_diff(Command):
745
601
    takes_options = ['revision', 'diff-options']
746
602
    aliases = ['di', 'dif']
747
603
 
748
 
    @display_command
749
604
    def run(self, revision=None, file_list=None, diff_options=None):
750
605
        from bzrlib.diff import show_diff
751
 
        try:
752
 
            tree, file_list = internal_tree_files(file_list)
753
 
            b = None
754
 
            b2 = None
755
 
        except FileInWrongBranch:
756
 
            if len(file_list) != 2:
757
 
                raise BzrCommandError("Files are in different branches")
758
 
 
759
 
            b, file1 = Branch.open_containing(file_list[0])
760
 
            b2, file2 = Branch.open_containing(file_list[1])
761
 
            if file1 != "" or file2 != "":
762
 
                # FIXME diff those two files. rbc 20051123
763
 
                raise BzrCommandError("Files are in different branches")
764
 
            file_list = None
 
606
 
 
607
        if file_list:
 
608
            b = Branch.open_containing(file_list[0])[0]
 
609
            tree = WorkingTree(b.base, b)
 
610
            file_list = [tree.relpath(f) for f in file_list]
 
611
            if file_list == ['']:
 
612
                # just pointing to top-of-tree
 
613
                file_list = None
 
614
        else:
 
615
            b = Branch.open_containing('.')[0]
 
616
 
765
617
        if revision is not None:
766
 
            if b2 is not None:
767
 
                raise BzrCommandError("Can't specify -r with two branches")
768
618
            if len(revision) == 1:
769
 
                return show_diff(tree.branch, revision[0], specific_files=file_list,
770
 
                                 external_diff_options=diff_options)
 
619
                show_diff(b, revision[0], specific_files=file_list,
 
620
                          external_diff_options=diff_options)
771
621
            elif len(revision) == 2:
772
 
                return show_diff(tree.branch, revision[0], specific_files=file_list,
773
 
                                 external_diff_options=diff_options,
774
 
                                 revision2=revision[1])
 
622
                show_diff(b, revision[0], specific_files=file_list,
 
623
                          external_diff_options=diff_options,
 
624
                          revision2=revision[1])
775
625
            else:
776
626
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
777
627
        else:
778
 
            if b is not None:
779
 
                return show_diff(b, None, specific_files=file_list,
780
 
                                 external_diff_options=diff_options, b2=b2)
781
 
            else:
782
 
                return show_diff(tree.branch, None, specific_files=file_list,
783
 
                                 external_diff_options=diff_options)
 
628
            show_diff(b, None, specific_files=file_list,
 
629
                      external_diff_options=diff_options)
 
630
 
 
631
        
784
632
 
785
633
 
786
634
class cmd_deleted(Command):
792
640
    # directories with readdir, rather than stating each one.  Same
793
641
    # level of effort but possibly much less IO.  (Or possibly not,
794
642
    # if the directories are very large...)
795
 
    @display_command
796
643
    def run(self, show_ids=False):
797
 
        tree = WorkingTree.open_containing(u'.')[0]
798
 
        old = tree.branch.basis_tree()
 
644
        b = Branch.open_containing('.')[0]
 
645
        old = b.basis_tree()
 
646
        new = b.working_tree()
799
647
        for path, ie in old.inventory.iter_entries():
800
 
            if not tree.has_id(ie.file_id):
 
648
            if not new.has_id(ie.file_id):
801
649
                if show_ids:
802
650
                    print '%-50s %s' % (path, ie.file_id)
803
651
                else:
807
655
class cmd_modified(Command):
808
656
    """List files modified in working tree."""
809
657
    hidden = True
810
 
    @display_command
811
658
    def run(self):
812
659
        from bzrlib.delta import compare_trees
813
660
 
814
 
        tree = WorkingTree.open_containing(u'.')[0]
815
 
        td = compare_trees(tree.branch.basis_tree(), tree)
 
661
        b = Branch.open_containing('.')[0]
 
662
        td = compare_trees(b.basis_tree(), b.working_tree())
816
663
 
817
664
        for path, id, kind, text_modified, meta_modified in td.modified:
818
665
            print path
822
669
class cmd_added(Command):
823
670
    """List files added in working tree."""
824
671
    hidden = True
825
 
    @display_command
826
672
    def run(self):
827
 
        wt = WorkingTree.open_containing(u'.')[0]
828
 
        basis_inv = wt.branch.basis_tree().inventory
 
673
        b = Branch.open_containing('.')[0]
 
674
        wt = b.working_tree()
 
675
        basis_inv = b.basis_tree().inventory
829
676
        inv = wt.inventory
830
677
        for file_id in inv:
831
678
            if file_id in basis_inv:
843
690
    The root is the nearest enclosing directory with a .bzr control
844
691
    directory."""
845
692
    takes_args = ['filename?']
846
 
    @display_command
847
693
    def run(self, filename=None):
848
694
        """Print the branch root."""
849
 
        tree = WorkingTree.open_containing(filename)[0]
850
 
        print tree.basedir
 
695
        b = Branch.open_containing(filename)[0]
 
696
        print b.base
851
697
 
852
698
 
853
699
class cmd_log(Command):
854
700
    """Show log of this branch.
855
701
 
856
 
    To request a range of logs, you can use the command -r begin..end
857
 
    -r revision requests a specific revision, -r ..end or -r begin.. are
 
702
    To request a range of logs, you can use the command -r begin:end
 
703
    -r revision requests a specific revision, -r :end or -r begin: are
858
704
    also valid.
859
705
    """
860
706
 
872
718
                            type=str),
873
719
                     Option('short', help='use moderately short format'),
874
720
                     ]
875
 
    @display_command
 
721
    
876
722
    def run(self, filename=None, timezone='original',
877
723
            verbose=False,
878
724
            show_ids=False,
889
735
        direction = (forward and 'forward') or 'reverse'
890
736
        
891
737
        if filename:
892
 
            # might be a tree:
893
 
            tree = None
894
 
            try:
895
 
                tree, fp = WorkingTree.open_containing(filename)
896
 
                b = tree.branch
897
 
                if fp != '':
898
 
                    inv = tree.read_working_inventory()
899
 
            except NotBranchError:
900
 
                pass
901
 
            if tree is None:
902
 
                b, fp = Branch.open_containing(filename)
903
 
                if fp != '':
904
 
                    inv = b.get_inventory(b.last_revision())
 
738
            b, fp = Branch.open_containing(filename)
905
739
            if fp != '':
906
 
                file_id = inv.path2id(fp)
 
740
                file_id = b.read_working_inventory().path2id(fp)
907
741
            else:
908
742
                file_id = None  # points to branch root
909
743
        else:
910
 
            tree, relpath = WorkingTree.open_containing(u'.')
911
 
            b = tree.branch
 
744
            b, relpath = Branch.open_containing('.')
912
745
            file_id = None
913
746
 
914
747
        if revision is None:
922
755
        else:
923
756
            raise BzrCommandError('bzr log --revision takes one or two values.')
924
757
 
925
 
        # By this point, the revision numbers are converted to the +ve
926
 
        # form if they were supplied in the -ve form, so we can do
927
 
        # this comparison in relative safety
928
 
        if rev1 > rev2:
929
 
            (rev2, rev1) = (rev1, rev2)
 
758
        if rev1 == 0:
 
759
            rev1 = None
 
760
        if rev2 == 0:
 
761
            rev2 = None
930
762
 
931
 
        mutter('encoding log as %r', bzrlib.user_encoding)
 
763
        mutter('encoding log as %r' % bzrlib.user_encoding)
932
764
 
933
765
        # use 'replace' so that we don't abort if trying to write out
934
766
        # in e.g. the default C locale.
961
793
    A more user-friendly interface is "bzr log FILE"."""
962
794
    hidden = True
963
795
    takes_args = ["filename"]
964
 
    @display_command
965
796
    def run(self, filename):
966
 
        tree, relpath = WorkingTree.open_containing(filename)
967
 
        b = tree.branch
968
 
        inv = tree.read_working_inventory()
 
797
        b, relpath = Branch.open_containing(filename)[0]
 
798
        inv = b.read_working_inventory()
969
799
        file_id = inv.path2id(relpath)
970
800
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
971
801
            print "%6d %s" % (revno, what)
976
806
    """
977
807
    # TODO: Take a revision or remote path and list that tree instead.
978
808
    hidden = True
979
 
    takes_options = ['verbose', 'revision',
980
 
                     Option('non-recursive',
981
 
                            help='don\'t recurse into sub-directories'),
982
 
                     Option('from-root',
983
 
                            help='Print all paths from the root of the branch.'),
984
 
                     Option('unknown', help='Print unknown files'),
985
 
                     Option('versioned', help='Print versioned files'),
986
 
                     Option('ignored', help='Print ignored files'),
987
 
 
988
 
                     Option('null', help='Null separate the files'),
989
 
                    ]
990
 
    @display_command
991
 
    def run(self, revision=None, verbose=False, 
992
 
            non_recursive=False, from_root=False,
993
 
            unknown=False, versioned=False, ignored=False,
994
 
            null=False):
995
 
 
996
 
        if verbose and null:
997
 
            raise BzrCommandError('Cannot set both --verbose and --null')
998
 
        all = not (unknown or versioned or ignored)
999
 
 
1000
 
        selection = {'I':ignored, '?':unknown, 'V':versioned}
1001
 
 
1002
 
        tree, relpath = WorkingTree.open_containing(u'.')
1003
 
        if from_root:
1004
 
            relpath = u''
1005
 
        elif relpath:
1006
 
            relpath += '/'
1007
 
        if revision is not None:
1008
 
            tree = tree.branch.revision_tree(
1009
 
                revision[0].in_history(tree.branch).rev_id)
 
809
    def run(self, revision=None, verbose=False):
 
810
        b, relpath = Branch.open_containing('.')[0]
 
811
        if revision == None:
 
812
            tree = b.working_tree()
 
813
        else:
 
814
            tree = b.revision_tree(revision.in_history(b).rev_id)
1010
815
        for fp, fc, kind, fid, entry in tree.list_files():
1011
 
            if fp.startswith(relpath):
1012
 
                fp = fp[len(relpath):]
1013
 
                if non_recursive and '/' in fp:
1014
 
                    continue
1015
 
                if not all and not selection[fc]:
1016
 
                    continue
1017
 
                if verbose:
1018
 
                    kindch = entry.kind_character()
1019
 
                    print '%-8s %s%s' % (fc, fp, kindch)
1020
 
                elif null:
1021
 
                    sys.stdout.write(fp)
1022
 
                    sys.stdout.write('\0')
1023
 
                    sys.stdout.flush()
1024
 
                else:
1025
 
                    print fp
 
816
            if verbose:
 
817
                kindch = entry.kind_character()
 
818
                print '%-8s %s%s' % (fc, fp, kindch)
 
819
            else:
 
820
                print fp
 
821
 
1026
822
 
1027
823
 
1028
824
class cmd_unknowns(Command):
1029
825
    """List unknown files."""
1030
 
    @display_command
1031
826
    def run(self):
1032
827
        from bzrlib.osutils import quotefn
1033
 
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
828
        for f in Branch.open_containing('.')[0].unknowns():
1034
829
            print quotefn(f)
1035
830
 
1036
831
 
 
832
 
1037
833
class cmd_ignore(Command):
1038
834
    """Ignore a command or pattern.
1039
835
 
1059
855
        from bzrlib.atomicfile import AtomicFile
1060
856
        import os.path
1061
857
 
1062
 
        tree, relpath = WorkingTree.open_containing(u'.')
1063
 
        ifn = tree.abspath('.bzrignore')
 
858
        b, relpath = Branch.open_containing('.')
 
859
        ifn = b.abspath('.bzrignore')
1064
860
 
1065
861
        if os.path.exists(ifn):
1066
862
            f = open(ifn, 'rt')
1085
881
        finally:
1086
882
            f.close()
1087
883
 
1088
 
        inv = tree.inventory
 
884
        inv = b.working_tree().inventory
1089
885
        if inv.path2id('.bzrignore'):
1090
886
            mutter('.bzrignore is already versioned')
1091
887
        else:
1092
888
            mutter('need to make new .bzrignore file versioned')
1093
 
            tree.add(['.bzrignore'])
 
889
            b.add(['.bzrignore'])
 
890
 
1094
891
 
1095
892
 
1096
893
class cmd_ignored(Command):
1097
894
    """List ignored files and the patterns that matched them.
1098
895
 
1099
896
    See also: bzr ignore"""
1100
 
    @display_command
1101
897
    def run(self):
1102
 
        tree = WorkingTree.open_containing(u'.')[0]
 
898
        tree = Branch.open_containing('.')[0].working_tree()
1103
899
        for path, file_class, kind, file_id, entry in tree.list_files():
1104
900
            if file_class != 'I':
1105
901
                continue
1117
913
    hidden = True
1118
914
    takes_args = ['revno']
1119
915
    
1120
 
    @display_command
1121
916
    def run(self, revno):
1122
917
        try:
1123
918
            revno = int(revno)
1124
919
        except ValueError:
1125
920
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1126
921
 
1127
 
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
922
        print Branch.open_containing('.')[0].get_rev_id(revno)
1128
923
 
1129
924
 
1130
925
class cmd_export(Command):
1137
932
    is found exports to a directory (equivalent to --format=dir).
1138
933
 
1139
934
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1140
 
    is given, the top directory will be the root name of the file.
1141
 
 
1142
 
    Note: export of tree with non-ascii filenames to zip is not supported.
1143
 
 
1144
 
    Supported formats       Autodetected by extension
1145
 
    -----------------       -------------------------
1146
 
         dir                            -
1147
 
         tar                          .tar
1148
 
         tbz2                    .tar.bz2, .tbz2
1149
 
         tgz                      .tar.gz, .tgz
1150
 
         zip                          .zip
1151
 
    """
 
935
    is given, the top directory will be the root name of the file."""
 
936
    # TODO: list known exporters
1152
937
    takes_args = ['dest']
1153
938
    takes_options = ['revision', 'format', 'root']
1154
939
    def run(self, dest, revision=None, format=None, root=None):
1155
940
        import os.path
1156
 
        from bzrlib.export import export
1157
 
        tree = WorkingTree.open_containing(u'.')[0]
1158
 
        b = tree.branch
 
941
        b = Branch.open_containing('.')[0]
1159
942
        if revision is None:
1160
 
            # should be tree.last_revision  FIXME
1161
943
            rev_id = b.last_revision()
1162
944
        else:
1163
945
            if len(revision) != 1:
1164
946
                raise BzrError('bzr export --revision takes exactly 1 argument')
1165
947
            rev_id = revision[0].in_history(b).rev_id
1166
948
        t = b.revision_tree(rev_id)
1167
 
        try:
1168
 
            export(t, dest, format, root)
1169
 
        except errors.NoSuchExportFormat, e:
1170
 
            raise BzrCommandError('Unsupported export format: %s' % e.format)
 
949
        arg_root, ext = os.path.splitext(os.path.basename(dest))
 
950
        if ext in ('.gz', '.bz2'):
 
951
            new_root, new_ext = os.path.splitext(arg_root)
 
952
            if new_ext == '.tar':
 
953
                arg_root = new_root
 
954
                ext = new_ext + ext
 
955
        if root is None:
 
956
            root = arg_root
 
957
        if not format:
 
958
            if ext in (".tar",):
 
959
                format = "tar"
 
960
            elif ext in (".tar.gz", ".tgz"):
 
961
                format = "tgz"
 
962
            elif ext in (".tar.bz2", ".tbz2"):
 
963
                format = "tbz2"
 
964
            else:
 
965
                format = "dir"
 
966
        t.export(dest, format, root)
1171
967
 
1172
968
 
1173
969
class cmd_cat(Command):
1176
972
    takes_options = ['revision']
1177
973
    takes_args = ['filename']
1178
974
 
1179
 
    @display_command
1180
975
    def run(self, filename, revision=None):
1181
 
        if revision is not None and len(revision) != 1:
 
976
        if revision is None:
 
977
            raise BzrCommandError("bzr cat requires a revision number")
 
978
        elif len(revision) != 1:
1182
979
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1183
 
        tree = None
1184
 
        try:
1185
 
            tree, relpath = WorkingTree.open_containing(filename)
1186
 
            b = tree.branch
1187
 
        except NotBranchError:
1188
 
            pass
1189
 
 
1190
 
        if tree is None:
1191
 
            b, relpath = Branch.open_containing(filename)
1192
 
        if revision is None:
1193
 
            revision_id = b.last_revision()
1194
 
        else:
1195
 
            revision_id = revision[0].in_history(b).rev_id
1196
 
        b.print_file(relpath, revision_id)
 
980
        b, relpath = Branch.open_containing(filename)
 
981
        b.print_file(relpath, revision[0].in_history(b).revno)
1197
982
 
1198
983
 
1199
984
class cmd_local_time_offset(Command):
1200
985
    """Show the offset in seconds from GMT to local time."""
1201
986
    hidden = True    
1202
 
    @display_command
1203
987
    def run(self):
1204
988
        print bzrlib.osutils.local_time_offset()
1205
989
 
1244
1028
            unchanged=False, strict=False):
1245
1029
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1246
1030
                StrictCommitFailed)
1247
 
        from bzrlib.msgeditor import edit_commit_message, \
1248
 
                make_commit_message_template
 
1031
        from bzrlib.msgeditor import edit_commit_message
1249
1032
        from bzrlib.status import show_status
1250
 
        from tempfile import TemporaryFile
1251
 
        import codecs
1252
 
 
1253
 
        # TODO: Need a blackbox test for invoking the external editor; may be
1254
 
        # slightly problematic to run this cross-platform.
1255
 
 
1256
 
        # TODO: do more checks that the commit will succeed before 
1257
 
        # spending the user's valuable time typing a commit message.
1258
 
        #
1259
 
        # TODO: if the commit *does* happen to fail, then save the commit 
1260
 
        # message to a temporary file where it can be recovered
1261
 
        tree, selected_list = tree_files(selected_list)
 
1033
        from cStringIO import StringIO
 
1034
 
 
1035
        b = Branch.open_containing('.')[0]
 
1036
        tree = WorkingTree(b.base, b)
 
1037
        if selected_list:
 
1038
            selected_list = [tree.relpath(s) for s in selected_list]
1262
1039
        if message is None and not file:
1263
 
            template = make_commit_message_template(tree, selected_list)
1264
 
            message = edit_commit_message(template)
 
1040
            catcher = StringIO()
 
1041
            show_status(b, specific_files=selected_list,
 
1042
                        to_file=catcher)
 
1043
            message = edit_commit_message(catcher.getvalue())
 
1044
 
1265
1045
            if message is None:
1266
1046
                raise BzrCommandError("please specify a commit message"
1267
1047
                                      " with either --message or --file")
1276
1056
                raise BzrCommandError("empty commit message specified")
1277
1057
            
1278
1058
        try:
1279
 
            tree.commit(message, specific_files=selected_list,
1280
 
                        allow_pointless=unchanged, strict=strict)
 
1059
            b.commit(message, specific_files=selected_list,
 
1060
                     allow_pointless=unchanged, strict=strict)
1281
1061
        except PointlessCommit:
1282
1062
            # FIXME: This should really happen before the file is read in;
1283
1063
            # perhaps prepare the commit; get the message; then actually commit
1289
1069
        except StrictCommitFailed:
1290
1070
            raise BzrCommandError("Commit refused because there are unknown "
1291
1071
                                  "files in the working tree.")
1292
 
        note('Committed revision %d.' % (tree.branch.revno(),))
1293
1072
 
1294
1073
 
1295
1074
class cmd_check(Command):
1298
1077
    This command checks various invariants about the branch storage to
1299
1078
    detect data corruption or bzr bugs.
1300
1079
    """
1301
 
    takes_args = ['branch?']
 
1080
    takes_args = ['dir?']
1302
1081
    takes_options = ['verbose']
1303
1082
 
1304
 
    def run(self, branch=None, verbose=False):
 
1083
    def run(self, dir='.', verbose=False):
1305
1084
        from bzrlib.check import check
1306
 
        if branch is None:
1307
 
            tree = WorkingTree.open_containing()[0]
1308
 
            branch = tree.branch
1309
 
        else:
1310
 
            branch = Branch.open(branch)
1311
 
        check(branch, verbose)
 
1085
        check(Branch.open_containing(dir)[0], verbose)
1312
1086
 
1313
1087
 
1314
1088
class cmd_scan_cache(Command):
1316
1090
    def run(self):
1317
1091
        from bzrlib.hashcache import HashCache
1318
1092
 
1319
 
        c = HashCache(u'.')
 
1093
        c = HashCache('.')
1320
1094
        c.read()
1321
1095
        c.scan()
1322
1096
            
1342
1116
    """
1343
1117
    takes_args = ['dir?']
1344
1118
 
1345
 
    def run(self, dir=u'.'):
 
1119
    def run(self, dir='.'):
1346
1120
        from bzrlib.upgrade import upgrade
1347
1121
        upgrade(dir)
1348
1122
 
1351
1125
    """Show bzr user id."""
1352
1126
    takes_options = ['email']
1353
1127
    
1354
 
    @display_command
1355
1128
    def run(self, email=False):
1356
1129
        try:
1357
 
            b = WorkingTree.open_containing(u'.')[0].branch
 
1130
            b = bzrlib.branch.Branch.open_containing('.')[0]
1358
1131
            config = bzrlib.config.BranchConfig(b)
1359
1132
        except NotBranchError:
1360
1133
            config = bzrlib.config.GlobalConfig()
1364
1137
        else:
1365
1138
            print config.username()
1366
1139
 
1367
 
class cmd_nick(Command):
1368
 
    """\
1369
 
    Print or set the branch nickname.  
1370
 
    If unset, the tree root directory name is used as the nickname
1371
 
    To print the current nickname, execute with no argument.  
1372
 
    """
1373
 
    takes_args = ['nickname?']
1374
 
    def run(self, nickname=None):
1375
 
        branch = Branch.open_containing(u'.')[0]
1376
 
        if nickname is None:
1377
 
            self.printme(branch)
1378
 
        else:
1379
 
            branch.nick = nickname
1380
 
 
1381
 
    @display_command
1382
 
    def printme(self, branch):
1383
 
        print branch.nick 
1384
1140
 
1385
1141
class cmd_selftest(Command):
1386
1142
    """Run internal test suite.
1388
1144
    This creates temporary test directories in the working directory,
1389
1145
    but not existing data is affected.  These directories are deleted
1390
1146
    if the tests pass, or left behind to help in debugging if they
1391
 
    fail and --keep-output is specified.
 
1147
    fail.
1392
1148
    
1393
1149
    If arguments are given, they are regular expressions that say
1394
1150
    which tests should run.
1398
1154
    takes_args = ['testspecs*']
1399
1155
    takes_options = ['verbose', 
1400
1156
                     Option('one', help='stop when one test fails'),
1401
 
                     Option('keep-output', 
1402
 
                            help='keep output directories when tests fail')
1403
1157
                    ]
1404
1158
 
1405
 
    def run(self, testspecs_list=None, verbose=False, one=False,
1406
 
            keep_output=False):
 
1159
    def run(self, testspecs_list=None, verbose=False, one=False):
1407
1160
        import bzrlib.ui
1408
 
        from bzrlib.tests import selftest
 
1161
        from bzrlib.selftest import selftest
1409
1162
        # we don't want progress meters from the tests to go to the
1410
1163
        # real output; and we don't want log messages cluttering up
1411
1164
        # the real logs.
1419
1172
                pattern = ".*"
1420
1173
            result = selftest(verbose=verbose, 
1421
1174
                              pattern=pattern,
1422
 
                              stop_on_failure=one, 
1423
 
                              keep_output=keep_output)
 
1175
                              stop_on_failure=one)
1424
1176
            if result:
1425
1177
                bzrlib.trace.info('tests passed')
1426
1178
            else:
1446
1198
 
1447
1199
class cmd_version(Command):
1448
1200
    """Show version of bzr."""
1449
 
    @display_command
1450
1201
    def run(self):
1451
1202
        show_version()
1452
1203
 
1453
1204
class cmd_rocks(Command):
1454
1205
    """Statement of optimism."""
1455
1206
    hidden = True
1456
 
    @display_command
1457
1207
    def run(self):
1458
1208
        print "it sure does!"
1459
1209
 
1466
1216
    takes_args = ['branch', 'other']
1467
1217
    hidden = True
1468
1218
    
1469
 
    @display_command
1470
1219
    def run(self, branch, other):
1471
1220
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
1472
1221
        
1526
1275
    --force is given.
1527
1276
    """
1528
1277
    takes_args = ['branch?']
1529
 
    takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1530
 
                     Option('show-base', help="Show base revision text in "
1531
 
                            "conflicts")]
 
1278
    takes_options = ['revision', 'force', 'merge-type']
1532
1279
 
1533
 
    def run(self, branch=None, revision=None, force=False, merge_type=None,
1534
 
            show_base=False, reprocess=False):
 
1280
    def run(self, branch=None, revision=None, force=False, 
 
1281
            merge_type=None):
1535
1282
        from bzrlib.merge import merge
1536
1283
        from bzrlib.merge_core import ApplyMerge3
1537
1284
        if merge_type is None:
1538
1285
            merge_type = ApplyMerge3
1539
1286
        if branch is None:
1540
 
            branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
 
1287
            branch = Branch.open_containing('.')[0].get_parent()
1541
1288
            if branch is None:
1542
1289
                raise BzrCommandError("No merge location known or specified.")
1543
1290
            else:
1548
1295
        else:
1549
1296
            if len(revision) == 1:
1550
1297
                base = [None, None]
1551
 
                other_branch = Branch.open_containing(branch)[0]
1552
 
                revno = revision[0].in_history(other_branch).revno
1553
 
                other = [branch, revno]
 
1298
                other = [branch, revision[0].in_history(branch).revno]
1554
1299
            else:
1555
1300
                assert len(revision) == 2
1556
1301
                if None in revision:
1557
1302
                    raise BzrCommandError(
1558
1303
                        "Merge doesn't permit that revision specifier.")
1559
 
                b = Branch.open_containing(branch)[0]
 
1304
                b = Branch.open(branch)
1560
1305
 
1561
1306
                base = [branch, revision[0].in_history(b).revno]
1562
1307
                other = [branch, revision[1].in_history(b).revno]
1563
1308
 
1564
1309
        try:
1565
 
            conflict_count = merge(other, base, check_clean=(not force),
1566
 
                                   merge_type=merge_type, reprocess=reprocess,
1567
 
                                   show_base=show_base)
1568
 
            if conflict_count != 0:
1569
 
                return 1
1570
 
            else:
1571
 
                return 0
 
1310
            merge(other, base, check_clean=(not force), merge_type=merge_type)
1572
1311
        except bzrlib.errors.AmbiguousBase, e:
1573
1312
            m = ("sorry, bzr can't determine the right merge base yet\n"
1574
1313
                 "candidates are:\n  "
1579
1318
            log_error(m)
1580
1319
 
1581
1320
 
1582
 
class cmd_remerge(Command):
1583
 
    """Redo a merge.
1584
 
    """
1585
 
    takes_args = ['file*']
1586
 
    takes_options = ['merge-type', 'reprocess',
1587
 
                     Option('show-base', help="Show base revision text in "
1588
 
                            "conflicts")]
1589
 
 
1590
 
    def run(self, file_list=None, merge_type=None, show_base=False,
1591
 
            reprocess=False):
1592
 
        from bzrlib.merge import merge_inner, transform_tree
1593
 
        from bzrlib.merge_core import ApplyMerge3
1594
 
        if merge_type is None:
1595
 
            merge_type = ApplyMerge3
1596
 
        tree, file_list = tree_files(file_list)
1597
 
        tree.lock_write()
1598
 
        try:
1599
 
            pending_merges = tree.pending_merges() 
1600
 
            if len(pending_merges) != 1:
1601
 
                raise BzrCommandError("Sorry, remerge only works after normal"
1602
 
                                      + " merges.  Not cherrypicking or"
1603
 
                                      + "multi-merges.")
1604
 
            base_revision = common_ancestor(tree.branch.last_revision(), 
1605
 
                                            pending_merges[0], tree.branch)
1606
 
            base_tree = tree.branch.revision_tree(base_revision)
1607
 
            other_tree = tree.branch.revision_tree(pending_merges[0])
1608
 
            interesting_ids = None
1609
 
            if file_list is not None:
1610
 
                interesting_ids = set()
1611
 
                for filename in file_list:
1612
 
                    file_id = tree.path2id(filename)
1613
 
                    interesting_ids.add(file_id)
1614
 
                    if tree.kind(file_id) != "directory":
1615
 
                        continue
1616
 
                    
1617
 
                    for name, ie in tree.inventory.iter_entries(file_id):
1618
 
                        interesting_ids.add(ie.file_id)
1619
 
            transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1620
 
            if file_list is None:
1621
 
                restore_files = list(tree.iter_conflicts())
1622
 
            else:
1623
 
                restore_files = file_list
1624
 
            for filename in restore_files:
1625
 
                try:
1626
 
                    restore(tree.abspath(filename))
1627
 
                except NotConflicted:
1628
 
                    pass
1629
 
            conflicts =  merge_inner(tree.branch, other_tree, base_tree, 
1630
 
                                     interesting_ids = interesting_ids, 
1631
 
                                     other_rev_id=pending_merges[0], 
1632
 
                                     merge_type=merge_type, 
1633
 
                                     show_base=show_base,
1634
 
                                     reprocess=reprocess)
1635
 
        finally:
1636
 
            tree.unlock()
1637
 
        if conflicts > 0:
1638
 
            return 1
1639
 
        else:
1640
 
            return 0
1641
 
 
1642
1321
class cmd_revert(Command):
1643
1322
    """Reverse all changes since the last commit.
1644
1323
 
1651
1330
    aliases = ['merge-revert']
1652
1331
 
1653
1332
    def run(self, revision=None, no_backup=False, file_list=None):
1654
 
        from bzrlib.merge import merge_inner
 
1333
        from bzrlib.merge import merge
1655
1334
        from bzrlib.commands import parse_spec
 
1335
 
1656
1336
        if file_list is not None:
1657
1337
            if len(file_list) == 0:
1658
1338
                raise BzrCommandError("No files specified")
1659
 
        else:
1660
 
            file_list = []
1661
1339
        if revision is None:
1662
1340
            revno = -1
1663
 
            tree = WorkingTree.open_containing(u'.')[0]
1664
 
            # FIXME should be tree.last_revision
1665
 
            rev_id = tree.branch.last_revision()
1666
1341
        elif len(revision) != 1:
1667
1342
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1668
1343
        else:
1669
 
            tree, file_list = tree_files(file_list)
1670
 
            rev_id = revision[0].in_history(tree.branch).rev_id
1671
 
        tree.revert(file_list, tree.branch.revision_tree(rev_id),
1672
 
                                not no_backup)
 
1344
            b = Branch.open_containing('.')[0]
 
1345
            revno = revision[0].in_history(b).revno
 
1346
        merge(('.', revno), parse_spec('.'),
 
1347
              check_clean=False,
 
1348
              ignore_zero=True,
 
1349
              backup_files=not no_backup,
 
1350
              file_list=file_list)
 
1351
        if not file_list:
 
1352
            Branch.open_containing('.')[0].set_pending_merges([])
1673
1353
 
1674
1354
 
1675
1355
class cmd_assert_fail(Command):
1687
1367
    takes_args = ['topic?']
1688
1368
    aliases = ['?']
1689
1369
    
1690
 
    @display_command
1691
1370
    def run(self, topic=None, long=False):
1692
1371
        import help
1693
1372
        if topic is None and long:
1703
1382
    aliases = ['s-c']
1704
1383
    hidden = True
1705
1384
    
1706
 
    @display_command
1707
1385
    def run(self, context=None):
1708
1386
        import shellcomplete
1709
1387
        shellcomplete.shellcomplete(context)
1718
1396
    def run(self, from_branch, to_branch):
1719
1397
        from bzrlib.fetch import Fetcher
1720
1398
        from bzrlib.branch import Branch
1721
 
        from_b = Branch.open(from_branch)
1722
 
        to_b = Branch.open(to_branch)
1723
 
        from_b.lock_read()
1724
 
        try:
1725
 
            to_b.lock_write()
1726
 
            try:
1727
 
                Fetcher(to_b, from_b)
1728
 
            finally:
1729
 
                to_b.unlock()
1730
 
        finally:
1731
 
            from_b.unlock()
 
1399
        from_b = Branch(from_branch)
 
1400
        to_b = Branch(to_branch)
 
1401
        Fetcher(to_b, from_b)
 
1402
        
1732
1403
 
1733
1404
 
1734
1405
class cmd_missing(Command):
1739
1410
    
1740
1411
    takes_args = ['remote?']
1741
1412
    aliases = ['mis', 'miss']
1742
 
    takes_options = ['verbose']
 
1413
    # We don't have to add quiet to the list, because 
 
1414
    # unknown options are parsed as booleans
 
1415
    takes_options = ['verbose', 'quiet']
1743
1416
 
1744
 
    @display_command
1745
 
    def run(self, remote=None, verbose=False):
 
1417
    def run(self, remote=None, verbose=False, quiet=False):
1746
1418
        from bzrlib.errors import BzrCommandError
1747
1419
        from bzrlib.missing import show_missing
1748
1420
 
1749
 
        if verbose and is_quiet():
 
1421
        if verbose and quiet:
1750
1422
            raise BzrCommandError('Cannot pass both quiet and verbose')
1751
1423
 
1752
 
        tree = WorkingTree.open_containing(u'.')[0]
1753
 
        parent = tree.branch.get_parent()
 
1424
        b = Branch.open_containing('.')[0]
 
1425
        parent = b.get_parent()
1754
1426
        if remote is None:
1755
1427
            if parent is None:
1756
1428
                raise BzrCommandError("No missing location known or specified.")
1757
1429
            else:
1758
 
                if not is_quiet():
 
1430
                if not quiet:
1759
1431
                    print "Using last location: %s" % parent
1760
1432
                remote = parent
1761
1433
        elif parent is None:
1762
1434
            # We only update parent if it did not exist, missing
1763
1435
            # should not change the parent
1764
 
            tree.branch.set_parent(remote)
 
1436
            b.set_parent(remote)
1765
1437
        br_remote = Branch.open_containing(remote)[0]
1766
 
        return show_missing(tree.branch, br_remote, verbose=verbose, 
1767
 
                            quiet=is_quiet())
 
1438
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1768
1439
 
1769
1440
 
1770
1441
class cmd_plugins(Command):
1771
1442
    """List plugins"""
1772
1443
    hidden = True
1773
 
    @display_command
1774
1444
    def run(self):
1775
1445
        import bzrlib.plugin
1776
1446
        from inspect import getdoc
1777
 
        for name, plugin in bzrlib.plugin.all_plugins().items():
 
1447
        for plugin in bzrlib.plugin.all_plugins:
1778
1448
            if hasattr(plugin, '__path__'):
1779
1449
                print plugin.__path__[0]
1780
1450
            elif hasattr(plugin, '__file__'):
1791
1461
    """Show testament (signing-form) of a revision."""
1792
1462
    takes_options = ['revision', 'long']
1793
1463
    takes_args = ['branch?']
1794
 
    @display_command
1795
 
    def run(self, branch=u'.', revision=None, long=False):
 
1464
    def run(self, branch='.', revision=None, long=False):
1796
1465
        from bzrlib.testament import Testament
1797
 
        b = WorkingTree.open_containing(branch)[0].branch
 
1466
        b = Branch.open_containing(branch)[0]
1798
1467
        b.lock_read()
1799
1468
        try:
1800
1469
            if revision is None:
1829
1498
                     Option('long', help='show date in annotations'),
1830
1499
                     ]
1831
1500
 
1832
 
    @display_command
1833
1501
    def run(self, filename, all=False, long=False):
1834
1502
        from bzrlib.annotate import annotate_file
1835
 
        tree, relpath = WorkingTree.open_containing(filename)
1836
 
        branch = tree.branch
1837
 
        branch.lock_read()
 
1503
        b, relpath = Branch.open_containing(filename)
 
1504
        b.lock_read()
1838
1505
        try:
 
1506
            tree = WorkingTree(b.base, b)
 
1507
            tree = b.revision_tree(b.last_revision())
1839
1508
            file_id = tree.inventory.path2id(relpath)
1840
 
            tree = branch.revision_tree(branch.last_revision())
1841
1509
            file_version = tree.inventory[file_id].revision
1842
 
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
 
1510
            annotate_file(b, file_version, file_id, long, all, sys.stdout)
1843
1511
        finally:
1844
 
            branch.unlock()
 
1512
            b.unlock()
1845
1513
 
1846
1514
 
1847
1515
class cmd_re_sign(Command):
1859
1527
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1860
1528
        if revision_id is None and revision is None:
1861
1529
            raise BzrCommandError('You must supply either --revision or a revision_id')
1862
 
        b = WorkingTree.open_containing(u'.')[0].branch
 
1530
        b = Branch.open_containing('.')[0]
1863
1531
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1864
1532
        if revision_id is not None:
1865
1533
            b.sign_revision(revision_id, gpg_strategy)
1866
1534
        elif revision is not None:
1867
 
            if len(revision) == 1:
1868
 
                revno, rev_id = revision[0].in_history(b)
 
1535
            for rev in revision:
 
1536
                if rev is None:
 
1537
                    raise BzrCommandError('You cannot specify a NULL revision.')
 
1538
                revno, rev_id = rev.in_history(b)
1869
1539
                b.sign_revision(rev_id, gpg_strategy)
1870
 
            elif len(revision) == 2:
1871
 
                # are they both on rh- if so we can walk between them
1872
 
                # might be nice to have a range helper for arbitrary
1873
 
                # revision paths. hmm.
1874
 
                from_revno, from_revid = revision[0].in_history(b)
1875
 
                to_revno, to_revid = revision[1].in_history(b)
1876
 
                if to_revid is None:
1877
 
                    to_revno = b.revno()
1878
 
                if from_revno is None or to_revno is None:
1879
 
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1880
 
                for revno in range(from_revno, to_revno + 1):
1881
 
                    b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1882
 
            else:
1883
 
                raise BzrCommandError('Please supply either one revision, or a range.')
1884
 
 
1885
 
 
1886
 
class cmd_uncommit(bzrlib.commands.Command):
1887
 
    """Remove the last committed revision.
1888
 
 
1889
 
    By supplying the --all flag, it will not only remove the entry 
1890
 
    from revision_history, but also remove all of the entries in the
1891
 
    stores.
1892
 
 
1893
 
    --verbose will print out what is being removed.
1894
 
    --dry-run will go through all the motions, but not actually
1895
 
    remove anything.
1896
 
    
1897
 
    In the future, uncommit will create a changeset, which can then
1898
 
    be re-applied.
1899
 
    """
1900
 
    takes_options = ['all', 'verbose', 'revision',
1901
 
                    Option('dry-run', help='Don\'t actually make changes'),
1902
 
                    Option('force', help='Say yes to all questions.')]
1903
 
    takes_args = ['location?']
1904
 
    aliases = []
1905
 
 
1906
 
    def run(self, location=None, all=False,
1907
 
            dry_run=False, verbose=False,
1908
 
            revision=None, force=False):
1909
 
        from bzrlib.branch import Branch
1910
 
        from bzrlib.log import log_formatter
1911
 
        import sys
1912
 
        from bzrlib.uncommit import uncommit
1913
 
 
1914
 
        if location is None:
1915
 
            location = u'.'
1916
 
        b, relpath = Branch.open_containing(location)
1917
 
 
1918
 
        if revision is None:
1919
 
            revno = b.revno()
1920
 
            rev_id = b.last_revision()
1921
 
        else:
1922
 
            revno, rev_id = revision[0].in_history(b)
1923
 
        if rev_id is None:
1924
 
            print 'No revisions to uncommit.'
1925
 
 
1926
 
        for r in range(revno, b.revno()+1):
1927
 
            rev_id = b.get_rev_id(r)
1928
 
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
1929
 
            lf.show(r, b.get_revision(rev_id), None)
1930
 
 
1931
 
        if dry_run:
1932
 
            print 'Dry-run, pretending to remove the above revisions.'
1933
 
            if not force:
1934
 
                val = raw_input('Press <enter> to continue')
1935
 
        else:
1936
 
            print 'The above revision(s) will be removed.'
1937
 
            if not force:
1938
 
                val = raw_input('Are you sure [y/N]? ')
1939
 
                if val.lower() not in ('y', 'yes'):
1940
 
                    print 'Canceled'
1941
 
                    return 0
1942
 
 
1943
 
        uncommit(b, remove_files=all,
1944
 
                dry_run=dry_run, verbose=verbose,
1945
 
                revno=revno)
1946
1540
 
1947
1541
 
1948
1542
# these get imported and then picked up by the scan for cmd_*
1949
1543
# TODO: Some more consistent way to split command definitions across files;
1950
1544
# we do need to load at least some information about them to know of 
1951
1545
# aliases.
1952
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
 
1546
from bzrlib.conflicts import cmd_resolve, cmd_conflicts