~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

- rules for using destructors

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
 
1
# Copyright (C) 2004, 2005 by Canonical Ltd
2
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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
 
"""builtin bzr commands"""
18
 
 
19
 
 
20
 
import errno
 
17
 
 
18
import sys
21
19
import os
22
 
import sys
23
20
 
24
21
import bzrlib
25
 
import bzrlib.branch
 
22
from bzrlib import BZRDIR
 
23
from bzrlib.commands import Command
26
24
from bzrlib.branch import Branch
27
 
import bzrlib.bzrdir as bzrdir
28
 
from bzrlib.commands import Command, display_command
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
 
                           NotVersionedError)
35
 
from bzrlib.log import show_one_log
36
 
from bzrlib.merge import Merge3Merger
 
25
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
 
26
from bzrlib.errors import DivergedBranches
37
27
from bzrlib.option import Option
38
 
from bzrlib.progress import DummyProgress, ProgressPhase
39
28
from bzrlib.revisionspec import RevisionSpec
40
29
import bzrlib.trace
41
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
42
 
from bzrlib.transport.local import LocalTransport
43
 
import bzrlib.ui
 
30
from bzrlib.trace import mutter, note, log_error, warning
44
31
from bzrlib.workingtree import WorkingTree
45
32
 
46
33
 
47
 
def tree_files(file_list, default_branch=u'.'):
48
 
    try:
49
 
        return internal_tree_files(file_list, default_branch)
50
 
    except FileInWrongBranch, e:
51
 
        raise BzrCommandError("%s is not in the same branch as %s" %
52
 
                             (e.path, file_list[0]))
53
 
 
54
 
 
55
 
# XXX: Bad function name; should possibly also be a class method of
56
 
# WorkingTree rather than a function.
57
 
def internal_tree_files(file_list, default_branch=u'.'):
58
 
    """Convert command-line paths to a WorkingTree and relative paths.
59
 
 
60
 
    This is typically used for command-line processors that take one or
61
 
    more filenames, and infer the workingtree that contains them.
62
 
 
63
 
    The filenames given are not required to exist.
64
 
 
65
 
    :param file_list: Filenames to convert.  
66
 
 
67
 
    :param default_branch: Fallback tree path to use if file_list is empty or None.
68
 
 
69
 
    :return: workingtree, [relative_paths]
70
 
    """
71
 
    if file_list is None or len(file_list) == 0:
72
 
        return WorkingTree.open_containing(default_branch)[0], file_list
73
 
    tree = WorkingTree.open_containing(file_list[0])[0]
74
 
    new_list = []
75
 
    for filename in file_list:
76
 
        try:
77
 
            new_list.append(tree.relpath(filename))
78
 
        except errors.PathNotChild:
79
 
            raise FileInWrongBranch(tree.branch, filename)
80
 
    return tree, new_list
81
 
 
82
 
 
83
 
def get_format_type(typestring):
84
 
    """Parse and return a format specifier."""
85
 
    if typestring == "weave":
86
 
        return bzrdir.BzrDirFormat6()
87
 
    if typestring == "default":
88
 
        return bzrdir.BzrDirMetaFormat1()
89
 
    if typestring == "metaweave":
90
 
        format = bzrdir.BzrDirMetaFormat1()
91
 
        format.repository_format = bzrlib.repository.RepositoryFormat7()
92
 
        return format
93
 
    if typestring == "knit":
94
 
        format = bzrdir.BzrDirMetaFormat1()
95
 
        format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
96
 
        return format
97
 
    msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
98
 
          "metaweave and weave" % typestring
99
 
    raise BzrCommandError(msg)
100
 
 
101
 
 
102
 
# TODO: Make sure no commands unconditionally use the working directory as a
103
 
# branch.  If a filename argument is used, the first of them should be used to
104
 
# specify the branch.  (Perhaps this can be factored out into some kind of
105
 
# Argument class, representing a file in a branch, where the first occurrence
106
 
# opens the branch?)
107
 
 
108
34
class cmd_status(Command):
109
35
    """Display status summary.
110
36
 
145
71
    that revision, or between two revisions if two are provided.
146
72
    """
147
73
    
 
74
    # XXX: FIXME: bzr status should accept a -r option to show changes
 
75
    # relative to a revision, or between revisions
 
76
 
148
77
    # TODO: --no-recurse, --recurse options
149
78
    
150
79
    takes_args = ['file*']
151
 
    takes_options = ['all', 'show-ids', 'revision']
 
80
    takes_options = ['all', 'show-ids']
152
81
    aliases = ['st', 'stat']
153
82
    
154
 
    @display_command
155
83
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
156
 
        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]
157
96
            
158
 
        from bzrlib.status import show_tree_status
159
 
        show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
160
 
                         specific_files=file_list, revision=revision)
 
97
        from bzrlib.status import show_status
 
98
        show_status(b, show_unchanged=all, show_ids=show_ids,
 
99
                    specific_files=file_list, revision=revision)
161
100
 
162
101
 
163
102
class cmd_cat_revision(Command):
171
110
    takes_args = ['revision_id?']
172
111
    takes_options = ['revision']
173
112
    
174
 
    @display_command
175
113
    def run(self, revision_id=None, revision=None):
176
114
 
177
115
        if revision_id is not None and revision is not None:
178
116
            raise BzrCommandError('You can only supply one of revision_id or --revision')
179
117
        if revision_id is None and revision is None:
180
118
            raise BzrCommandError('You must supply either --revision or a revision_id')
181
 
        b = WorkingTree.open_containing(u'.')[0].branch
 
119
        b = Branch.open_containing('.')[0]
182
120
        if revision_id is not None:
183
 
            sys.stdout.write(b.repository.get_revision_xml(revision_id))
 
121
            sys.stdout.write(b.get_revision_xml_file(revision_id).read())
184
122
        elif revision is not None:
185
123
            for rev in revision:
186
124
                if rev is None:
187
125
                    raise BzrCommandError('You cannot specify a NULL revision.')
188
126
                revno, rev_id = rev.in_history(b)
189
 
                sys.stdout.write(b.repository.get_revision_xml(rev_id))
 
127
                sys.stdout.write(b.get_revision_xml_file(rev_id).read())
190
128
    
191
129
 
192
130
class cmd_revno(Command):
193
131
    """Show current revision number.
194
132
 
195
133
    This is equal to the number of revisions on this branch."""
196
 
    takes_args = ['location?']
197
 
    @display_command
198
 
    def run(self, location=u'.'):
199
 
        print Branch.open_containing(location)[0].revno()
 
134
    def run(self):
 
135
        print Branch.open_containing('.')[0].revno()
200
136
 
201
137
 
202
138
class cmd_revision_info(Command):
205
141
    hidden = True
206
142
    takes_args = ['revision_info*']
207
143
    takes_options = ['revision']
208
 
    @display_command
209
144
    def run(self, revision=None, revision_info_list=[]):
210
145
 
211
146
        revs = []
217
152
        if len(revs) == 0:
218
153
            raise BzrCommandError('You must supply a revision identifier')
219
154
 
220
 
        b = WorkingTree.open_containing(u'.')[0].branch
 
155
        b = Branch.open_containing('.')[0]
221
156
 
222
157
        for rev in revs:
223
158
            revinfo = rev.in_history(b)
249
184
    implicitly add the parent, and so on up to the root. This means
250
185
    you should never need to explictly add a directory, they'll just
251
186
    get added when you add a file in the directory.
252
 
 
253
 
    --dry-run will show which files would be added, but not actually 
254
 
    add them.
255
187
    """
256
188
    takes_args = ['file*']
257
 
    takes_options = ['no-recurse', 'dry-run', 'verbose']
258
 
 
259
 
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
260
 
        import bzrlib.add
261
 
 
262
 
        if dry_run:
263
 
            if is_quiet():
264
 
                # This is pointless, but I'd rather not raise an error
265
 
                action = bzrlib.add.add_action_null
266
 
            else:
267
 
                action = bzrlib.add.add_action_print
268
 
        elif is_quiet():
269
 
            action = bzrlib.add.add_action_add
 
189
    takes_options = ['no-recurse', 'quiet']
 
190
    
 
191
    def run(self, file_list, no_recurse=False, quiet=False):
 
192
        from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
 
193
        if quiet:
 
194
            reporter = add_reporter_null
270
195
        else:
271
 
            action = bzrlib.add.add_action_add_and_print
272
 
 
273
 
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
274
 
                                              action)
275
 
        if len(ignored) > 0:
276
 
            for glob in sorted(ignored.keys()):
277
 
                match_len = len(ignored[glob])
278
 
                if verbose:
279
 
                    for path in ignored[glob]:
280
 
                        print "ignored %s matching \"%s\"" % (path, glob)
281
 
                else:
282
 
                    print "ignored %d file(s) matching \"%s\"" % (match_len,
283
 
                                                              glob)
284
 
            print "If you wish to add some of these files, please add them"\
285
 
                " by name."
 
196
            reporter = add_reporter_print
 
197
        smart_add(file_list, not no_recurse, reporter)
286
198
 
287
199
 
288
200
class cmd_mkdir(Command):
293
205
    takes_args = ['dir+']
294
206
 
295
207
    def run(self, dir_list):
 
208
        b = None
 
209
        
296
210
        for d in dir_list:
297
211
            os.mkdir(d)
298
 
            wt, dd = WorkingTree.open_containing(d)
299
 
            wt.add([dd])
 
212
            if not b:
 
213
                b = Branch.open_containing(d)[0]
 
214
            b.add([d])
300
215
            print 'added', d
301
216
 
302
217
 
305
220
    takes_args = ['filename']
306
221
    hidden = True
307
222
    
308
 
    @display_command
309
223
    def run(self, filename):
310
 
        tree, relpath = WorkingTree.open_containing(filename)
 
224
        branch, relpath = Branch.open_containing(filename)
311
225
        print relpath
312
226
 
313
227
 
314
228
class cmd_inventory(Command):
315
 
    """Show inventory of the current working copy or a revision.
316
 
 
317
 
    It is possible to limit the output to a particular entry
318
 
    type using the --kind option.  For example; --kind file.
319
 
    """
320
 
    takes_options = ['revision', 'show-ids', 'kind']
 
229
    """Show inventory of the current working copy or a revision."""
 
230
    takes_options = ['revision', 'show-ids']
321
231
    
322
 
    @display_command
323
 
    def run(self, revision=None, show_ids=False, kind=None):
324
 
        if kind and kind not in ['file', 'directory', 'symlink']:
325
 
            raise BzrCommandError('invalid kind specified')
326
 
        tree = WorkingTree.open_containing(u'.')[0]
 
232
    def run(self, revision=None, show_ids=False):
 
233
        b = Branch.open_containing('.')[0]
327
234
        if revision is None:
328
 
            inv = tree.read_working_inventory()
 
235
            inv = b.read_working_inventory()
329
236
        else:
330
237
            if len(revision) > 1:
331
238
                raise BzrCommandError('bzr inventory --revision takes'
332
239
                    ' exactly one revision identifier')
333
 
            inv = tree.branch.repository.get_revision_inventory(
334
 
                revision[0].in_history(tree.branch).rev_id)
 
240
            inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
335
241
 
336
242
        for path, entry in inv.entries():
337
 
            if kind and kind != entry.kind:
338
 
                continue
339
243
            if show_ids:
340
244
                print '%-50s %s' % (path, entry.file_id)
341
245
            else:
342
246
                print path
343
247
 
344
248
 
 
249
class cmd_move(Command):
 
250
    """Move files to a different directory.
 
251
 
 
252
    examples:
 
253
        bzr move *.txt doc
 
254
 
 
255
    The destination must be a versioned directory in the same branch.
 
256
    """
 
257
    takes_args = ['source$', 'dest']
 
258
    def run(self, source_list, dest):
 
259
        b = Branch.open_containing('.')[0]
 
260
 
 
261
        # TODO: glob expansion on windows?
 
262
        tree = WorkingTree(b.base, b)
 
263
        b.move([tree.relpath(s) for s in source_list], tree.relpath(dest))
 
264
 
 
265
 
 
266
class cmd_rename(Command):
 
267
    """Change the name of an entry.
 
268
 
 
269
    examples:
 
270
      bzr rename frob.c frobber.c
 
271
      bzr rename src/frob.c lib/frob.c
 
272
 
 
273
    It is an error if the destination name exists.
 
274
 
 
275
    See also the 'move' command, which moves files into a different
 
276
    directory without changing their name.
 
277
    """
 
278
    # TODO: Some way to rename multiple files without invoking 
 
279
    # bzr for each one?"""
 
280
    takes_args = ['from_name', 'to_name']
 
281
    
 
282
    def run(self, 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))
 
286
 
 
287
 
345
288
class cmd_mv(Command):
346
289
    """Move or rename a file.
347
290
 
356
299
    Files cannot be moved between branches.
357
300
    """
358
301
    takes_args = ['names*']
359
 
    aliases = ['move', 'rename']
360
 
 
361
302
    def run(self, names_list):
362
303
        if len(names_list) < 2:
363
304
            raise BzrCommandError("missing file argument")
364
 
        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]
365
308
        
366
309
        if os.path.isdir(names_list[-1]):
367
310
            # move into existing directory
