~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Martin Pool
  • Date: 2005-09-19 07:43:53 UTC
  • Revision ID: mbp@sourcefrog.net-20050919074353-534837a6b802ce32
- compute order to import revisions

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