~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2006-06-26 16:23:10 UTC
  • mfrom: (1780.2.1 misc-fixen)
  • mto: This revision was merged to the branch mainline in revision 1815.
  • Revision ID: robertc@robertcollins.net-20060626162310-98f5b55b8cc19d46
(robertc) Misc minor typos and the like.

Show diffs side-by-side

added added

removed removed

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