368
 
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
 
311
            for pair in b.move(rel_names[:-1], rel_names[-1]):
369
312
                print "%s => %s" % pair
370
313
        else:
371
314
            if len(names_list) != 2:
372
315
                raise BzrCommandError('to mv multiple files the destination '
373
316
                                      'must be a versioned directory')
374
 
            tree.rename_one(rel_names[0], rel_names[1])
 
317
            b.rename_one(rel_names[0], rel_names[1])
375
318
            print "%s => %s" % (rel_names[0], rel_names[1])
376
319
            
377
320
    
 
321
 
 
322
 
378
323
class cmd_pull(Command):
379
 
    """Turn this branch into a mirror of another branch.
 
324
    """Pull any changes from another branch into the current one.
 
325
 
 
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.
380
329
 
381
330
    This command only works on branches that have not diverged.  Branches are
382
 
    considered diverged if the destination branch's most recent commit is one
383
 
    that has not been merged (directly or indirectly) into the parent.
384
 
 
385
 
    If branches have diverged, you can use 'bzr merge' to integrate the changes
386
 
    from one into the other.  Once one branch has merged, the other should
387
 
    be able to pull it again.
 
331
    considered diverged if both branches have had commits without first
 
332
    pulling from the other.
388
333
 
389
334
    If branches have diverged, you can use 'bzr merge' to pull the text changes
390
 
    from one into the other.  Once one branch has merged, the other should
391
 
    be able to pull it again.
392
 
 
393
 
    If you want to forget your local changes and just update your branch to
394
 
    match the remote one, use pull --overwrite.
395
 
 
396
 
    If there is no default location set, the first pull will set it.  After
397
 
    that, you can omit the location to use the default.  To change the
398
 
    default, use --remember.
 
335
    from one into the other.
399
336
    """
400
 
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
 
337
    takes_options = ['remember', 'clobber']
401
338
    takes_args = ['location?']
402
339
 
403
 
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
404
 
        # FIXME: too much stuff is in the command class
405
 
        try:
406
 
            tree_to = WorkingTree.open_containing(u'.')[0]
407
 
            branch_to = tree_to.branch
408
 
        except NoWorkingTree:
409
 
            tree_to = None
410
 
            branch_to = Branch.open_containing(u'.')[0] 
411
 
        stored_loc = branch_to.get_parent()
 
340
    def run(self, location=None, remember=False, clobber=False):
 
341
        from bzrlib.merge import merge
 
342
        import tempfile
 
343
        from shutil import rmtree
 
344
        import errno
 
345
        
 
346
        br_to = Branch.open_containing('.')[0]
 
347
        stored_loc = br_to.get_parent()
412
348
        if location is None:
413
349
            if stored_loc is None:
414
350
                raise BzrCommandError("No pull location known or specified.")
415
351
            else:
416
352
                print "Using saved location: %s" % stored_loc
417
353
                location = stored_loc
418
 
 
419
 
        if branch_to.get_parent() is None or remember:
420
 
            branch_to.set_parent(location)
421
 
 
422
 
        branch_from = Branch.open(location)
423
 
 
424
 
        if revision is None:
425
 
            rev_id = None
426
 
        elif len(revision) == 1:
427
 
            rev_id = revision[0].in_history(branch_from).rev_id
428
 
        else:
429
 
            raise BzrCommandError('bzr pull --revision takes one value.')
430
 
 
431
 
        old_rh = branch_to.revision_history()
432
 
        if tree_to is not None:
433
 
            count = tree_to.pull(branch_from, overwrite, rev_id)
434
 
        else:
435
 
            count = branch_to.pull(branch_from, overwrite, rev_id)
436
 
        note('%d revision(s) pulled.' % (count,))
437
 
 
438
 
        if verbose:
439
 
            new_rh = branch_to.revision_history()
440
 
            if old_rh != new_rh:
441
 
                # Something changed
442
 
                from bzrlib.log import show_changed_revisions
443
 
                show_changed_revisions(branch_to, old_rh, new_rh)
444
 
 
445
 
 
446
 
class cmd_push(Command):
447
 
    """Update a mirror of this branch.
448
 
    
449
 
    The target branch will not have its working tree populated because this
450
 
    is both expensive, and is not supported on remote file systems.
451
 
    
452
 
    Some smart servers or protocols *may* put the working tree in place in
453
 
    the future.
454
 
 
455
 
    This command only works on branches that have not diverged.  Branches are
456
 
    considered diverged if the destination branch's most recent commit is one
457
 
    that has not been merged (directly or indirectly) by the source branch.
458
 
 
459
 
    If branches have diverged, you can use 'bzr push --overwrite' to replace
460
 
    the other branch completely, discarding its unmerged changes.
461
 
    
462
 
    If you want to ensure you have the different changes in the other branch,
463
 
    do a merge (see bzr help merge) from the other branch, and commit that.
464
 
    After that you will be able to do a push without '--overwrite'.
465
 
 
466
 
    If there is no default push location set, the first push will set it.
467
 
    After that, you can omit the location to use the default.  To change the
468
 
    default, use --remember.
469
 
    """
470
 
    takes_options = ['remember', 'overwrite', 
471
 
                     Option('create-prefix', 
472
 
                            help='Create the path leading up to the branch '
473
 
                                 'if it does not already exist')]
474
 
    takes_args = ['location?']
475
 
 
476
 
    def run(self, location=None, remember=False, overwrite=False,
477
 
            create_prefix=False, verbose=False):
478
 
        # FIXME: Way too big!  Put this into a function called from the
479
 
        # command.
480
 
        from bzrlib.transport import get_transport
481
 
        
482
 
        br_from = Branch.open_containing('.')[0]
483
 
        stored_loc = br_from.get_push_location()
484
 
        if location is None:
485
 
            if stored_loc is None:
486
 
                raise BzrCommandError("No push location known or specified.")
487
 
            else:
488
 
                print "Using saved location: %s" % stored_loc
489
 
                location = stored_loc
490
 
        if br_from.get_push_location() is None or remember:
491
 
            br_from.set_push_location(location)
492
 
        try:
493
 
            dir_to = bzrlib.bzrdir.BzrDir.open(location)
494
 
            br_to = dir_to.open_branch()
495
 
        except NotBranchError:
496
 
            # create a branch.
497
 
            transport = get_transport(location).clone('..')
498
 
            if not create_prefix:
499
 
                try:
500
 
                    transport.mkdir(transport.relpath(location))
501
 
                except NoSuchFile:
502
 
                    raise BzrCommandError("Parent directory of %s "
503
 
                                          "does not exist." % location)
504
 
            else:
505
 
                current = transport.base
506
 
                needed = [(transport, transport.relpath(location))]
507
 
                while needed:
508
 
                    try:
509
 
                        transport, relpath = needed[-1]
510
 
                        transport.mkdir(relpath)
511
 
                        needed.pop()
512
 
                    except NoSuchFile:
513
 
                        new_transport = transport.clone('..')
514
 
                        needed.append((new_transport,
515
 
                                       new_transport.relpath(transport.base)))
516
 
                        if new_transport.base == transport.base:
517
 
                            raise BzrCommandError("Could not create "
518
 
                                                  "path prefix.")
519
 
            dir_to = br_from.bzrdir.clone(location)
520
 
            br_to = dir_to.open_branch()
521
 
        old_rh = br_to.revision_history()
522
 
        try:
523
 
            try:
524
 
                tree_to = dir_to.open_workingtree()
525
 
            except errors.NotLocalUrl:
526
 
                # TODO: This should be updated for branches which don't have a
527
 
                # working tree, as opposed to ones where we just couldn't 
528
 
                # update the tree.
529
 
                warning('This transport does not update the working '
530
 
                        'tree of: %s' % (br_to.base,))
531
 
                count = br_to.pull(br_from, overwrite)
532
 
            except NoWorkingTree:
533
 
                count = br_to.pull(br_from, overwrite)
534
 
            else:
535
 
                count = tree_to.pull(br_from, overwrite)
 
354
        br_from = Branch.open(location)
 
355
        try:
 
356
            br_to.working_tree().pull(br_from, remember, clobber)
536
357
        except DivergedBranches:
537
358
            raise BzrCommandError("These branches have diverged."
538
 
                                  "  Try a merge then push with overwrite.")
539
 
        note('%d revision(s) pushed.' % (count,))
540
 
 
541
 
        if verbose:
542
 
            new_rh = br_to.revision_history()
543
 
            if old_rh != new_rh:
544
 
                # Something changed
545
 
                from bzrlib.log import show_changed_revisions
546
 
                show_changed_revisions(br_to, old_rh, new_rh)
 
359
                                  "  Try merge.")
547
360
 
548
361
 
549
362
class cmd_branch(Command):
564
377
    aliases = ['get', 'clone']
565
378
 
566
379
    def run(self, from_location, to_location=None, revision=None, basis=None):
567
 
        from bzrlib.osutils import rmtree
 
380
        from bzrlib.clone import copy_branch
 
381
        import tempfile
 
382
        import errno
 
383
        from shutil import rmtree
 
384
        cache_root = tempfile.mkdtemp()
568
385
        if revision is None:
569
386
            revision = [None]
570
387
        elif len(revision) > 1:
580
397
                raise
581
398
        br_from.lock_read()
582
399
        try:
 
400
            br_from.setup_caching(cache_root)
583
401
            if basis is not None:
584
 
                basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
 
402
                basis_branch = Branch.open_containing(basis)[0]
585
403
            else:
586
 
                basis_dir = None
 
404
                basis_branch = None
587
405
            if len(revision) == 1 and revision[0] is not None:
588
406
                revision_id = revision[0].in_history(br_from)[1]
589
407
            else:
590
 
                # FIXME - wt.last_revision, fallback to branch, fall back to
591
 
                # None or perhaps NULL_REVISION to mean copy nothing
592
 
                # RBC 20060209
593
 
                revision_id = br_from.last_revision()
 
408
                revision_id = None
594
409
            if to_location is None:
595
410
                to_location = os.path.basename(from_location.rstrip("/\\"))
596
 
                name = None
597
 
            else:
598
 
                name = os.path.basename(to_location) + '\n'
599
411
            try:
600
412
                os.mkdir(to_location)
601
413
            except OSError, e:
608
420
                else:
609
421
                    raise
610
422
            try:
611
 
                # preserve whatever source format we have.
612
 
                dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
613
 
                branch = dir.open_branch()
 
423
                copy_branch(br_from, to_location, revision_id, basis_branch)
614
424
            except bzrlib.errors.NoSuchRevision:
615
425
                rmtree(to_location)
616
426
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
617
427
                raise BzrCommandError(msg)
618
428
            except bzrlib.errors.UnlistableBranch:
619
 
                rmtree(to_location)
620
 
                msg = "The branch %s cannot be used as a --basis" % (basis,)
621
 
                raise BzrCommandError(msg)
622
 
            if name:
623
 
                branch.control_files.put_utf8('branch-name', name)
624
 
 
625
 
            note('Branched %d revision(s).' % branch.revno())
 
429
                msg = "The branch %s cannot be used as a --basis"
626
430
        finally:
627
431
            br_from.unlock()
628
 
 
629
 
 
630
 
class cmd_checkout(Command):
631
 
    """Create a new checkout of an existing branch.
632
 
 
633
 
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
634
 
    the branch found in '.'. This is useful if you have removed the working tree
635
 
    or if it was never created - i.e. if you pushed the branch to its current
636
 
    location using SFTP.
637
 
    
638
 
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
639
 
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
640
 
 
641
 
    To retrieve the branch as of a particular revision, supply the --revision
642
 
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
643
 
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
644
 
    code.)
645
 
 
646
 
    --basis is to speed up checking out from remote branches.  When specified, it
647
 
    uses the inventory and file contents from the basis branch in preference to the
648
 
    branch being checked out.
649
 
    """
650
 
    takes_args = ['branch_location?', 'to_location?']
651
 
    takes_options = ['revision', # , 'basis']
652
 
                     Option('lightweight',
653
 
                            help="perform a lightweight checkout. Lightweight "
654
 
                                 "checkouts depend on access to the branch for "
655
 
                                 "every operation. Normal checkouts can perform "
656
 
                                 "common operations like diff and status without "
657
 
                                 "such access, and also support local commits."
658
 
                            ),
659
 
                     ]
660
 
 
661
 
    def run(self, branch_location=None, to_location=None, revision=None, basis=None,
662
 
            lightweight=False):
663
 
        if revision is None:
664
 
            revision = [None]
665
 
        elif len(revision) > 1:
666
 
            raise BzrCommandError(
667
 
                'bzr checkout --revision takes exactly 1 revision value')
668
 
        if branch_location is None:
669
 
            branch_location = bzrlib.osutils.getcwd()
670
 
            to_location = branch_location
671
 
        source = Branch.open(branch_location)
672
 
        if len(revision) == 1 and revision[0] is not None:
673
 
            revision_id = revision[0].in_history(source)[1]
674
 
        else:
675
 
            revision_id = None
676
 
        if to_location is None:
677
 
            to_location = os.path.basename(branch_location.rstrip("/\\"))
678
 
        # if the source and to_location are the same, 
679
 
        # and there is no working tree,
680
 
        # then reconstitute a branch
681
 
        if (bzrlib.osutils.abspath(to_location) == 
682
 
            bzrlib.osutils.abspath(branch_location)):
683
 
            try:
684
 
                source.bzrdir.open_workingtree()
685
 
            except errors.NoWorkingTree:
686
 
                source.bzrdir.create_workingtree()
687
 
                return
688
 
        try:
689
 
            os.mkdir(to_location)
690
 
        except OSError, e:
691
 
            if e.errno == errno.EEXIST:
692
 
                raise BzrCommandError('Target directory "%s" already'
693
 
                                      ' exists.' % to_location)
694
 
            if e.errno == errno.ENOENT:
695
 
                raise BzrCommandError('Parent of "%s" does not exist.' %
696
 
                                      to_location)
697
 
            else:
698
 
                raise
699
 
        old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
700
 
        bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
701
 
        try:
702
 
            if lightweight:
703
 
                checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
704
 
                bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
705
 
            else:
706
 
                checkout_branch =  bzrlib.bzrdir.BzrDir.create_branch_convenience(
707
 
                    to_location, force_new_tree=False)
708
 
                checkout = checkout_branch.bzrdir
709
 
                checkout_branch.bind(source)
710
 
                if revision_id is not None:
711
 
                    rh = checkout_branch.revision_history()
712
 
                    checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
713
 
            checkout.create_workingtree(revision_id)
714
 
        finally:
715
 
            bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
 
432
            rmtree(cache_root)
716
433
 
717
434
 
718
435
class cmd_renames(Command):
723
440
    # TODO: Only show renames under dir, rather than in the whole branch.
724
441
    takes_args = ['dir?']
725
442
 
726
 
    @display_command
727
 
    def run(self, dir=u'.'):
728
 
        tree = WorkingTree.open_containing(dir)[0]
729
 
        old_inv = tree.basis_tree().inventory
730
 
        new_inv = tree.read_working_inventory()
 
443
    def run(self, dir='.'):
 
444
        b = Branch.open_containing(dir)[0]
 
445
        old_inv = b.basis_tree().inventory
 
446
        new_inv = b.read_working_inventory()
731
447
 
732
448
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
733
449
        renames.sort()
735
451
            print "%s => %s" % (old_name, new_name)        
736
452
 
737
453
 
738
 
class cmd_update(Command):
739
 
    """Update a tree to have the latest code committed to its branch.
740
 
    
741
 
    This will perform a merge into the working tree, and may generate
742
 
    conflicts. If you have any local changes, you will still 
743
 
    need to commit them after the update for the update to be complete.
744
 
    
745
 
    If you want to discard your local changes, you can just do a 
746
 
    'bzr revert' instead of 'bzr commit' after the update.
747
 
    """
748
 
    takes_args = ['dir?']
749
 
 
750
 
    def run(self, dir='.'):
751
 
        tree = WorkingTree.open_containing(dir)[0]
752
 
        tree.lock_write()
753
 
        try:
754
 
            if tree.last_revision() == tree.branch.last_revision():
755
 
                # may be up to date, check master too.
756
 
                master = tree.branch.get_master_branch()
757
 
                if master is None or master.last_revision == tree.last_revision():
758
 
                    note("Tree is up to date.")
759
 
                    return
760
 
            conflicts = tree.update()
761
 
            note('Updated to revision %d.' %
762
 
                 (tree.branch.revision_id_to_revno(tree.last_revision()),))
763
 
            if conflicts != 0:
764
 
                return 1
765
 
            else:
766
 
                return 0
767
 
        finally:
768
 
            tree.unlock()
769
 
 
770
 
 
771
454
class cmd_info(Command):
772
 
    """Show information about a working tree, branch or repository.
773
 
 
774
 
    This command will show all known locations and formats associated to the
775
 
    tree, branch or repository.  Statistical information is included with
776
 
    each report.
777
 
 
778
 
    Branches and working trees will also report any missing revisions.
779
 
    """
780
 
    takes_args = ['location?']
781
 
    takes_options = ['verbose']
782
 
 
783
 
    @display_command
784
 
    def run(self, location=None, verbose=False):
785
 
        from bzrlib.info import show_bzrdir_info
786
 
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
787
 
                         verbose=verbose)
 
455
    """Show statistical information about a branch."""
 
456
    takes_args = ['branch?']
 
457
    
 
458
    def run(self, branch=None):
 
459
        import info
 
460
        b = Branch.open_containing(branch)[0]
 
461
        info.show_info(b)
788
462
 
789
463
 
790
464
class cmd_remove(Command):
798
472
    aliases = ['rm']
799
473
    
800
474
    def run(self, file_list, verbose=False):
801
 
        tree, file_list = tree_files(file_list)
802
 
        tree.remove(file_list, verbose=verbose)
 
475
        b = Branch.open_containing(file_list[0])[0]
 
476
        tree = WorkingTree(b.base, b)
 
477
        tree.remove([tree.relpath(f) for f in file_list], verbose=verbose)
803
478
 
804
479
 
805
480
class cmd_file_id(Command):
811
486
    """
812
487
    hidden = True
813
488
    takes_args = ['filename']
814
 
    @display_command
815
489
    def run(self, filename):
816
 
        tree, relpath = WorkingTree.open_containing(filename)
817
 
        i = tree.inventory.path2id(relpath)
 
490
        b, relpath = Branch.open_containing(filename)
 
491
        i = b.inventory.path2id(relpath)
818
492
        if i == None:
819
493
            raise BzrError("%r is not a versioned file" % filename)
820
494
        else:
828
502
    starting at the branch root."""
829
503
    hidden = True
830
504
    takes_args = ['filename']
831
 
    @display_command
832
505
    def run(self, filename):
833
 
        tree, relpath = WorkingTree.open_containing(filename)
834
 
        inv = tree.inventory
 
506
        b, relpath = Branch.open_containing(filename)
 
507
        inv = b.inventory
835
508
        fid = inv.path2id(relpath)
836
509
        if fid == None:
837
510
            raise BzrError("%r is not a versioned file" % filename)
839
512
            print fip
840
513
 
841
514
 
842
 
class cmd_reconcile(Command):
843
 
    """Reconcile bzr metadata in a branch.
844
 
 
845
 
    This can correct data mismatches that may have been caused by
846
 
    previous ghost operations or bzr upgrades. You should only
847
 
    need to run this command if 'bzr check' or a bzr developer 
848
 
    advises you to run it.
849
 
 
850
 
    If a second branch is provided, cross-branch reconciliation is
851
 
    also attempted, which will check that data like the tree root
852
 
    id which was not present in very early bzr versions is represented
853
 
    correctly in both branches.
854
 
 
855
 
    At the same time it is run it may recompress data resulting in 
856
 
    a potential saving in disk space or performance gain.
857
 
 
858
 
    The branch *MUST* be on a listable system such as local disk or sftp.
859
 
    """
860
 
    takes_args = ['branch?']
861
 
 
862
 
    def run(self, branch="."):
863
 
        from bzrlib.reconcile import reconcile
864
 
        dir = bzrlib.bzrdir.BzrDir.open(branch)
865
 
        reconcile(dir)
866
 
 
867
 
 
868
515
class cmd_revision_history(Command):
869
516
    """Display list of revision ids on this branch."""
870
517
    hidden = True
871
 
    @display_command
872
518
    def run(self):
873
 
        branch = WorkingTree.open_containing(u'.')[0].branch
874
 
        for patchid in branch.revision_history():
 
519
        for patchid in Branch.open_containing('.')[0].revision_history():
875
520
            print patchid
876
521
 
877
522
 
878
523
class cmd_ancestry(Command):
879
524
    """List all revisions merged into this branch."""
880
525
    hidden = True
881
 
    @display_command
882
526
    def run(self):
883
 
        tree = WorkingTree.open_containing(u'.')[0]
884
 
        b = tree.branch
885
 
        # FIXME. should be tree.last_revision
886
 
        for revision_id in b.repository.get_ancestry(b.last_revision()):
 
527
        b = find_branch('.')
 
528
        for revision_id in b.get_ancestry(b.last_revision()):
887
529
            print revision_id
888
530
 
889
531
 
 
532
class cmd_directories(Command):
 
533
    """Display list of versioned directories in this branch."""
 
534
    def run(self):
 
535
        for name, ie in Branch.open_containing('.')[0].read_working_inventory().directories():
 
536
            if name == '':
 
537
                print '.'
 
538
            else:
 
539
                print name
 
540
 
 
541
 
890
542
class cmd_init(Command):
891
543
    """Make a directory into a versioned branch.
892
544
 
893
545
    Use this to create an empty branch, or before importing an
894
546
    existing project.
895
547
 
896
 
    If there is a repository in a parent directory of the location, then 
897
 
    the history of the branch will be stored in the repository.  Otherwise
898
 
    init creates a standalone branch which carries its own history in 
899
 
    .bzr.
900
 
 
901
 
    If there is already a branch at the location but it has no working tree,
902
 
    the tree can be populated with 'bzr checkout'.
903
 
 
904
548
    Recipe for importing a tree of files:
905
549
        cd ~/project
906
550
        bzr init
907
 
        bzr add .
 
551
        bzr add -v .
908
552
        bzr status
909
553
        bzr commit -m 'imported project'
910
554
    """
911
 
    takes_args = ['location?']
912
 
    takes_options = [
913
 
                     Option('format', 
914
 
                            help='Specify a format for this branch. Current'
915
 
                                 ' formats are: default, knit, metaweave and'
916
 
                                 ' weave. Default is knit; metaweave and'
917
 
                                 ' weave are deprecated',
918
 
                            type=get_format_type),
919
 
                     ]
920
 
    def run(self, location=None, format=None):
921
 
        from bzrlib.branch import Branch
922
 
        if format is None:
923
 
            format = get_format_type('default')
924
 
        if location is None:
925
 
            location = u'.'
926
 
        else:
927
 
            # The path has to exist to initialize a
928
 
            # branch inside of it.
929
 
            # Just using os.mkdir, since I don't
930
 
            # believe that we want to create a bunch of
931
 
            # locations if the user supplies an extended path
932
 
            if not os.path.exists(location):
933
 
                os.mkdir(location)
934
 
        try:
935
 
            existing_bzrdir = bzrdir.BzrDir.open(location)
936
 
        except NotBranchError:
937
 
            # really a NotBzrDir error...
938
 
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
939
 
        else:
940
 
            if existing_bzrdir.has_branch():
941
 
                if existing_bzrdir.has_workingtree():
942
 
                    raise errors.AlreadyBranchError(location)
943
 
                else:
944
 
                    raise errors.BranchExistsWithoutWorkingTree(location)
945
 
            else:
946
 
                existing_bzrdir.create_branch()
947
 
                existing_bzrdir.create_workingtree()
948
 
 
949
 
 
950
 
class cmd_init_repository(Command):
951
 
    """Create a shared repository to hold branches.
952
 
 
953
 
    New branches created under the repository directory will store their revisions
954
 
    in the repository, not in the branch directory, if the branch format supports
955
 
    shared storage.
956
 
 
957
 
    example:
958
 
        bzr init-repo repo
959
 
        bzr init repo/trunk
960
 
        bzr checkout --lightweight repo/trunk trunk-checkout
961
 
        cd trunk-checkout
962
 
        (add files here)
963
 
    """
964
 
    takes_args = ["location"] 
965
 
    takes_options = [Option('format', 
966
 
                            help='Specify a format for this repository.'
967
 
                                 ' Current formats are: default, knit,'
968
 
                                 ' metaweave and weave. Default is knit;'
969
 
                                 ' metaweave and weave are deprecated',
970
 
                            type=get_format_type),
971
 
                     Option('trees',
972
 
                             help='Allows branches in repository to have'
973
 
                             ' a working tree')]
974
 
    aliases = ["init-repo"]
975
 
    def run(self, location, format=None, trees=False):
976
 
        from bzrlib.transport import get_transport
977
 
        if format is None:
978
 
            format = get_format_type('default')
979
 
        transport = get_transport(location)
980
 
        if not transport.has('.'):
981
 
            transport.mkdir('')
982
 
        newdir = format.initialize_on_transport(transport)
983
 
        repo = newdir.create_repository(shared=True)
984
 
        repo.set_make_working_trees(trees)
 
555
    def run(self):
 
556
        Branch.initialize('.')
985
557
 
986
558
 
987
559
class cmd_diff(Command):
990
562
    If files are listed, only the changes in those files are listed.
991
563
    Otherwise, all changes for the tree are listed.
992
564
 
993
 
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
994
 
    produces patches suitable for "patch -p1".
995
 
 
996
565
    examples:
997
566
        bzr diff
998
567
        bzr diff -r1
999
568
        bzr diff -r1..2
1000
 
        bzr diff --diff-prefix old/:new/
1001
 
        bzr diff bzr.mine bzr.dev
1002
 
        bzr diff foo.c
1003
569
    """
 
570
    # TODO: Allow diff across branches.
1004
571
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
1005
572
    #       or a graphical diff.
1006
573
 
1007
574
    # TODO: Python difflib is not exactly the same as unidiff; should
1008
575
    #       either fix it up or prefer to use an external diff.
1009
576
 
 
577
    # TODO: If a directory is given, diff everything under that.
 
578
 
1010
579
    # TODO: Selected-file diff is inefficient and doesn't show you
1011
580
    #       deleted files.
1012
581
 
1013
582
    # TODO: This probably handles non-Unix newlines poorly.
1014
583
    
1015
584
    takes_args = ['file*']
1016
 
    takes_options = ['revision', 'diff-options', 'prefix']
 
585
    takes_options = ['revision', 'diff-options']
1017
586
    aliases = ['di', 'dif']
1018
587
 
1019
 
    @display_command
1020
 
    def run(self, revision=None, file_list=None, diff_options=None,
1021
 
            prefix=None):
1022
 
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
 
588
    def run(self, revision=None, file_list=None, diff_options=None):
 
589
        from bzrlib.diff import show_diff
1023
590
 
1024
 
        if (prefix is None) or (prefix == '0'):
1025
 
            # diff -p0 format
1026
 
            old_label = ''
1027
 
            new_label = ''
1028
 
        elif prefix == '1':
1029
 
            old_label = 'old/'
1030
 
            new_label = 'new/'
 
591
        if file_list:
 
592
            b = Branch.open_containing(file_list[0])[0]
 
593
            tree = WorkingTree(b.base, b)
 
594
            file_list = [tree.relpath(f) for f in file_list]
 
595
            if file_list == ['']:
 
596
                # just pointing to top-of-tree
 
597
                file_list = None
1031
598
        else:
1032
 
            if not ':' in prefix:
1033
 
                 raise BzrError("--diff-prefix expects two values separated by a colon")
1034
 
            old_label, new_label = prefix.split(":")
1035
 
        
1036
 
        try:
1037
 
            tree1, file_list = internal_tree_files(file_list)
1038
 
            tree2 = None
1039
 
            b = None
1040
 
            b2 = None
1041
 
        except FileInWrongBranch:
1042
 
            if len(file_list) != 2:
1043
 
                raise BzrCommandError("Files are in different branches")
 
599
            b = Branch.open_containing('.')[0]
1044
600
 
1045
 
            tree1, file1 = WorkingTree.open_containing(file_list[0])
1046
 
            tree2, file2 = WorkingTree.open_containing(file_list[1])
1047
 
            if file1 != "" or file2 != "":
1048
 
                # FIXME diff those two files. rbc 20051123
1049
 
                raise BzrCommandError("Files are in different branches")
1050
 
            file_list = None
1051
601
        if revision is not None:
1052
 
            if tree2 is not None:
1053
 
                raise BzrCommandError("Can't specify -r with two branches")
1054
 
            if (len(revision) == 1) or (revision[1].spec is None):
1055
 
                return diff_cmd_helper(tree1, file_list, diff_options,
1056
 
                                       revision[0], 
1057
 
                                       old_label=old_label, new_label=new_label)
 
602
            if len(revision) == 1:
 
603
                show_diff(b, revision[0], specific_files=file_list,
 
604
                          external_diff_options=diff_options)
1058
605
            elif len(revision) == 2:
1059
 
                return diff_cmd_helper(tree1, file_list, diff_options,
1060
 
                                       revision[0], revision[1],
1061
 
                                       old_label=old_label, new_label=new_label)
 
606
                show_diff(b, revision[0], specific_files=file_list,
 
607
                          external_diff_options=diff_options,
 
608
                          revision2=revision[1])
1062
609
            else:
1063
610
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
1064
611
        else:
1065
 
            if tree2 is not None:
1066
 
                return show_diff_trees(tree1, tree2, sys.stdout, 
1067
 
                                       specific_files=file_list,
1068
 
                                       external_diff_options=diff_options,
1069
 
                                       old_label=old_label, new_label=new_label)
1070
 
            else:
1071
 
                return diff_cmd_helper(tree1, file_list, diff_options,
1072
 
                                       old_label=old_label, new_label=new_label)
 
612
            show_diff(b, None, specific_files=file_list,
 
613
                      external_diff_options=diff_options)
 
614
 
 
615
        
1073
616
 
1074
617
 
1075
618
class cmd_deleted(Command):
1081
624
    # directories with readdir, rather than stating each one.  Same
1082
625
    # level of effort but possibly much less IO.  (Or possibly not,
1083
626
    # if the directories are very large...)
1084
 
    @display_command
1085
627
    def run(self, show_ids=False):
1086
 
        tree = WorkingTree.open_containing(u'.')[0]
1087
 
        old = tree.basis_tree()
 
628
        b = Branch.open_containing('.')[0]
 
629
        old = b.basis_tree()
 
630
        new = b.working_tree()
1088
631
        for path, ie in old.inventory.iter_entries():
1089
 
            if not tree.has_id(ie.file_id):
 
632
            if not new.has_id(ie.file_id):
1090
633
                if show_ids:
1091
634
                    print '%-50s %s' % (path, ie.file_id)
1092
635
                else:
1096
639
class cmd_modified(Command):
1097
640
    """List files modified in working tree."""
1098
641
    hidden = True
1099
 
    @display_command
1100
642
    def run(self):
1101
643
        from bzrlib.delta import compare_trees
1102
644
 
1103
 
        tree = WorkingTree.open_containing(u'.')[0]
1104
 
        td = compare_trees(tree.basis_tree(), tree)
 
645
        b = Branch.open_containing('.')[0]
 
646
        td = compare_trees(b.basis_tree(), b.working_tree())
1105
647
 
1106
648
        for path, id, kind, text_modified, meta_modified in td.modified:
1107
649
            print path
1111
653
class cmd_added(Command):
1112
654
    """List files added in working tree."""
1113
655
    hidden = True
1114
 
    @display_command
1115
656
    def run(self):
1116
 
        wt = WorkingTree.open_containing(u'.')[0]
1117
 
        basis_inv = wt.basis_tree().inventory
 
657
        b = Branch.open_containing('.')[0]
 
658
        wt = b.working_tree()
 
659
        basis_inv = b.basis_tree().inventory
1118
660
        inv = wt.inventory
1119
661
        for file_id in inv:
1120
662
            if file_id in basis_inv:
1121
663
                continue
1122
664
            path = inv.id2path(file_id)
1123
 
            if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
 
665
            if not os.access(b.abspath(path), os.F_OK):
1124
666
                continue
1125
667
            print path
1126
668
                
1132
674
    The root is the nearest enclosing directory with a .bzr control
1133
675
    directory."""
1134
676
    takes_args = ['filename?']
1135
 
    @display_command
1136
677
    def run(self, filename=None):
1137
678
        """Print the branch root."""
1138
 
        tree = WorkingTree.open_containing(filename)[0]
1139
 
        print tree.basedir
 
679
        b = Branch.open_containing(filename)[0]
 
680
        print b.base
1140
681
 
1141
682
 
1142
683
class cmd_log(Command):
1143
 
    """Show log of a branch, file, or directory.
1144
 
 
1145
 
    By default show the log of the branch containing the working directory.
1146
 
 
1147
 
    To request a range of logs, you can use the command -r begin..end
1148
 
    -r revision requests a specific revision, -r ..end or -r begin.. are
 
684
    """Show log of this branch.
 
685
 
 
686
    To request a range of logs, you can use the command -r begin:end
 
687
    -r revision requests a specific revision, -r :end or -r begin: are
1149
688
    also valid.
1150
 
 
1151
 
    examples:
1152
 
        bzr log
1153
 
        bzr log foo.c
1154
 
        bzr log -r -10.. http://server/branch
1155
689
    """
1156
690
 
1157
691
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1158
692
 
1159
 
    takes_args = ['location?']
 
693
    takes_args = ['filename?']
1160
694
    takes_options = [Option('forward', 
1161
695
                            help='show from oldest to newest'),
1162
 
                     'timezone', 
1163
 
                     Option('verbose', 
1164
 
                             help='show files changed in each revision'),
 
696
                     'timezone', 'verbose', 
1165
697
                     'show-ids', 'revision',
1166
 
                     'log-format',
1167
 
                     'line', 'long', 
 
698
                     Option('line', help='format with one line per revision'),
 
699
                     'long', 
1168
700
                     Option('message',
1169
701
                            help='show revisions whose message matches this regexp',
1170
702
                            type=str),
1171
 
                     'short',
 
703
                     Option('short', help='use moderately short format'),
1172
704
                     ]
1173
 
    @display_command
1174
 
    def run(self, location=None, timezone='original',
 
705
    
 
706
    def run(self, filename=None, timezone='original',
1175
707
            verbose=False,
1176
708
            show_ids=False,
1177
709
            forward=False,
1178
710
            revision=None,
1179
 
            log_format=None,
1180
711
            message=None,
1181
712
            long=False,
1182
713
            short=False,
1187
718
            "invalid message argument %r" % message
1188
719
        direction = (forward and 'forward') or 'reverse'
1189
720
        
1190
 
        # log everything
1191
 
        file_id = None
1192
 
        if location:
1193
 
            # find the file id to log:
1194
 
 
1195
 
            dir, fp = bzrdir.BzrDir.open_containing(location)
1196
 
            b = dir.open_branch()
 
721
        if filename:
 
722
            b, fp = Branch.open_containing(filename)
1197
723
            if fp != '':
1198
 
                try:
1199
 
                    # might be a tree:
1200
 
                    inv = dir.open_workingtree().inventory
1201
 
                except (errors.NotBranchError, errors.NotLocalUrl):
1202
 
                    # either no tree, or is remote.
1203
 
                    inv = b.basis_tree().inventory
1204
 
                file_id = inv.path2id(fp)
 
724
                file_id = b.read_working_inventory().path2id(fp)
 
725
            else:
 
726
                file_id = None  # points to branch root
1205
727
        else:
1206
 
            # local dir only
1207
 
            # FIXME ? log the current subdir only RBC 20060203 
1208
 
            dir, relpath = bzrdir.BzrDir.open_containing('.')
1209
 
            b = dir.open_branch()
 
728
            b, relpath = Branch.open_containing('.')
 
729
            file_id = None
1210
730
 
1211
731
        if revision is None:
1212
732
            rev1 = None
1214
734
        elif len(revision) == 1:
1215
735
            rev1 = rev2 = revision[0].in_history(b).revno
1216
736
        elif len(revision) == 2:
1217
 
            if revision[0].spec is None:
1218
 
                # missing begin-range means first revision
1219
 
                rev1 = 1
1220
 
            else:
1221
 
                rev1 = revision[0].in_history(b).revno
1222
 
 
1223
 
            if revision[1].spec is None:
1224
 
                # missing end-range means last known revision
1225
 
                rev2 = b.revno()
1226
 
            else:
1227
 
                rev2 = revision[1].in_history(b).revno
 
737
            rev1 = revision[0].in_history(b).revno
 
738
            rev2 = revision[1].in_history(b).revno
1228
739
        else:
1229
740
            raise BzrCommandError('bzr log --revision takes one or two values.')
1230
741
 
1231
 
        # By this point, the revision numbers are converted to the +ve
1232
 
        # form if they were supplied in the -ve form, so we can do
1233
 
        # this comparison in relative safety
1234
 
        if rev1 > rev2:
1235
 
            (rev2, rev1) = (rev1, rev2)
 
742
        if rev1 == 0:
 
743
            rev1 = None
 
744
        if rev2 == 0:
 
745
            rev2 = None
1236
746
 
1237
 
        mutter('encoding log as %r', bzrlib.user_encoding)
 
747
        mutter('encoding log as %r' % bzrlib.user_encoding)
1238
748
 
1239
749
        # use 'replace' so that we don't abort if trying to write out
1240
750
        # in e.g. the default C locale.
1241
751
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1242
752
 
1243
 
        if (log_format == None):
1244
 
            default = bzrlib.config.BranchConfig(b).log_format()
1245
 
            log_format = get_log_format(long=long, short=short, line=line, default=default)
1246
 
 
 
753
        log_format = 'long'
 
754
        if short:
 
755
            log_format = 'short'
 
756
        if line:
 
757
            log_format = 'line'
1247
758
        lf = log_formatter(log_format,
1248
759
                           show_ids=show_ids,
1249
760
                           to_file=outf,
1259
770
                 search=message)
1260
771
 
1261
772
 
1262
 
def get_log_format(long=False, short=False, line=False, default='long'):
1263
 
    log_format = default
1264
 
    if long:
1265
 
        log_format = 'long'
1266
 
    if short:
1267
 
        log_format = 'short'
1268
 
    if line:
1269
 
        log_format = 'line'
1270
 
    return log_format
1271
 
 
1272
773
 
1273
774
class cmd_touching_revisions(Command):
1274
775
    """Return revision-ids which affected a particular file.
1276
777
    A more user-friendly interface is "bzr log FILE"."""
1277
778
    hidden = True
1278
779
    takes_args = ["filename"]
1279
 
    @display_command
1280
780
    def run(self, filename):
1281
 
        tree, relpath = WorkingTree.open_containing(filename)
1282
 
        b = tree.branch
1283
 
        inv = tree.read_working_inventory()
 
781
        b, relpath = Branch.open_containing(filename)[0]
 
782
        inv = b.read_working_inventory()
1284
783
        file_id = inv.path2id(relpath)
1285
784
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1286
785
            print "%6d %s" % (revno, what)
1291
790
    """
1292
791
    # TODO: Take a revision or remote path and list that tree instead.
1293
792
    hidden = True
1294
 
    takes_options = ['verbose', 'revision',
1295
 
                     Option('non-recursive',
1296
 
                            help='don\'t recurse into sub-directories'),
1297
 
                     Option('from-root',
1298
 
                            help='Print all paths from the root of the branch.'),
1299
 
                     Option('unknown', help='Print unknown files'),
1300
 
                     Option('versioned', help='Print versioned files'),
1301
 
                     Option('ignored', help='Print ignored files'),
1302
 
 
1303
 
                     Option('null', help='Null separate the files'),
1304
 
                    ]
1305
 
    @display_command
1306
 
    def run(self, revision=None, verbose=False, 
1307
 
            non_recursive=False, from_root=False,
1308
 
            unknown=False, versioned=False, ignored=False,
1309
 
            null=False):
1310
 
 
1311
 
        if verbose and null:
1312
 
            raise BzrCommandError('Cannot set both --verbose and --null')
1313
 
        all = not (unknown or versioned or ignored)
1314
 
 
1315
 
        selection = {'I':ignored, '?':unknown, 'V':versioned}
1316
 
 
1317
 
        tree, relpath = WorkingTree.open_containing(u'.')
1318
 
        if from_root:
1319
 
            relpath = u''
1320
 
        elif relpath:
1321
 
            relpath += '/'
1322
 
        if revision is not None:
1323
 
            tree = tree.branch.repository.revision_tree(
1324
 
                revision[0].in_history(tree.branch).rev_id)
 
793
    def run(self, revision=None, verbose=False):
 
794
        b, relpath = Branch.open_containing('.')[0]
 
795
        if revision == None:
 
796
            tree = b.working_tree()
 
797
        else:
 
798
            tree = b.revision_tree(revision.in_history(b).rev_id)
1325
799
        for fp, fc, kind, fid, entry in tree.list_files():
1326
 
            if fp.startswith(relpath):
1327
 
                fp = fp[len(relpath):]
1328
 
                if non_recursive and '/' in fp:
1329
 
                    continue
1330
 
                if not all and not selection[fc]:
1331
 
                    continue
1332
 
                if verbose:
1333
 
                    kindch = entry.kind_character()
1334
 
                    print '%-8s %s%s' % (fc, fp, kindch)
1335
 
                elif null:
1336
 
                    sys.stdout.write(fp)
1337
 
                    sys.stdout.write('\0')
1338
 
                    sys.stdout.flush()
1339
 
                else:
1340
 
                    print fp
 
800
            if verbose:
 
801
                kindch = entry.kind_character()
 
802
                print '%-8s %s%s' % (fc, fp, kindch)
 
803
            else:
 
804
                print fp
 
805
 
1341
806
 
1342
807
 
1343
808
class cmd_unknowns(Command):
1344
809
    """List unknown files."""
1345
 
    @display_command
1346
810
    def run(self):
1347
811
        from bzrlib.osutils import quotefn
1348
 
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
812
        for f in Branch.open_containing('.')[0].unknowns():
1349
813
            print quotefn(f)
1350
814
 
1351
815
 
 
816
 
1352
817
class cmd_ignore(Command):
1353
818
    """Ignore a command or pattern.
1354
819
 
1374
839
        from bzrlib.atomicfile import AtomicFile
1375
840
        import os.path
1376
841
 
1377
 
        tree, relpath = WorkingTree.open_containing(u'.')
1378
 
        ifn = tree.abspath('.bzrignore')
 
842
        b, relpath = Branch.open_containing('.')
 
843
        ifn = b.abspath('.bzrignore')
1379
844
 
1380
845
        if os.path.exists(ifn):
1381
846
            f = open(ifn, 'rt')
1400
865
        finally:
1401
866
            f.close()
1402
867
 
1403
 
        inv = tree.inventory
 
868
        inv = b.working_tree().inventory
1404
869
        if inv.path2id('.bzrignore'):
1405
870
            mutter('.bzrignore is already versioned')
1406
871
        else:
1407
872
            mutter('need to make new .bzrignore file versioned')
1408
 
            tree.add(['.bzrignore'])
 
873
            b.add(['.bzrignore'])
 
874
 
1409
875
 
1410
876
 
1411
877
class cmd_ignored(Command):
1412
878
    """List ignored files and the patterns that matched them.
1413
879
 
1414
880
    See also: bzr ignore"""
1415
 
    @display_command
1416
881
    def run(self):
1417
 
        tree = WorkingTree.open_containing(u'.')[0]
 
882
        tree = Branch.open_containing('.')[0].working_tree()
1418
883
        for path, file_class, kind, file_id, entry in tree.list_files():
1419
884
            if file_class != 'I':
1420
885
                continue
1432
897
    hidden = True
1433
898
    takes_args = ['revno']
1434
899
    
1435
 
    @display_command
1436
900
    def run(self, revno):
1437
901
        try:
1438
902
            revno = int(revno)
1439
903
        except ValueError:
1440
904
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1441
905
 
1442
 
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
906
        print Branch.open_containing('.')[0].get_rev_id(revno)
1443
907
 
1444
908
 
1445
909
class cmd_export(Command):
1452
916
    is found exports to a directory (equivalent to --format=dir).
1453
917
 
1454
918
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1455
 
    is given, the top directory will be the root name of the file.
1456
 
 
1457
 
    Note: export of tree with non-ascii filenames to zip is not supported.
1458
 
 
1459
 
     Supported formats       Autodetected by extension
1460
 
     -----------------       -------------------------
1461
 
         dir                            -
1462
 
         tar                          .tar
1463
 
         tbz2                    .tar.bz2, .tbz2
1464
 
         tgz                      .tar.gz, .tgz
1465
 
         zip                          .zip
1466
 
    """
 
919
    is given, the top directory will be the root name of the file."""
 
920
    # TODO: list known exporters
1467
921
    takes_args = ['dest']
1468
922
    takes_options = ['revision', 'format', 'root']
1469
923
    def run(self, dest, revision=None, format=None, root=None):
1470
924
        import os.path
1471
 
        from bzrlib.export import export
1472
 
        tree = WorkingTree.open_containing(u'.')[0]
1473
 
        b = tree.branch
 
925
        b = Branch.open_containing('.')[0]
1474
926
        if revision is None:
1475
 
            # should be tree.last_revision  FIXME
1476
927
            rev_id = b.last_revision()
1477
928
        else:
1478
929
            if len(revision) != 1:
1479
930
                raise BzrError('bzr export --revision takes exactly 1 argument')
1480
931
            rev_id = revision[0].in_history(b).rev_id
1481
 
        t = b.repository.revision_tree(rev_id)
1482
 
        try:
1483
 
            export(t, dest, format, root)
1484
 
        except errors.NoSuchExportFormat, e:
1485
 
            raise BzrCommandError('Unsupported export format: %s' % e.format)
 
932
        t = b.revision_tree(rev_id)
 
933
        arg_root, ext = os.path.splitext(os.path.basename(dest))
 
934
        if ext in ('.gz', '.bz2'):
 
935
            new_root, new_ext = os.path.splitext(arg_root)
 
936
            if new_ext == '.tar':
 
937
                arg_root = new_root
 
938
                ext = new_ext + ext
 
939
        if root is None:
 
940
            root = arg_root
 
941
        if not format:
 
942
            if ext in (".tar",):
 
943
                format = "tar"
 
944
            elif ext in (".tar.gz", ".tgz"):
 
945
                format = "tgz"
 
946
            elif ext in (".tar.bz2", ".tbz2"):
 
947
                format = "tbz2"
 
948
            else:
 
949
                format = "dir"
 
950
        t.export(dest, format, root)
1486
951
 
1487
952
 
1488
953
class cmd_cat(Command):
1491
956
    takes_options = ['revision']
1492
957
    takes_args = ['filename']
1493
958
 
1494
 
    @display_command
1495
959
    def run(self, filename, revision=None):
1496
 
        if revision is not None and len(revision) != 1:
 
960
        if revision is None:
 
961
            raise BzrCommandError("bzr cat requires a revision number")
 
962
        elif len(revision) != 1:
1497
963
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1498
 
        tree = None
1499
 
        try:
1500
 
            tree, relpath = WorkingTree.open_containing(filename)
1501
 
            b = tree.branch
1502
 
        except NotBranchError:
1503
 
            pass
1504
 
 
1505
 
        if tree is None:
1506
 
            b, relpath = Branch.open_containing(filename)
1507
 
        if revision is None:
1508
 
            revision_id = b.last_revision()
1509
 
        else:
1510
 
            revision_id = revision[0].in_history(b).rev_id
1511
 
        b.print_file(relpath, revision_id)
 
964
        b, relpath = Branch.open_containing(filename)
 
965
        b.print_file(relpath, revision[0].in_history(b).revno)
1512
966
 
1513
967
 
1514
968
class cmd_local_time_offset(Command):
1515
969
    """Show the offset in seconds from GMT to local time."""
1516
970
    hidden = True    
1517
 
    @display_command
1518
971
    def run(self):
1519
972
        print bzrlib.osutils.local_time_offset()
1520
973
 
1552
1005
                     Option('strict',
1553
1006
                            help="refuse to commit if there are unknown "
1554
1007
                            "files in the working tree."),
1555
 
                     Option('local',
1556
 
                            help="perform a local only commit in a bound "
1557
 
                                 "branch. Such commits are not pushed to "
1558
 
                                 "the master branch until a normal commit "
1559
 
                                 "is performed."
1560
 
                            ),
1561
1008
                     ]
1562
1009
    aliases = ['ci', 'checkin']
1563
1010
 
1564
1011
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1565
 
            unchanged=False, strict=False, local=False):
1566
 
        from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
 
1012
            unchanged=False, strict=False):
1567
1013
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1568
1014
                StrictCommitFailed)
1569
 
        from bzrlib.msgeditor import edit_commit_message, \
1570
 
                make_commit_message_template
1571
 
        from tempfile import TemporaryFile
1572
 
        import codecs
1573
 
 
1574
 
        # TODO: Need a blackbox test for invoking the external editor; may be
1575
 
        # slightly problematic to run this cross-platform.
1576
 
 
1577
 
        # TODO: do more checks that the commit will succeed before 
1578
 
        # spending the user's valuable time typing a commit message.
1579
 
        #
1580
 
        # TODO: if the commit *does* happen to fail, then save the commit 
1581
 
        # message to a temporary file where it can be recovered
1582
 
        tree, selected_list = tree_files(selected_list)
1583
 
        if local and not tree.branch.get_bound_location():
1584
 
            raise errors.LocalRequiresBoundBranch()
 
1015
        from bzrlib.msgeditor import edit_commit_message
 
1016
        from bzrlib.status import show_status
 
1017
        from cStringIO import StringIO
 
1018
 
 
1019
        b = Branch.open_containing('.')[0]
 
1020
        tree = WorkingTree(b.base, b)
 
1021
        if selected_list:
 
1022
            selected_list = [tree.relpath(s) for s in selected_list]
1585
1023
        if message is None and not file:
1586
 
            template = make_commit_message_template(tree, selected_list)
1587
 
            message = edit_commit_message(template)
 
1024
            catcher = StringIO()
 
1025
            show_status(b, specific_files=selected_list,
 
1026
                        to_file=catcher)
 
1027
            message = edit_commit_message(catcher.getvalue())
 
1028
 
1588
1029
            if message is None:
1589
1030
                raise BzrCommandError("please specify a commit message"
1590
1031
                                      " with either --message or --file")
1597
1038
 
1598
1039
        if message == "":
1599
1040
                raise BzrCommandError("empty commit message specified")
1600
 
        
1601
 
        if verbose:
1602
 
            reporter = ReportCommitToLog()
1603
 
        else:
1604
 
            reporter = NullCommitReporter()
1605
 
        
 
1041
            
1606
1042
        try:
1607
 
            tree.commit(message, specific_files=selected_list,
1608
 
                        allow_pointless=unchanged, strict=strict, local=local,
1609
 
                        reporter=reporter)
 
1043
            b.commit(message, specific_files=selected_list,
 
1044
                     allow_pointless=unchanged, strict=strict)
1610
1045
        except PointlessCommit:
1611
1046
            # FIXME: This should really happen before the file is read in;
1612
1047
            # perhaps prepare the commit; get the message; then actually commit
1618
1053
        except StrictCommitFailed:
1619
1054
            raise BzrCommandError("Commit refused because there are unknown "
1620
1055
                                  "files in the working tree.")
1621
 
        except errors.BoundBranchOutOfDate, e:
1622
 
            raise BzrCommandError(str(e)
1623
 
                                  + ' Either unbind, update, or'
1624
 
                                    ' pass --local to commit.')
1625
1056
 
1626
1057
 
1627
1058
class cmd_check(Command):
1630
1061
    This command checks various invariants about the branch storage to
1631
1062
    detect data corruption or bzr bugs.
1632
1063
    """
1633
 
    takes_args = ['branch?']
 
1064
    takes_args = ['dir?']
1634
1065
    takes_options = ['verbose']
1635
1066
 
1636
 
    def run(self, branch=None, verbose=False):
 
1067
    def run(self, dir='.', verbose=False):
1637
1068
        from bzrlib.check import check
1638
 
        if branch is None:
1639
 
            tree = WorkingTree.open_containing()[0]
1640
 
            branch = tree.branch
1641
 
        else:
1642
 
            branch = Branch.open(branch)
1643
 
        check(branch, verbose)
 
1069
        check(Branch.open_containing(dir)[0], verbose)
1644
1070
 
1645
1071
 
1646
1072
class cmd_scan_cache(Command):
1648
1074
    def run(self):
1649
1075
        from bzrlib.hashcache import HashCache
1650
1076
 
1651
 
        c = HashCache(u'.')
 
1077
        c = HashCache('.')
1652
1078
        c.read()
1653
1079
        c.scan()
1654
1080
            
1660
1086
 
1661
1087
        if c.needs_write:
1662
1088
            c.write()
 
1089
            
1663
1090
 
1664
1091
 
1665
1092
class cmd_upgrade(Command):
1666
1093
    """Upgrade branch storage to current format.
1667
1094
 
1668
1095
    The check command or bzr developers may sometimes advise you to run
1669
 
    this command. When the default format has changed you may also be warned
1670
 
    during other operations to upgrade.
 
1096
    this command.
 
1097
 
 
1098
    This version of this command upgrades from the full-text storage
 
1099
    used by bzr 0.0.8 and earlier to the weave format (v5).
1671
1100
    """
1672
 
    takes_args = ['url?']
1673
 
    takes_options = [
1674
 
                     Option('format', 
1675
 
                            help='Upgrade to a specific format. Current formats'
1676
 
                                 ' are: default, knit, metaweave and weave.'
1677
 
                                 ' Default is knit; metaweave and weave are'
1678
 
                                 ' deprecated',
1679
 
                            type=get_format_type),
1680
 
                    ]
1681
 
 
1682
 
 
1683
 
    def run(self, url='.', format=None):
 
1101
    takes_args = ['dir?']
 
1102
 
 
1103
    def run(self, dir='.'):
1684
1104
        from bzrlib.upgrade import upgrade
1685
 
        if format is None:
1686
 
            format = get_format_type('default')
1687
 
        upgrade(url, format)
 
1105
        upgrade(dir)
1688
1106
 
1689
1107
 
1690
1108
class cmd_whoami(Command):
1691
1109
    """Show bzr user id."""
1692
1110
    takes_options = ['email']
1693
1111
    
1694
 
    @display_command
1695
1112
    def run(self, email=False):
1696
1113
        try:
1697
 
            b = WorkingTree.open_containing(u'.')[0].branch
 
1114
            b = bzrlib.branch.Branch.open_containing('.')[0]
1698
1115
            config = bzrlib.config.BranchConfig(b)
1699
1116
        except NotBranchError:
1700
1117
            config = bzrlib.config.GlobalConfig()
1705
1122
            print config.username()
1706
1123
 
1707
1124
 
1708
 
class cmd_nick(Command):
1709
 
    """Print or set the branch nickname.  
1710
 
 
1711
 
    If unset, the tree root directory name is used as the nickname
1712
 
    To print the current nickname, execute with no argument.  
1713
 
    """
1714
 
    takes_args = ['nickname?']
1715
 
    def run(self, nickname=None):
1716
 
        branch = Branch.open_containing(u'.')[0]
1717
 
        if nickname is None:
1718
 
            self.printme(branch)
1719
 
        else:
1720
 
            branch.nick = nickname
1721
 
 
1722
 
    @display_command
1723
 
    def printme(self, branch):
1724
 
        print branch.nick 
1725
 
 
1726
 
 
1727
1125
class cmd_selftest(Command):
1728
1126
    """Run internal test suite.
1729
1127
    
1730
1128
    This creates temporary test directories in the working directory,
1731
1129
    but not existing data is affected.  These directories are deleted
1732
1130
    if the tests pass, or left behind to help in debugging if they
1733
 
    fail and --keep-output is specified.
 
1131
    fail.
1734
1132
    
1735
1133
    If arguments are given, they are regular expressions that say
1736
1134
    which tests should run.
1737
 
 
1738
 
    If the global option '--no-plugins' is given, plugins are not loaded
1739
 
    before running the selftests.  This has two effects: features provided or
1740
 
    modified by plugins will not be tested, and tests provided by plugins will
1741
 
    not be run.
1742
 
 
1743
 
    examples:
1744
 
        bzr selftest ignore
1745
 
        bzr --no-plugins selftest -v
1746
1135
    """
1747
1136
    # TODO: --list should give a list of all available tests
1748
 
 
1749
 
    # NB: this is used from the class without creating an instance, which is
1750
 
    # why it does not have a self parameter.
1751
 
    def get_transport_type(typestring):
1752
 
        """Parse and return a transport specifier."""
1753
 
        if typestring == "sftp":
1754
 
            from bzrlib.transport.sftp import SFTPAbsoluteServer
1755
 
            return SFTPAbsoluteServer
1756
 
        if typestring == "memory":
1757
 
            from bzrlib.transport.memory import MemoryServer
1758
 
            return MemoryServer
1759
 
        if typestring == "fakenfs":
1760
 
            from bzrlib.transport.fakenfs import FakeNFSServer
1761
 
            return FakeNFSServer
1762
 
        msg = "No known transport type %s. Supported types are: sftp\n" %\
1763
 
            (typestring)
1764
 
        raise BzrCommandError(msg)
1765
 
 
1766
1137
    hidden = True
1767
1138
    takes_args = ['testspecs*']
1768
 
    takes_options = ['verbose',
 
1139
    takes_options = ['verbose', 
1769
1140
                     Option('one', help='stop when one test fails'),
1770
 
                     Option('keep-output', 
1771
 
                            help='keep output directories when tests fail'),
1772
 
                     Option('transport', 
1773
 
                            help='Use a different transport by default '
1774
 
                                 'throughout the test suite.',
1775
 
                            type=get_transport_type),
1776
1141
                    ]
1777
1142
 
1778
 
    def run(self, testspecs_list=None, verbose=False, one=False,
1779
 
            keep_output=False, transport=None):
 
1143
    def run(self, testspecs_list=None, verbose=False, one=False):
1780
1144
        import bzrlib.ui
1781
 
        from bzrlib.tests import selftest
 
1145
        from bzrlib.selftest import selftest
1782
1146
        # we don't want progress meters from the tests to go to the
1783
1147
        # real output; and we don't want log messages cluttering up
1784
1148
        # the real logs.
1792
1156
                pattern = ".*"
1793
1157
            result = selftest(verbose=verbose, 
1794
1158
                              pattern=pattern,
1795
 
                              stop_on_failure=one, 
1796
 
                              keep_output=keep_output,
1797
 
                              transport=transport)
 
1159
                              stop_on_failure=one)
1798
1160
            if result:
1799
1161
                bzrlib.trace.info('tests passed')
1800
1162
            else:
1804
1166
            bzrlib.ui.ui_factory = save_ui
1805
1167
 
1806
1168
 
1807
 
def _get_bzr_branch():
1808
 
    """If bzr is run from a branch, return Branch or None"""
1809
 
    import bzrlib.errors
1810
 
    from bzrlib.branch import Branch
1811
 
    from bzrlib.osutils import abspath
1812
 
    from os.path import dirname
1813
 
    
1814
 
    try:
1815
 
        branch = Branch.open(dirname(abspath(dirname(__file__))))
1816
 
        return branch
1817
 
    except bzrlib.errors.BzrError:
1818
 
        return None
1819
 
    
1820
 
 
1821
1169
def show_version():
1822
1170
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
1823
1171
    # is bzrlib itself in a branch?
1824
 
    branch = _get_bzr_branch()
1825
 
    if branch:
1826
 
        rh = branch.revision_history()
1827
 
        revno = len(rh)
1828
 
        print "  bzr checkout, revision %d" % (revno,)
1829
 
        print "  nick: %s" % (branch.nick,)
1830
 
        if rh:
1831
 
            print "  revid: %s" % (rh[-1],)
 
1172
    bzrrev = bzrlib.get_bzr_revision()
 
1173
    if bzrrev:
 
1174
        print "  (bzr checkout, revision %d {%s})" % bzrrev
1832
1175
    print bzrlib.__copyright__
1833
1176
    print "http://bazaar-ng.org/"
1834
1177
    print
1839
1182
 
1840
1183
class cmd_version(Command):
1841
1184
    """Show version of bzr."""
1842
 
    @display_command
1843
1185
    def run(self):
1844
1186
        show_version()
1845
1187
 
1846
1188
class cmd_rocks(Command):
1847
1189
    """Statement of optimism."""
1848
1190
    hidden = True
1849
 
    @display_command
1850
1191
    def run(self):
1851
1192
        print "it sure does!"
1852
1193
 
1859
1200
    takes_args = ['branch', 'other']
1860
1201
    hidden = True
1861
1202
    
1862
 
    @display_command
1863
1203
    def run(self, branch, other):
1864
1204
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
1865
1205
        
1872
1212
        last1 = branch1.last_revision()
1873
1213
        last2 = branch2.last_revision()
1874
1214
 
1875
 
        source = MultipleRevisionSources(branch1.repository, 
1876
 
                                         branch2.repository)
 
1215
        source = MultipleRevisionSources(branch1, branch2)
1877
1216
        
1878
1217
        base_rev_id = common_ancestor(last1, last2, source)
1879
1218
 
1901
1240
    will be used as a BASE, and the second one as OTHER.  Revision
1902
1241
    numbers are always relative to the specified branch.
1903
1242
 
1904
 
    By default, bzr will try to merge in all new work from the other
 
1243
    By default bzr will try to merge in all new work from the other
1905
1244
    branch, automatically determining an appropriate base.  If this
1906
1245
    fails, you may need to give an explicit base.
1907
1246
    
1908
 
    Merge will do its best to combine the changes in two branches, but there
1909
 
    are some kinds of problems only a human can fix.  When it encounters those,
1910
 
    it will mark a conflict.  A conflict means that you need to fix something,
1911
 
    before you should commit.
1912
 
 
1913
 
    Use bzr resolve when you have fixed a problem.  See also bzr conflicts.
1914
 
 
1915
 
    If there is no default branch set, the first merge will set it. After
1916
 
    that, you can omit the branch to use the default.  To change the
1917
 
    default, use --remember.
1918
 
 
1919
1247
    Examples:
1920
1248
 
1921
1249
    To merge the latest revision from bzr.dev
1931
1259
    --force is given.
1932
1260
    """
1933
1261
    takes_args = ['branch?']
1934
 
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
1935
 
                     Option('show-base', help="Show base revision text in "
1936
 
                            "conflicts")]
 
1262
    takes_options = ['revision', 'force', 'merge-type']
1937
1263
 
1938
 
    def run(self, branch=None, revision=None, force=False, merge_type=None,
1939
 
            show_base=False, reprocess=False, remember=False):
 
1264
    def run(self, branch=None, revision=None, force=False, 
 
1265
            merge_type=None):
 
1266
        from bzrlib.merge import merge
 
1267
        from bzrlib.merge_core import ApplyMerge3
1940
1268
        if merge_type is None:
1941
 
            merge_type = Merge3Merger
1942
 
 
1943
 
        tree = WorkingTree.open_containing(u'.')[0]
1944
 
        stored_loc = tree.branch.get_parent()
 
1269
            merge_type = ApplyMerge3
1945
1270
        if branch is None:
1946
 
            if stored_loc is None:
1947
 
                raise BzrCommandError("No merge branch known or specified.")
 
1271
            branch = Branch.open_containing('.')[0].get_parent()
 
1272
            if branch is None:
 
1273
                raise BzrCommandError("No merge location known or specified.")
1948
1274
            else:
1949
 
                print "Using saved branch: %s" % stored_loc
1950
 
                branch = stored_loc
1951
 
 
1952
 
        if tree.branch.get_parent() is None or remember:
1953
 
            tree.branch.set_parent(branch)
1954
 
 
 
1275
                print "Using saved location: %s" % branch 
1955
1276
        if revision is None or len(revision) < 1:
1956
1277
            base = [None, None]
1957
1278
            other = [branch, -1]
1958
 
            other_branch, path = Branch.open_containing(branch)
1959
1279
        else:
1960
1280
            if len(revision) == 1:
1961
1281
                base = [None, None]
1962
 
                other_branch, path = Branch.open_containing(branch)
1963
 
                revno = revision[0].in_history(other_branch).revno
1964
 
                other = [branch, revno]
 
1282
                other = [branch, revision[0].in_history(branch).revno]
1965
1283
            else:
1966
1284
                assert len(revision) == 2
1967
1285
                if None in revision:
1968
1286
                    raise BzrCommandError(
1969
1287
                        "Merge doesn't permit that revision specifier.")
1970
 
                b, path = Branch.open_containing(branch)
 
1288
                b = Branch.open(branch)
1971
1289
 
1972
1290
                base = [branch, revision[0].in_history(b).revno]
1973
1291
                other = [branch, revision[1].in_history(b).revno]
1974
 
        if path != "":
1975
 
            interesting_files = [path]
1976
 
        else:
1977
 
            interesting_files = None
1978
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1292
 
1979
1293
        try:
1980
 
            try:
1981
 
                conflict_count = merge(other, base, check_clean=(not force),
1982
 
                                       merge_type=merge_type, 
1983
 
                                       reprocess=reprocess,
1984
 
                                       show_base=show_base, 
1985
 
                                       pb=pb, file_list=interesting_files)
1986
 
            finally:
1987
 
                pb.finished()
1988
 
            if conflict_count != 0:
1989
 
                return 1
1990
 
            else:
1991
 
                return 0
 
1294
            merge(other, base, check_clean=(not force), merge_type=merge_type)
1992
1295
        except bzrlib.errors.AmbiguousBase, e:
1993
1296
            m = ("sorry, bzr can't determine the right merge base yet\n"
1994
1297
                 "candidates are:\n  "
1999
1302
            log_error(m)
2000
1303
 
2001
1304
 
2002
 
class cmd_remerge(Command):
2003
 
    """Redo a merge.
2004
 
    """
2005
 
    takes_args = ['file*']
2006
 
    takes_options = ['merge-type', 'reprocess',
2007
 
                     Option('show-base', help="Show base revision text in "
2008
 
                            "conflicts")]
2009
 
 
2010
 
    def run(self, file_list=None, merge_type=None, show_base=False,
2011
 
            reprocess=False):
2012
 
        from bzrlib.merge import merge_inner, transform_tree
2013
 
        if merge_type is None:
2014
 
            merge_type = Merge3Merger
2015
 
        tree, file_list = tree_files(file_list)
2016
 
        tree.lock_write()
2017
 
        try:
2018
 
            pending_merges = tree.pending_merges() 
2019
 
            if len(pending_merges) != 1:
2020
 
                raise BzrCommandError("Sorry, remerge only works after normal"
2021
 
                                      + " merges.  Not cherrypicking or"
2022
 
                                      + "multi-merges.")
2023
 
            repository = tree.branch.repository
2024
 
            base_revision = common_ancestor(tree.branch.last_revision(), 
2025
 
                                            pending_merges[0], repository)
2026
 
            base_tree = repository.revision_tree(base_revision)
2027
 
            other_tree = repository.revision_tree(pending_merges[0])
2028
 
            interesting_ids = None
2029
 
            if file_list is not None:
2030
 
                interesting_ids = set()
2031
 
                for filename in file_list:
2032
 
                    file_id = tree.path2id(filename)
2033
 
                    if file_id is None:
2034
 
                        raise NotVersionedError(filename)
2035
 
                    interesting_ids.add(file_id)
2036
 
                    if tree.kind(file_id) != "directory":
2037
 
                        continue
2038
 
                    
2039
 
                    for name, ie in tree.inventory.iter_entries(file_id):
2040
 
                        interesting_ids.add(ie.file_id)
2041
 
            transform_tree(tree, tree.basis_tree(), interesting_ids)
2042
 
            if file_list is None:
2043
 
                restore_files = list(tree.iter_conflicts())
2044
 
            else:
2045
 
                restore_files = file_list
2046
 
            for filename in restore_files:
2047
 
                try:
2048
 
                    restore(tree.abspath(filename))
2049
 
                except NotConflicted:
2050
 
                    pass
2051
 
            conflicts =  merge_inner(tree.branch, other_tree, base_tree,
2052
 
                                     this_tree=tree,
2053
 
                                     interesting_ids = interesting_ids, 
2054
 
                                     other_rev_id=pending_merges[0], 
2055
 
                                     merge_type=merge_type, 
2056
 
                                     show_base=show_base,
2057
 
                                     reprocess=reprocess)
2058
 
        finally:
2059
 
            tree.unlock()
2060
 
        if conflicts > 0:
2061
 
            return 1
2062
 
        else:
2063
 
            return 0
2064
 
 
2065
1305
class cmd_revert(Command):
2066
1306
    """Reverse all changes since the last commit.
2067
1307
 
2074
1314
    aliases = ['merge-revert']
2075
1315
 
2076
1316
    def run(self, revision=None, no_backup=False, file_list=None):
 
1317
        from bzrlib.merge import merge
2077
1318
        from bzrlib.commands import parse_spec
 
1319
 
2078
1320
        if file_list is not None:
2079
1321
            if len(file_list) == 0:
2080
1322
                raise BzrCommandError("No files specified")
2081
 
        else:
2082
 
            file_list = []
2083
 
        
2084
 
        tree, file_list = tree_files(file_list)
2085
1323
        if revision is None:
2086
 
            # FIXME should be tree.last_revision
2087
 
            rev_id = tree.last_revision()
 
1324
            revno = -1
2088
1325
        elif len(revision) != 1:
2089
1326
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2090
1327
        else:
2091
 
            rev_id = revision[0].in_history(tree.branch).rev_id
2092
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
2093
 
        try:
2094
 
            tree.revert(file_list, 
2095
 
                        tree.branch.repository.revision_tree(rev_id),
2096
 
                        not no_backup, pb)
2097
 
        finally:
2098
 
            pb.finished()
 
1328
            b = Branch.open_containing('.')[0]
 
1329
            revno = revision[0].in_history(b).revno
 
1330
        merge(('.', revno), parse_spec('.'),
 
1331
              check_clean=False,
 
1332
              ignore_zero=True,
 
1333
              backup_files=not no_backup,
 
1334
              file_list=file_list)
 
1335
        if not file_list:
 
1336
            Branch.open_containing('.')[0].set_pending_merges([])
2099
1337
 
2100
1338
 
2101
1339
class cmd_assert_fail(Command):
2109
1347
    """Show help on a command or other topic.
2110
1348
 
2111
1349
    For a list of all available commands, say 'bzr help commands'."""
2112
 
    takes_options = [Option('long', 'show help on all commands')]
 
1350
    takes_options = ['long']
2113
1351
    takes_args = ['topic?']
2114
 
    aliases = ['?', '--help', '-?', '-h']
 
1352
    aliases = ['?']
2115
1353
    
2116
 
    @display_command
2117
1354
    def run(self, topic=None, long=False):
2118
1355
        import help
2119
1356
        if topic is None and long:
2129
1366
    aliases = ['s-c']
2130
1367
    hidden = True
2131
1368
    
2132
 
    @display_command
2133
1369
    def run(self, context=None):
2134
1370
        import shellcomplete
2135
1371
        shellcomplete.shellcomplete(context)
2144
1380
    def run(self, from_branch, to_branch):
2145
1381
        from bzrlib.fetch import Fetcher
2146
1382
        from bzrlib.branch import Branch
2147
 
        from_b = Branch.open(from_branch)
2148
 
        to_b = Branch.open(to_branch)
 
1383
        from_b = Branch(from_branch)
 
1384
        to_b = Branch(to_branch)
2149
1385
        Fetcher(to_b, from_b)
 
1386
        
2150
1387
 
2151
1388
 
2152
1389
class cmd_missing(Command):
2153
 
    """Show unmerged/unpulled revisions between two branches.
2154
 
 
2155
 
    OTHER_BRANCH may be local or remote."""
2156
 
    takes_args = ['other_branch?']
2157
 
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
2158
 
                     Option('mine-only', 
2159
 
                            'Display changes in the local branch only'),
2160
 
                     Option('theirs-only', 
2161
 
                            'Display changes in the remote branch only'), 
2162
 
                     'log-format',
2163
 
                     'line',
2164
 
                     'long', 
2165
 
                     'short',
2166
 
                     'show-ids',
2167
 
                     'verbose'
2168
 
                     ]
2169
 
 
2170
 
    def run(self, other_branch=None, reverse=False, mine_only=False,
2171
 
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
2172
 
            show_ids=False, verbose=False):
2173
 
        from bzrlib.missing import find_unmerged, iter_log_data
2174
 
        from bzrlib.log import log_formatter
2175
 
        local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
2176
 
        parent = local_branch.get_parent()
2177
 
        if other_branch is None:
2178
 
            other_branch = parent
2179
 
            if other_branch is None:
 
1390
    """What is missing in this branch relative to other branch.
 
1391
    """
 
1392
    # TODO: rewrite this in terms of ancestry so that it shows only
 
1393
    # unmerged things
 
1394
    
 
1395
    takes_args = ['remote?']
 
1396
    aliases = ['mis', 'miss']
 
1397
    # We don't have to add quiet to the list, because 
 
1398
    # unknown options are parsed as booleans
 
1399
    takes_options = ['verbose', 'quiet']
 
1400
 
 
1401
    def run(self, remote=None, verbose=False, quiet=False):
 
1402
        from bzrlib.errors import BzrCommandError
 
1403
        from bzrlib.missing import show_missing
 
1404
 
 
1405
        if verbose and quiet:
 
1406
            raise BzrCommandError('Cannot pass both quiet and verbose')
 
1407
 
 
1408
        b = Branch.open_containing('.')[0]
 
1409
        parent = b.get_parent()
 
1410
        if remote is None:
 
1411
            if parent is None:
2180
1412
                raise BzrCommandError("No missing location known or specified.")
2181
 
            print "Using last location: " + local_branch.get_parent()
2182
 
        remote_branch = bzrlib.branch.Branch.open(other_branch)
2183
 
        if remote_branch.base == local_branch.base:
2184
 
            remote_branch = local_branch
2185
 
        local_branch.lock_read()
2186
 
        try:
2187
 
            remote_branch.lock_read()
2188
 
            try:
2189
 
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2190
 
                if (log_format == None):
2191
 
                    default = bzrlib.config.BranchConfig(local_branch).log_format()
2192
 
                    log_format = get_log_format(long=long, short=short, line=line, default=default)
2193
 
                lf = log_formatter(log_format, sys.stdout,
2194
 
                                   show_ids=show_ids,
2195
 
                                   show_timezone='original')
2196
 
                if reverse is False:
2197
 
                    local_extra.reverse()
2198
 
                    remote_extra.reverse()
2199
 
                if local_extra and not theirs_only:
2200
 
                    print "You have %d extra revision(s):" % len(local_extra)
2201
 
                    for data in iter_log_data(local_extra, local_branch.repository,
2202
 
                                              verbose):
2203
 
                        lf.show(*data)
2204
 
                    printed_local = True
2205
 
                else:
2206
 
                    printed_local = False
2207
 
                if remote_extra and not mine_only:
2208
 
                    if printed_local is True:
2209
 
                        print "\n\n"
2210
 
                    print "You are missing %d revision(s):" % len(remote_extra)
2211
 
                    for data in iter_log_data(remote_extra, remote_branch.repository, 
2212
 
                                              verbose):
2213
 
                        lf.show(*data)
2214
 
                if not remote_extra and not local_extra:
2215
 
                    status_code = 0
2216
 
                    print "Branches are up to date."
2217
 
                else:
2218
 
                    status_code = 1
2219
 
            finally:
2220
 
                remote_branch.unlock()
2221
 
        finally:
2222
 
            local_branch.unlock()
2223
 
        if not status_code and parent is None and other_branch is not None:
2224
 
            local_branch.lock_write()
2225
 
            try:
2226
 
                # handle race conditions - a parent might be set while we run.
2227
 
                if local_branch.get_parent() is None:
2228
 
                    local_branch.set_parent(other_branch)
2229
 
            finally:
2230
 
                local_branch.unlock()
2231
 
        return status_code
 
1413
            else:
 
1414
                if not quiet:
 
1415
                    print "Using last location: %s" % parent
 
1416
                remote = parent
 
1417
        elif parent is None:
 
1418
            # We only update parent if it did not exist, missing
 
1419
            # should not change the parent
 
1420
            b.set_parent(remote)
 
1421
        br_remote = Branch.open_containing(remote)[0]
 
1422
        return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
2232
1423
 
2233
1424
 
2234
1425
class cmd_plugins(Command):
2235
1426
    """List plugins"""
2236
1427
    hidden = True
2237
 
    @display_command
2238
1428
    def run(self):
2239
1429
        import bzrlib.plugin
2240
1430
        from inspect import getdoc
2241
 
        for name, plugin in bzrlib.plugin.all_plugins().items():
 
1431
        for plugin in bzrlib.plugin.all_plugins:
2242
1432
            if hasattr(plugin, '__path__'):
2243
1433
                print plugin.__path__[0]
2244
1434
            elif hasattr(plugin, '__file__'):
2255
1445
    """Show testament (signing-form) of a revision."""
2256
1446
    takes_options = ['revision', 'long']
2257
1447
    takes_args = ['branch?']
2258
 
    @display_command
2259
 
    def run(self, branch=u'.', revision=None, long=False):
 
1448
    def run(self, branch='.', revision=None, long=False):
2260
1449
        from bzrlib.testament import Testament
2261
 
        b = WorkingTree.open_containing(branch)[0].branch
 
1450
        b = Branch.open_containing(branch)[0]
2262
1451
        b.lock_read()
2263
1452
        try:
2264
1453
            if revision is None:
2265
1454
                rev_id = b.last_revision()
2266
1455
            else:
2267
1456
                rev_id = revision[0].in_history(b).rev_id
2268
 
            t = Testament.from_revision(b.repository, rev_id)
 
1457
            t = Testament.from_revision(b, rev_id)
2269
1458
            if long:
2270
1459
                sys.stdout.writelines(t.as_text_lines())
2271
1460
            else:
2284
1473
    shown only at the top, unless the --all option is given.
2285
1474
    """
2286
1475
    # TODO: annotate directories; showing when each file was last changed
 
1476
    # TODO: annotate a previous version of a file
2287
1477
    # TODO: if the working copy is modified, show annotations on that 
2288
1478
    #       with new uncommitted lines marked
2289
1479
    aliases = ['blame', 'praise']
2290
1480
    takes_args = ['filename']
2291
1481
    takes_options = [Option('all', help='show annotations on all lines'),
2292
1482
                     Option('long', help='show date in annotations'),
2293
 
                     'revision'
2294
1483
                     ]
2295
1484
 
2296
 
    @display_command
2297
 
    def run(self, filename, all=False, long=False, revision=None):
 
1485
    def run(self, filename, all=False, long=False):
2298
1486
        from bzrlib.annotate import annotate_file
2299
 
        tree, relpath = WorkingTree.open_containing(filename)
2300
 
        branch = tree.branch
2301
 
        branch.lock_read()
 
1487
        b, relpath = Branch.open_containing(filename)
 
1488
        b.lock_read()
2302
1489
        try:
2303
 
            if revision is None:
2304
 
                revision_id = branch.last_revision()
2305
 
            elif len(revision) != 1:
2306
 
                raise BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2307
 
            else:
2308
 
                revision_id = revision[0].in_history(branch).rev_id
 
1490
            tree = WorkingTree(b.base, b)
 
1491
            tree = b.revision_tree(b.last_revision())
2309
1492
            file_id = tree.inventory.path2id(relpath)
2310
 
            tree = branch.repository.revision_tree(revision_id)
2311
1493
            file_version = tree.inventory[file_id].revision
2312
 
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
 
1494
            annotate_file(b, file_version, file_id, long, all, sys.stdout)
2313
1495
        finally:
2314
 
            branch.unlock()
 
1496
            b.unlock()
2315
1497
 
2316
1498
 
2317
1499
class cmd_re_sign(Command):
2319
1501
    # TODO be able to replace existing ones.
2320
1502
 
2321
1503
    hidden = True # is this right ?
2322
 
    takes_args = ['revision_id*']
 
1504
    takes_args = ['revision_id?']
2323
1505
    takes_options = ['revision']
2324
1506
    
2325
 
    def run(self, revision_id_list=None, revision=None):
 
1507
    def run(self, revision_id=None, revision=None):
2326
1508
        import bzrlib.config as config
2327
1509
        import bzrlib.gpg as gpg
2328
 
        if revision_id_list is not None and revision is not None:
 
1510
        if revision_id is not None and revision is not None:
2329
1511
            raise BzrCommandError('You can only supply one of revision_id or --revision')
2330
 
        if revision_id_list is None and revision is None:
 
1512
        if revision_id is None and revision is None:
2331
1513
            raise BzrCommandError('You must supply either --revision or a revision_id')
2332
 
        b = WorkingTree.open_containing(u'.')[0].branch
 
1514
        b = Branch.open_containing('.')[0]
2333
1515
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
2334
 
        if revision_id_list is not None:
2335
 
            for revision_id in revision_id_list:
2336
 
                b.repository.sign_revision(revision_id, gpg_strategy)
 
1516
        if revision_id is not None:
 
1517
            b.sign_revision(revision_id, gpg_strategy)
2337
1518
        elif revision is not None:
2338
 
            if len(revision) == 1:
2339
 
                revno, rev_id = revision[0].in_history(b)
2340
 
                b.repository.sign_revision(rev_id, gpg_strategy)
2341
 
            elif len(revision) == 2:
2342
 
                # are they both on rh- if so we can walk between them
2343
 
                # might be nice to have a range helper for arbitrary
2344
 
                # revision paths. hmm.
2345
 
                from_revno, from_revid = revision[0].in_history(b)
2346
 
                to_revno, to_revid = revision[1].in_history(b)
2347
 
                if to_revid is None:
2348
 
                    to_revno = b.revno()
2349
 
                if from_revno is None or to_revno is None:
2350
 
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
2351
 
                for revno in range(from_revno, to_revno + 1):
2352
 
                    b.repository.sign_revision(b.get_rev_id(revno), 
2353
 
                                               gpg_strategy)
2354
 
            else:
2355
 
                raise BzrCommandError('Please supply either one revision, or a range.')
2356
 
 
2357
 
 
2358
 
class cmd_bind(Command):
2359
 
    """Bind the current branch to a master branch.
2360
 
 
2361
 
    After binding, commits must succeed on the master branch
2362
 
    before they are executed on the local one.
2363
 
    """
2364
 
 
2365
 
    takes_args = ['location']
2366
 
    takes_options = []
2367
 
 
2368
 
    def run(self, location=None):
2369
 
        b, relpath = Branch.open_containing(u'.')
2370
 
        b_other = Branch.open(location)
2371
 
        try:
2372
 
            b.bind(b_other)
2373
 
        except DivergedBranches:
2374
 
            raise BzrCommandError('These branches have diverged.'
2375
 
                                  ' Try merging, and then bind again.')
2376
 
 
2377
 
 
2378
 
class cmd_unbind(Command):
2379
 
    """Unbind the current branch from its master branch.
2380
 
 
2381
 
    After unbinding, the local branch is considered independent.
2382
 
    All subsequent commits will be local.
2383
 
    """
2384
 
 
2385
 
    takes_args = []
2386
 
    takes_options = []
2387
 
 
2388
 
    def run(self):
2389
 
        b, relpath = Branch.open_containing(u'.')
2390
 
        if not b.unbind():
2391
 
            raise BzrCommandError('Local branch is not bound')
2392
 
 
2393
 
 
2394
 
class cmd_uncommit(bzrlib.commands.Command):
2395
 
    """Remove the last committed revision.
2396
 
 
2397
 
    By supplying the --all flag, it will not only remove the entry 
2398
 
    from revision_history, but also remove all of the entries in the
2399
 
    stores.
2400
 
 
2401
 
    --verbose will print out what is being removed.
2402
 
    --dry-run will go through all the motions, but not actually
2403
 
    remove anything.
2404
 
    
2405
 
    In the future, uncommit will create a changeset, which can then
2406
 
    be re-applied.
2407
 
    """
2408
 
 
2409
 
    # TODO: jam 20060108 Add an option to allow uncommit to remove
2410
 
    # unreferenced information in 'branch-as-repostory' branches.
2411
 
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2412
 
    # information in shared branches as well.
2413
 
    takes_options = ['verbose', 'revision',
2414
 
                    Option('dry-run', help='Don\'t actually make changes'),
2415
 
                    Option('force', help='Say yes to all questions.')]
2416
 
    takes_args = ['location?']
2417
 
    aliases = []
2418
 
 
2419
 
    def run(self, location=None, 
2420
 
            dry_run=False, verbose=False,
2421
 
            revision=None, force=False):
2422
 
        from bzrlib.branch import Branch
2423
 
        from bzrlib.log import log_formatter
2424
 
        import sys
2425
 
        from bzrlib.uncommit import uncommit
2426
 
 
2427
 
        if location is None:
2428
 
            location = u'.'
2429
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
2430
 
        try:
2431
 
            tree = control.open_workingtree()
2432
 
            b = tree.branch
2433
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
2434
 
            tree = None
2435
 
            b = control.open_branch()
2436
 
 
2437
 
        if revision is None:
2438
 
            revno = b.revno()
2439
 
            rev_id = b.last_revision()
2440
 
        else:
2441
 
            revno, rev_id = revision[0].in_history(b)
2442
 
        if rev_id is None:
2443
 
            print 'No revisions to uncommit.'
2444
 
 
2445
 
        for r in range(revno, b.revno()+1):
2446
 
            rev_id = b.get_rev_id(r)
2447
 
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2448
 
            lf.show(r, b.repository.get_revision(rev_id), None)
2449
 
 
2450
 
        if dry_run:
2451
 
            print 'Dry-run, pretending to remove the above revisions.'
2452
 
            if not force:
2453
 
                val = raw_input('Press <enter> to continue')
2454
 
        else:
2455
 
            print 'The above revision(s) will be removed.'
2456
 
            if not force:
2457
 
                val = raw_input('Are you sure [y/N]? ')
2458
 
                if val.lower() not in ('y', 'yes'):
2459
 
                    print 'Canceled'
2460
 
                    return 0
2461
 
 
2462
 
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2463
 
                revno=revno)
2464
 
 
2465
 
 
2466
 
class cmd_break_lock(Command):
2467
 
    """Break a dead lock on a repository, branch or working directory.
2468
 
 
2469
 
    CAUTION: Locks should only be broken when you are sure that the process
2470
 
    holding the lock has been stopped.
2471
 
 
2472
 
    You can get information on what locks are open via the 'bzr info' command.
2473
 
    
2474
 
    example:
2475
 
        bzr break-lock
2476
 
    """
2477
 
    takes_args = ['location?']
2478
 
 
2479
 
    def run(self, location=None, show=False):
2480
 
        if location is None:
2481
 
            location = u'.'
2482
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
2483
 
        try:
2484
 
            control.break_lock()
2485
 
        except NotImplementedError:
2486
 
            pass
2487
 
        
2488
 
 
2489
 
 
2490
 
# command-line interpretation helper for merge-related commands
2491
 
def merge(other_revision, base_revision,
2492
 
          check_clean=True, ignore_zero=False,
2493
 
          this_dir=None, backup_files=False, merge_type=Merge3Merger,
2494
 
          file_list=None, show_base=False, reprocess=False,
2495
 
          pb=DummyProgress()):
2496
 
    """Merge changes into a tree.
2497
 
 
2498
 
    base_revision
2499
 
        list(path, revno) Base for three-way merge.  
2500
 
        If [None, None] then a base will be automatically determined.
2501
 
    other_revision
2502
 
        list(path, revno) Other revision for three-way merge.
2503
 
    this_dir
2504
 
        Directory to merge changes into; '.' by default.
2505
 
    check_clean
2506
 
        If true, this_dir must have no uncommitted changes before the
2507
 
        merge begins.
2508
 
    ignore_zero - If true, suppress the "zero conflicts" message when 
2509
 
        there are no conflicts; should be set when doing something we expect
2510
 
        to complete perfectly.
2511
 
    file_list - If supplied, merge only changes to selected files.
2512
 
 
2513
 
    All available ancestors of other_revision and base_revision are
2514
 
    automatically pulled into the branch.
2515
 
 
2516
 
    The revno may be -1 to indicate the last revision on the branch, which is
2517
 
    the typical case.
2518
 
 
2519
 
    This function is intended for use from the command line; programmatic
2520
 
    clients might prefer to call merge.merge_inner(), which has less magic 
2521
 
    behavior.
2522
 
    """
2523
 
    from bzrlib.merge import Merger
2524
 
    if this_dir is None:
2525
 
        this_dir = u'.'
2526
 
    this_tree = WorkingTree.open_containing(this_dir)[0]
2527
 
    if show_base and not merge_type is Merge3Merger:
2528
 
        raise BzrCommandError("Show-base is not supported for this merge"
2529
 
                              " type. %s" % merge_type)
2530
 
    if reprocess and not merge_type.supports_reprocess:
2531
 
        raise BzrCommandError("Conflict reduction is not supported for merge"
2532
 
                              " type %s." % merge_type)
2533
 
    if reprocess and show_base:
2534
 
        raise BzrCommandError("Cannot do conflict reduction and show base.")
2535
 
    try:
2536
 
        merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
2537
 
        merger.pp = ProgressPhase("Merge phase", 5, pb)
2538
 
        merger.pp.next_phase()
2539
 
        merger.check_basis(check_clean)
2540
 
        merger.set_other(other_revision)
2541
 
        merger.pp.next_phase()
2542
 
        merger.set_base(base_revision)
2543
 
        if merger.base_rev_id == merger.other_rev_id:
2544
 
            note('Nothing to do.')
2545
 
            return 0
2546
 
        merger.backup_files = backup_files
2547
 
        merger.merge_type = merge_type 
2548
 
        merger.set_interesting_files(file_list)
2549
 
        merger.show_base = show_base 
2550
 
        merger.reprocess = reprocess
2551
 
        conflicts = merger.do_merge()
2552
 
        if file_list is None:
2553
 
            merger.set_pending()
2554
 
    finally:
2555
 
        pb.clear()
2556
 
    return conflicts
 
1519
            for rev in revision:
 
1520
                if rev is None:
 
1521
                    raise BzrCommandError('You cannot specify a NULL revision.')
 
1522
                revno, rev_id = rev.in_history(b)
 
1523
                b.sign_revision(rev_id, gpg_strategy)
2557
1524
 
2558
1525
 
2559
1526
# these get imported and then picked up by the scan for cmd_*
2560
1527
# TODO: Some more consistent way to split command definitions across files;
2561
1528
# we do need to load at least some information about them to know of 
2562
 
# aliases.  ideally we would avoid loading the implementation until the
2563
 
# details were needed.
2564
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
2565
 
from bzrlib.sign_my_commits import cmd_sign_my_commits
2566
 
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
2567
 
        cmd_weave_plan_merge, cmd_weave_merge_text
 
1529
# aliases.
 
1530
from bzrlib.conflicts import cmd_resolve, cmd_conflicts