/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: John Arbash Meinel
  • Date: 2006-09-13 02:09:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2004.
  • Revision ID: john@arbash-meinel.com-20060913020937-2df2f49f9a28ec43
Update HACKING and docstrings

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006, 2007 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
16
16
 
17
17
"""builtin bzr commands"""
18
18
 
19
 
import os
20
 
from StringIO import StringIO
21
19
 
22
 
from bzrlib.lazy_import import lazy_import
23
 
lazy_import(globals(), """
24
20
import codecs
25
21
import errno
26
 
import smtplib
 
22
import os
 
23
import os.path
27
24
import sys
28
 
import tempfile
29
 
import time
30
25
 
31
26
import bzrlib
32
27
from bzrlib import (
33
28
    branch,
34
29
    bundle,
35
30
    bzrdir,
36
 
    delta,
37
31
    config,
38
32
    errors,
39
 
    globbing,
40
33
    ignores,
41
34
    log,
42
 
    merge as _mod_merge,
43
 
    merge_directive,
44
35
    osutils,
45
 
    registry,
46
36
    repository,
47
 
    symbol_versioning,
48
37
    transport,
49
 
    tree as _mod_tree,
50
38
    ui,
51
39
    urlutils,
52
40
    )
53
 
from bzrlib.branch import Branch
 
41
from bzrlib.branch import Branch, BranchReferenceFormat
 
42
from bzrlib.bundle import read_bundle_from_url
54
43
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
55
44
from bzrlib.conflicts import ConflictList
 
45
from bzrlib.commands import Command, display_command
 
46
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
 
47
                           NotBranchError, DivergedBranches, NotConflicted,
 
48
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
 
49
                           NotVersionedError, NotABundle)
 
50
from bzrlib.merge import Merge3Merger
 
51
from bzrlib.option import Option
 
52
from bzrlib.progress import DummyProgress, ProgressPhase
56
53
from bzrlib.revision import common_ancestor
57
54
from bzrlib.revisionspec import RevisionSpec
 
55
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
 
56
from bzrlib.transport.local import LocalTransport
58
57
from bzrlib.workingtree import WorkingTree
59
 
""")
60
 
 
61
 
from bzrlib.commands import Command, display_command
62
 
from bzrlib.option import Option, RegistryOption
63
 
from bzrlib.progress import DummyProgress, ProgressPhase
64
 
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
65
58
 
66
59
 
67
60
def tree_files(file_list, default_branch=u'.'):
68
61
    try:
69
62
        return internal_tree_files(file_list, default_branch)
70
 
    except errors.FileInWrongBranch, e:
71
 
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
72
 
                                     (e.path, file_list[0]))
 
63
    except FileInWrongBranch, e:
 
64
        raise BzrCommandError("%s is not in the same branch as %s" %
 
65
                             (e.path, file_list[0]))
73
66
 
74
67
 
75
68
# XXX: Bad function name; should possibly also be a class method of
84
77
 
85
78
    :param file_list: Filenames to convert.  
86
79
 
87
 
    :param default_branch: Fallback tree path to use if file_list is empty or
88
 
        None.
 
80
    :param default_branch: Fallback tree path to use if file_list is empty or None.
89
81
 
90
82
    :return: workingtree, [relative_paths]
91
83
    """
92
84
    if file_list is None or len(file_list) == 0:
93
85
        return WorkingTree.open_containing(default_branch)[0], file_list
94
 
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
 
86
    tree = WorkingTree.open_containing(file_list[0])[0]
95
87
    new_list = []
96
88
    for filename in file_list:
97
89
        try:
98
 
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
 
90
            new_list.append(tree.relpath(filename))
99
91
        except errors.PathNotChild:
100
 
            raise errors.FileInWrongBranch(tree.branch, filename)
 
92
            raise FileInWrongBranch(tree.branch, filename)
101
93
    return tree, new_list
102
94
 
103
95
 
104
 
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
105
96
def get_format_type(typestring):
106
97
    """Parse and return a format specifier."""
107
 
    # Have to use BzrDirMetaFormat1 directly, so that
108
 
    # RepositoryFormat.set_default_format works
 
98
    if typestring == "weave":
 
99
        return bzrdir.BzrDirFormat6()
109
100
    if typestring == "default":
110
101
        return bzrdir.BzrDirMetaFormat1()
111
 
    try:
112
 
        return bzrdir.format_registry.make_bzrdir(typestring)
113
 
    except KeyError:
114
 
        msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
115
 
        raise errors.BzrCommandError(msg)
 
102
    if typestring == "metaweave":
 
103
        format = bzrdir.BzrDirMetaFormat1()
 
104
        format.repository_format = repository.RepositoryFormat7()
 
105
        return format
 
106
    if typestring == "knit":
 
107
        format = bzrdir.BzrDirMetaFormat1()
 
108
        format.repository_format = repository.RepositoryFormatKnit1()
 
109
        return format
 
110
    if typestring == "experimental-knit2":
 
111
        format = bzrdir.BzrDirMetaFormat1()
 
112
        format.repository_format = repository.RepositoryFormatKnit2()
 
113
        return format
 
114
    msg = "Unknown bzr format %s. Current formats are: default, knit,\n" \
 
115
          "metaweave and weave" % typestring
 
116
    raise BzrCommandError(msg)
116
117
 
117
118
 
118
119
# TODO: Make sure no commands unconditionally use the working directory as a
142
143
    modified
143
144
        Text has changed since the previous revision.
144
145
 
145
 
    kind changed
146
 
        File kind has been changed (e.g. from file to directory).
147
 
 
148
146
    unknown
149
147
        Not versioned and not matching an ignore pattern.
150
148
 
151
 
    To see ignored files use 'bzr ignored'.  For details on the
 
149
    To see ignored files use 'bzr ignored'.  For details in the
152
150
    changes to file texts, use 'bzr diff'.
153
 
    
154
 
    --short gives a status flags for each item, similar to the SVN's status
155
 
    command.
156
 
 
157
 
    Column 1: versioning / renames
158
 
      + File versioned
159
 
      - File unversioned
160
 
      R File renamed
161
 
      ? File unknown
162
 
      C File has conflicts
163
 
      P Entry for a pending merge (not a file)
164
 
 
165
 
    Column 2: Contents
166
 
      N File created
167
 
      D File deleted
168
 
      K File kind changed
169
 
      M File modified
170
 
 
171
 
    Column 3: Execute
172
 
      * The execute bit was changed
173
151
 
174
152
    If no arguments are specified, the status of the entire working
175
153
    directory is shown.  Otherwise, only the status of the specified
183
161
    # TODO: --no-recurse, --recurse options
184
162
    
185
163
    takes_args = ['file*']
186
 
    takes_options = ['show-ids', 'revision',
187
 
                     Option('short', help='Give short SVN-style status lines'),
188
 
                     Option('versioned', help='Only show versioned files')]
 
164
    takes_options = ['show-ids', 'revision']
189
165
    aliases = ['st', 'stat']
190
166
 
191
167
    encoding_type = 'replace'
192
168
    
193
169
    @display_command
194
 
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
195
 
            versioned=False):
 
170
    def run(self, show_ids=False, file_list=None, revision=None):
196
171
        from bzrlib.status import show_tree_status
197
172
 
198
173
        tree, file_list = tree_files(file_list)
199
174
            
200
175
        show_tree_status(tree, show_ids=show_ids,
201
176
                         specific_files=file_list, revision=revision,
202
 
                         to_file=self.outf, short=short, versioned=versioned)
 
177
                         to_file=self.outf)
203
178
 
204
179
 
205
180
class cmd_cat_revision(Command):
218
193
    @display_command
219
194
    def run(self, revision_id=None, revision=None):
220
195
 
221
 
        revision_id = osutils.safe_revision_id(revision_id, warn=False)
222
196
        if revision_id is not None and revision is not None:
223
 
            raise errors.BzrCommandError('You can only supply one of'
224
 
                                         ' revision_id or --revision')
 
197
            raise BzrCommandError('You can only supply one of revision_id or --revision')
225
198
        if revision_id is None and revision is None:
226
 
            raise errors.BzrCommandError('You must supply either'
227
 
                                         ' --revision or a revision_id')
 
199
            raise BzrCommandError('You must supply either --revision or a revision_id')
228
200
        b = WorkingTree.open_containing(u'.')[0].branch
229
201
 
230
202
        # TODO: jam 20060112 should cat-revision always output utf-8?
233
205
        elif revision is not None:
234
206
            for rev in revision:
235
207
                if rev is None:
236
 
                    raise errors.BzrCommandError('You cannot specify a NULL'
237
 
                                                 ' revision.')
 
208
                    raise BzrCommandError('You cannot specify a NULL revision.')
238
209
                revno, rev_id = rev.in_history(b)
239
210
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
240
211
    
241
212
 
242
 
class cmd_remove_tree(Command):
243
 
    """Remove the working tree from a given branch/checkout.
244
 
 
245
 
    Since a lightweight checkout is little more than a working tree
246
 
    this will refuse to run against one.
247
 
 
248
 
    To re-create the working tree, use "bzr checkout".
249
 
    """
250
 
 
251
 
    takes_args = ['location?']
252
 
 
253
 
    def run(self, location='.'):
254
 
        d = bzrdir.BzrDir.open(location)
255
 
        
256
 
        try:
257
 
            working = d.open_workingtree()
258
 
        except errors.NoWorkingTree:
259
 
            raise errors.BzrCommandError("No working tree to remove")
260
 
        except errors.NotLocalUrl:
261
 
            raise errors.BzrCommandError("You cannot remove the working tree of a "
262
 
                                         "remote path")
263
 
        
264
 
        working_path = working.bzrdir.root_transport.base
265
 
        branch_path = working.branch.bzrdir.root_transport.base
266
 
        if working_path != branch_path:
267
 
            raise errors.BzrCommandError("You cannot remove the working tree from "
268
 
                                         "a lightweight checkout")
269
 
        
270
 
        d.destroy_workingtree()
271
 
        
272
 
 
273
213
class cmd_revno(Command):
274
214
    """Show current revision number.
275
215
 
301
241
            for rev in revision_info_list:
302
242
                revs.append(RevisionSpec.from_string(rev))
303
243
        if len(revs) == 0:
304
 
            raise errors.BzrCommandError('You must supply a revision identifier')
 
244
            raise BzrCommandError('You must supply a revision identifier')
305
245
 
306
246
        b = WorkingTree.open_containing(u'.')[0].branch
307
247
 
341
281
 
342
282
    --file-ids-from will try to use the file ids from the supplied path.
343
283
    It looks up ids trying to find a matching parent directory with the
344
 
    same filename, and then by pure path. This option is rarely needed
345
 
    but can be useful when adding the same logical file into two
346
 
    branches that will be merged later (without showing the two different
347
 
    adds as a conflict). It is also useful when merging another project
348
 
    into a subdirectory of this one.
 
284
    same filename, and then by pure path.
349
285
    """
350
286
    takes_args = ['file*']
351
287
    takes_options = ['no-recurse', 'dry-run', 'verbose',
357
293
            file_ids_from=None):
358
294
        import bzrlib.add
359
295
 
360
 
        base_tree = None
361
296
        if file_ids_from is not None:
362
297
            try:
363
298
                base_tree, base_path = WorkingTree.open_containing(
364
299
                                            file_ids_from)
365
300
            except errors.NoWorkingTree:
366
 
                base_branch, base_path = Branch.open_containing(
 
301
                base_branch, base_path = branch.Branch.open_containing(
367
302
                                            file_ids_from)
368
303
                base_tree = base_branch.basis_tree()
369
304
 
373
308
            action = bzrlib.add.AddAction(to_file=self.outf,
374
309
                should_print=(not is_quiet()))
375
310
 
376
 
        if base_tree:
377
 
            base_tree.lock_read()
378
 
        try:
379
 
            added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
380
 
                action=action, save=not dry_run)
381
 
        finally:
382
 
            if base_tree is not None:
383
 
                base_tree.unlock()
 
311
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
 
312
                                              action=action, save=not dry_run)
384
313
        if len(ignored) > 0:
385
314
            if verbose:
386
315
                for glob in sorted(ignored.keys()):
432
361
    """Show inventory of the current working copy or a revision.
433
362
 
434
363
    It is possible to limit the output to a particular entry
435
 
    type using the --kind option.  For example: --kind file.
436
 
 
437
 
    It is also possible to restrict the list of files to a specific
438
 
    set. For example: bzr inventory --show-ids this/file
439
 
 
440
 
    See also: bzr ls
 
364
    type using the --kind option.  For example; --kind file.
441
365
    """
442
366
 
443
 
    hidden = True
444
 
 
445
367
    takes_options = ['revision', 'show-ids', 'kind']
446
 
 
447
 
    takes_args = ['file*']
448
 
 
 
368
    
449
369
    @display_command
450
 
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
 
370
    def run(self, revision=None, show_ids=False, kind=None):
451
371
        if kind and kind not in ['file', 'directory', 'symlink']:
452
 
            raise errors.BzrCommandError('invalid kind specified')
453
 
 
454
 
        work_tree, file_list = tree_files(file_list)
455
 
        work_tree.lock_read()
456
 
        try:
457
 
            if revision is not None:
458
 
                if len(revision) > 1:
459
 
                    raise errors.BzrCommandError(
460
 
                        'bzr inventory --revision takes exactly one revision'
461
 
                        ' identifier')
462
 
                revision_id = revision[0].in_history(work_tree.branch).rev_id
463
 
                tree = work_tree.branch.repository.revision_tree(revision_id)
464
 
 
465
 
                extra_trees = [work_tree]
466
 
                tree.lock_read()
467
 
            else:
468
 
                tree = work_tree
469
 
                extra_trees = []
470
 
 
471
 
            if file_list is not None:
472
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
473
 
                                          require_versioned=True)
474
 
                # find_ids_across_trees may include some paths that don't
475
 
                # exist in 'tree'.
476
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
477
 
                                 for file_id in file_ids if file_id in tree)
478
 
            else:
479
 
                entries = tree.inventory.entries()
480
 
        finally:
481
 
            tree.unlock()
482
 
            if tree is not work_tree:
483
 
                work_tree.unlock()
484
 
 
485
 
        for path, entry in entries:
 
372
            raise BzrCommandError('invalid kind specified')
 
373
        tree = WorkingTree.open_containing(u'.')[0]
 
374
        if revision is None:
 
375
            inv = tree.read_working_inventory()
 
376
        else:
 
377
            if len(revision) > 1:
 
378
                raise BzrCommandError('bzr inventory --revision takes'
 
379
                    ' exactly one revision identifier')
 
380
            inv = tree.branch.repository.get_revision_inventory(
 
381
                revision[0].in_history(tree.branch).rev_id)
 
382
 
 
383
        for path, entry in inv.entries():
486
384
            if kind and kind != entry.kind:
487
385
                continue
488
386
            if show_ids:
501
399
 
502
400
    If the last argument is a versioned directory, all the other names
503
401
    are moved into it.  Otherwise, there must be exactly two arguments
504
 
    and the file is changed to a new name.
505
 
 
506
 
    If OLDNAME does not exist on the filesystem but is versioned and
507
 
    NEWNAME does exist on the filesystem but is not versioned, mv
508
 
    assumes that the file has been manually moved and only updates
509
 
    its internal inventory to reflect that change.
510
 
    The same is valid when moving many SOURCE files to a DESTINATION.
 
402
    and the file is changed to a new name, which must not already exist.
511
403
 
512
404
    Files cannot be moved between branches.
513
405
    """
514
406
 
515
407
    takes_args = ['names*']
516
 
    takes_options = [Option("after", help="move only the bzr identifier"
517
 
        " of the file (file has already been moved). Use this flag if"
518
 
        " bzr is not able to detect this itself.")]
519
408
    aliases = ['move', 'rename']
520
409
    encoding_type = 'replace'
521
410
 
522
 
    def run(self, names_list, after=False):
 
411
    def run(self, names_list):
523
412
        if names_list is None:
524
413
            names_list = []
525
414
 
526
415
        if len(names_list) < 2:
527
 
            raise errors.BzrCommandError("missing file argument")
 
416
            raise BzrCommandError("missing file argument")
528
417
        tree, rel_names = tree_files(names_list)
529
418
        
530
419
        if os.path.isdir(names_list[-1]):
531
420
            # move into existing directory
532
 
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
421
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
533
422
                self.outf.write("%s => %s\n" % pair)
534
423
        else:
535
424
            if len(names_list) != 2:
536
 
                raise errors.BzrCommandError('to mv multiple files the'
537
 
                                             ' destination must be a versioned'
538
 
                                             ' directory')
539
 
            tree.rename_one(rel_names[0], rel_names[1], after=after)
 
425
                raise BzrCommandError('to mv multiple files the destination '
 
426
                                      'must be a versioned directory')
 
427
            tree.rename_one(rel_names[0], rel_names[1])
540
428
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
541
429
            
542
430
    
560
448
    location can be accessed.
561
449
    """
562
450
 
563
 
    takes_options = ['remember', 'overwrite', 'revision', 'verbose',
564
 
        Option('directory',
565
 
            help='branch to pull into, '
566
 
                 'rather than the one containing the working directory',
567
 
            short_name='d',
568
 
            type=unicode,
569
 
            ),
570
 
        ]
 
451
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
571
452
    takes_args = ['location?']
572
453
    encoding_type = 'replace'
573
454
 
574
 
    def run(self, location=None, remember=False, overwrite=False,
575
 
            revision=None, verbose=False,
576
 
            directory=None):
577
 
        from bzrlib.tag import _merge_tags_if_possible
 
455
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
578
456
        # FIXME: too much stuff is in the command class
579
 
        revision_id = None
580
 
        mergeable = None
581
 
        if directory is None:
582
 
            directory = u'.'
583
457
        try:
584
 
            tree_to = WorkingTree.open_containing(directory)[0]
 
458
            tree_to = WorkingTree.open_containing(u'.')[0]
585
459
            branch_to = tree_to.branch
586
 
        except errors.NoWorkingTree:
 
460
        except NoWorkingTree:
587
461
            tree_to = None
588
 
            branch_to = Branch.open_containing(directory)[0]
 
462
            branch_to = Branch.open_containing(u'.')[0]
589
463
 
590
464
        reader = None
591
465
        if location is not None:
592
466
            try:
593
 
                mergeable = bundle.read_mergeable_from_url(
594
 
                    location)
595
 
            except errors.NotABundle:
 
467
                reader = bundle.read_bundle_from_url(location)
 
468
            except NotABundle:
596
469
                pass # Continue on considering this url a Branch
597
470
 
598
471
        stored_loc = branch_to.get_parent()
599
472
        if location is None:
600
473
            if stored_loc is None:
601
 
                raise errors.BzrCommandError("No pull location known or"
602
 
                                             " specified.")
 
474
                raise BzrCommandError("No pull location known or specified.")
603
475
            else:
604
476
                display_url = urlutils.unescape_for_display(stored_loc,
605
477
                        self.outf.encoding)
606
478
                self.outf.write("Using saved location: %s\n" % display_url)
607
479
                location = stored_loc
608
480
 
609
 
        if mergeable is not None:
610
 
            if revision is not None:
611
 
                raise errors.BzrCommandError(
612
 
                    'Cannot use -r with merge directives or bundles')
613
 
            revision_id = mergeable.install_revisions(branch_to.repository)
 
481
 
 
482
        if reader is not None:
 
483
            install_bundle(branch_to.repository, reader)
614
484
            branch_from = branch_to
615
485
        else:
616
486
            branch_from = Branch.open(location)
618
488
            if branch_to.get_parent() is None or remember:
619
489
                branch_to.set_parent(branch_from.base)
620
490
 
621
 
        if revision is not None:
622
 
            if len(revision) == 1:
623
 
                revision_id = revision[0].in_history(branch_from).rev_id
624
 
            else:
625
 
                raise errors.BzrCommandError(
626
 
                    'bzr pull --revision takes one value.')
 
491
        rev_id = None
 
492
        if revision is None:
 
493
            if reader is not None:
 
494
                rev_id = reader.target
 
495
        elif len(revision) == 1:
 
496
            rev_id = revision[0].in_history(branch_from).rev_id
 
497
        else:
 
498
            raise BzrCommandError('bzr pull --revision takes one value.')
627
499
 
628
500
        old_rh = branch_to.revision_history()
629
501
        if tree_to is not None:
630
 
            result = tree_to.pull(branch_from, overwrite, revision_id,
631
 
                delta._ChangeReporter(unversioned_filter=tree_to.is_ignored))
 
502
            count = tree_to.pull(branch_from, overwrite, rev_id)
632
503
        else:
633
 
            result = branch_to.pull(branch_from, overwrite, revision_id)
 
504
            count = branch_to.pull(branch_from, overwrite, rev_id)
 
505
        note('%d revision(s) pulled.' % (count,))
634
506
 
635
 
        result.report(self.outf)
636
507
        if verbose:
637
 
            from bzrlib.log import show_changed_revisions
638
508
            new_rh = branch_to.revision_history()
639
 
            show_changed_revisions(branch_to, old_rh, new_rh,
640
 
                                   to_file=self.outf)
 
509
            if old_rh != new_rh:
 
510
                # Something changed
 
511
                from bzrlib.log import show_changed_revisions
 
512
                show_changed_revisions(branch_to, old_rh, new_rh,
 
513
                                       to_file=self.outf)
641
514
 
642
515
 
643
516
class cmd_push(Command):
667
540
    """
668
541
 
669
542
    takes_options = ['remember', 'overwrite', 'verbose',
670
 
        Option('create-prefix',
671
 
               help='Create the path leading up to the branch '
672
 
                    'if it does not already exist'),
673
 
        Option('directory',
674
 
            help='branch to push from, '
675
 
                 'rather than the one containing the working directory',
676
 
            short_name='d',
677
 
            type=unicode,
678
 
            ),
679
 
        Option('use-existing-dir',
680
 
               help='By default push will fail if the target'
681
 
                    ' directory exists, but does not already'
682
 
                    ' have a control directory. This flag will'
683
 
                    ' allow push to proceed.'),
684
 
        ]
 
543
                     Option('create-prefix', 
 
544
                            help='Create the path leading up to the branch '
 
545
                                 'if it does not already exist')]
685
546
    takes_args = ['location?']
686
547
    encoding_type = 'replace'
687
548
 
688
549
    def run(self, location=None, remember=False, overwrite=False,
689
 
            create_prefix=False, verbose=False,
690
 
            use_existing_dir=False,
691
 
            directory=None):
 
550
            create_prefix=False, verbose=False):
692
551
        # FIXME: Way too big!  Put this into a function called from the
693
552
        # command.
694
 
        if directory is None:
695
 
            directory = '.'
696
 
        br_from = Branch.open_containing(directory)[0]
 
553
        
 
554
        br_from = Branch.open_containing('.')[0]
697
555
        stored_loc = br_from.get_push_location()
698
556
        if location is None:
699
557
            if stored_loc is None:
700
 
                raise errors.BzrCommandError("No push location known or specified.")
 
558
                raise BzrCommandError("No push location known or specified.")
701
559
            else:
702
560
                display_url = urlutils.unescape_for_display(stored_loc,
703
561
                        self.outf.encoding)
707
565
        to_transport = transport.get_transport(location)
708
566
        location_url = to_transport.base
709
567
 
710
 
        br_to = repository_to = dir_to = None
711
 
        try:
712
 
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
713
 
        except errors.NotBranchError:
714
 
            pass # Didn't find anything
715
 
        else:
716
 
            # If we can open a branch, use its direct repository, otherwise see
717
 
            # if there is a repository without a branch.
718
 
            try:
719
 
                br_to = dir_to.open_branch()
720
 
            except errors.NotBranchError:
721
 
                # Didn't find a branch, can we find a repository?
722
 
                try:
723
 
                    repository_to = dir_to.find_repository()
724
 
                except errors.NoRepositoryPresent:
725
 
                    pass
726
 
            else:
727
 
                # Found a branch, so we must have found a repository
728
 
                repository_to = br_to.repository
729
 
        push_result = None
730
568
        old_rh = []
731
 
        if dir_to is None:
732
 
            # The destination doesn't exist; create it.
733
 
            # XXX: Refactor the create_prefix/no_create_prefix code into a
734
 
            #      common helper function
735
 
            try:
736
 
                to_transport.mkdir('.')
737
 
            except errors.FileExists:
738
 
                if not use_existing_dir:
739
 
                    raise errors.BzrCommandError("Target directory %s"
740
 
                         " already exists, but does not have a valid .bzr"
741
 
                         " directory. Supply --use-existing-dir to push"
742
 
                         " there anyway." % location)
743
 
            except errors.NoSuchFile:
744
 
                if not create_prefix:
745
 
                    raise errors.BzrCommandError("Parent directory of %s"
746
 
                        " does not exist."
747
 
                        "\nYou may supply --create-prefix to create all"
748
 
                        " leading parent directories."
749
 
                        % location)
750
 
 
751
 
                cur_transport = to_transport
752
 
                needed = [cur_transport]
753
 
                # Recurse upwards until we can create a directory successfully
754
 
                while True:
755
 
                    new_transport = cur_transport.clone('..')
756
 
                    if new_transport.base == cur_transport.base:
757
 
                        raise errors.BzrCommandError("Failed to create path"
758
 
                                                     " prefix for %s."
759
 
                                                     % location)
760
 
                    try:
761
 
                        new_transport.mkdir('.')
762
 
                    except errors.NoSuchFile:
763
 
                        needed.append(new_transport)
764
 
                        cur_transport = new_transport
765
 
                    else:
766
 
                        break
767
 
 
768
 
                # Now we only need to create child directories
 
569
        try:
 
570
            dir_to = bzrdir.BzrDir.open(location_url)
 
571
            br_to = dir_to.open_branch()
 
572
        except NotBranchError:
 
573
            # create a branch.
 
574
            to_transport = to_transport.clone('..')
 
575
            if not create_prefix:
 
576
                try:
 
577
                    relurl = to_transport.relpath(location_url)
 
578
                    mutter('creating directory %s => %s', location_url, relurl)
 
579
                    to_transport.mkdir(relurl)
 
580
                except NoSuchFile:
 
581
                    raise BzrCommandError("Parent directory of %s "
 
582
                                          "does not exist." % location)
 
583
            else:
 
584
                current = to_transport.base
 
585
                needed = [(to_transport, to_transport.relpath(location_url))]
769
586
                while needed:
770
 
                    cur_transport = needed.pop()
771
 
                    cur_transport.mkdir('.')
772
 
            
773
 
            # Now the target directory exists, but doesn't have a .bzr
774
 
            # directory. So we need to create it, along with any work to create
775
 
            # all of the dependent branches, etc.
 
587
                    try:
 
588
                        to_transport, relpath = needed[-1]
 
589
                        to_transport.mkdir(relpath)
 
590
                        needed.pop()
 
591
                    except NoSuchFile:
 
592
                        new_transport = to_transport.clone('..')
 
593
                        needed.append((new_transport,
 
594
                                       new_transport.relpath(to_transport.base)))
 
595
                        if new_transport.base == to_transport.base:
 
596
                            raise BzrCommandError("Could not create "
 
597
                                                  "path prefix.")
776
598
            dir_to = br_from.bzrdir.clone(location_url,
777
599
                revision_id=br_from.last_revision())
778
600
            br_to = dir_to.open_branch()
779
 
            # TODO: Some more useful message about what was copied
780
 
            note('Created new branch.')
 
601
            count = len(br_to.revision_history())
781
602
            # We successfully created the target, remember it
782
603
            if br_from.get_push_location() is None or remember:
783
604
                br_from.set_push_location(br_to.base)
784
 
        elif repository_to is None:
785
 
            # we have a bzrdir but no branch or repository
786
 
            # XXX: Figure out what to do other than complain.
787
 
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
788
 
                " directory, but not a branch or repository. This is an"
789
 
                " unsupported configuration. Please move the target directory"
790
 
                " out of the way and try again."
791
 
                % location)
792
 
        elif br_to is None:
793
 
            # We have a repository but no branch, copy the revisions, and then
794
 
            # create a branch.
795
 
            last_revision_id = br_from.last_revision()
796
 
            repository_to.fetch(br_from.repository,
797
 
                                revision_id=last_revision_id)
798
 
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
799
 
            note('Created new branch.')
800
 
            if br_from.get_push_location() is None or remember:
801
 
                br_from.set_push_location(br_to.base)
802
 
        else: # We have a valid to branch
 
605
        else:
803
606
            # We were able to connect to the remote location, so remember it
804
607
            # we don't need to successfully push because of possible divergence.
805
608
            if br_from.get_push_location() is None or remember:
811
614
                except errors.NotLocalUrl:
812
615
                    warning('This transport does not update the working '
813
616
                            'tree of: %s' % (br_to.base,))
814
 
                    push_result = br_from.push(br_to, overwrite)
815
 
                except errors.NoWorkingTree:
816
 
                    push_result = br_from.push(br_to, overwrite)
 
617
                    count = br_to.pull(br_from, overwrite)
 
618
                except NoWorkingTree:
 
619
                    count = br_to.pull(br_from, overwrite)
817
620
                else:
818
 
                    tree_to.lock_write()
819
 
                    try:
820
 
                        push_result = br_from.push(tree_to.branch, overwrite)
821
 
                        tree_to.update()
822
 
                    finally:
823
 
                        tree_to.unlock()
824
 
            except errors.DivergedBranches:
825
 
                raise errors.BzrCommandError('These branches have diverged.'
826
 
                                        '  Try using "merge" and then "push".')
827
 
        if push_result is not None:
828
 
            push_result.report(self.outf)
829
 
        elif verbose:
 
621
                    count = tree_to.pull(br_from, overwrite)
 
622
            except DivergedBranches:
 
623
                raise BzrCommandError("These branches have diverged."
 
624
                                      "  Try a merge then push with overwrite.")
 
625
        note('%d revision(s) pushed.' % (count,))
 
626
 
 
627
        if verbose:
830
628
            new_rh = br_to.revision_history()
831
629
            if old_rh != new_rh:
832
630
                # Something changed
833
631
                from bzrlib.log import show_changed_revisions
834
632
                show_changed_revisions(br_to, old_rh, new_rh,
835
633
                                       to_file=self.outf)
836
 
        else:
837
 
            # we probably did a clone rather than a push, so a message was
838
 
            # emitted above
839
 
            pass
840
634
 
841
635
 
842
636
class cmd_branch(Command):
847
641
 
848
642
    To retrieve the branch as of a particular revision, supply the --revision
849
643
    parameter, as in "branch foo/bar -r 5".
 
644
 
 
645
    --basis is to speed up branching from remote branches.  When specified, it
 
646
    copies all the file-contents, inventory and revision data from the basis
 
647
    branch before copying anything from the remote branch.
850
648
    """
851
649
    takes_args = ['from_location', 'to_location?']
852
 
    takes_options = ['revision']
 
650
    takes_options = ['revision', 'basis']
853
651
    aliases = ['get', 'clone']
854
652
 
855
 
    def run(self, from_location, to_location=None, revision=None):
856
 
        from bzrlib.tag import _merge_tags_if_possible
 
653
    def run(self, from_location, to_location=None, revision=None, basis=None):
857
654
        if revision is None:
858
655
            revision = [None]
859
656
        elif len(revision) > 1:
860
 
            raise errors.BzrCommandError(
 
657
            raise BzrCommandError(
861
658
                'bzr branch --revision takes exactly 1 revision value')
862
 
 
863
 
        br_from = Branch.open(from_location)
 
659
        try:
 
660
            br_from = Branch.open(from_location)
 
661
        except OSError, e:
 
662
            if e.errno == errno.ENOENT:
 
663
                raise BzrCommandError('Source location "%s" does not'
 
664
                                      ' exist.' % to_location)
 
665
            else:
 
666
                raise
864
667
        br_from.lock_read()
865
668
        try:
 
669
            if basis is not None:
 
670
                basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
 
671
            else:
 
672
                basis_dir = None
866
673
            if len(revision) == 1 and revision[0] is not None:
867
674
                revision_id = revision[0].in_history(br_from)[1]
868
675
            else:
880
687
            try:
881
688
                to_transport.mkdir('.')
882
689
            except errors.FileExists:
883
 
                raise errors.BzrCommandError('Target directory "%s" already'
884
 
                                             ' exists.' % to_location)
 
690
                raise BzrCommandError('Target directory "%s" already'
 
691
                                      ' exists.' % to_location)
885
692
            except errors.NoSuchFile:
886
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
887
 
                                             % to_location)
 
693
                raise BzrCommandError('Parent of "%s" does not exist.' %
 
694
                                      to_location)
888
695
            try:
889
696
                # preserve whatever source format we have.
890
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id)
 
697
                dir = br_from.bzrdir.sprout(to_transport.base,
 
698
                        revision_id, basis_dir)
891
699
                branch = dir.open_branch()
892
700
            except errors.NoSuchRevision:
893
701
                to_transport.delete_tree('.')
894
702
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
895
 
                raise errors.BzrCommandError(msg)
 
703
                raise BzrCommandError(msg)
 
704
            except errors.UnlistableBranch:
 
705
                osutils.rmtree(to_location)
 
706
                msg = "The branch %s cannot be used as a --basis" % (basis,)
 
707
                raise BzrCommandError(msg)
896
708
            if name:
897
709
                branch.control_files.put_utf8('branch-name', name)
898
 
            _merge_tags_if_possible(br_from, branch)
899
710
            note('Branched %d revision(s).' % branch.revno())
900
711
        finally:
901
712
            br_from.unlock()
917
728
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
918
729
    code.)
919
730
 
920
 
    See "help checkouts" for more information on checkouts.
 
731
    --basis is to speed up checking out from remote branches.  When specified, it
 
732
    uses the inventory and file contents from the basis branch in preference to the
 
733
    branch being checked out.
921
734
    """
922
735
    takes_args = ['branch_location?', 'to_location?']
923
 
    takes_options = ['revision',
 
736
    takes_options = ['revision', # , 'basis']
924
737
                     Option('lightweight',
925
738
                            help="perform a lightweight checkout. Lightweight "
926
739
                                 "checkouts depend on access to the branch for "
931
744
                     ]
932
745
    aliases = ['co']
933
746
 
934
 
    def run(self, branch_location=None, to_location=None, revision=None,
 
747
    def run(self, branch_location=None, to_location=None, revision=None, basis=None,
935
748
            lightweight=False):
936
749
        if revision is None:
937
750
            revision = [None]
938
751
        elif len(revision) > 1:
939
 
            raise errors.BzrCommandError(
 
752
            raise BzrCommandError(
940
753
                'bzr checkout --revision takes exactly 1 revision value')
941
754
        if branch_location is None:
942
755
            branch_location = osutils.getcwd()
962
775
            os.mkdir(to_location)
963
776
        except OSError, e:
964
777
            if e.errno == errno.EEXIST:
965
 
                raise errors.BzrCommandError('Target directory "%s" already'
966
 
                                             ' exists.' % to_location)
 
778
                raise BzrCommandError('Target directory "%s" already'
 
779
                                      ' exists.' % to_location)
967
780
            if e.errno == errno.ENOENT:
968
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
969
 
                                             % to_location)
 
781
                raise BzrCommandError('Parent of "%s" does not exist.' %
 
782
                                      to_location)
970
783
            else:
971
784
                raise
972
 
        source.create_checkout(to_location, revision_id, lightweight)
 
785
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
786
        bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
 
787
        try:
 
788
            source.create_checkout(to_location, revision_id, lightweight)
 
789
        finally:
 
790
            bzrdir.BzrDirFormat.set_default_format(old_format)
973
791
 
974
792
 
975
793
class cmd_renames(Command):
982
800
 
983
801
    @display_command
984
802
    def run(self, dir=u'.'):
 
803
        from bzrlib.tree import find_renames
985
804
        tree = WorkingTree.open_containing(dir)[0]
986
 
        tree.lock_read()
987
 
        try:
988
 
            new_inv = tree.inventory
989
 
            old_tree = tree.basis_tree()
990
 
            old_tree.lock_read()
991
 
            try:
992
 
                old_inv = old_tree.inventory
993
 
                renames = list(_mod_tree.find_renames(old_inv, new_inv))
994
 
                renames.sort()
995
 
                for old_name, new_name in renames:
996
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
997
 
            finally:
998
 
                old_tree.unlock()
999
 
        finally:
1000
 
            tree.unlock()
 
805
        old_inv = tree.basis_tree().inventory
 
806
        new_inv = tree.read_working_inventory()
 
807
        renames = list(find_renames(old_inv, new_inv))
 
808
        renames.sort()
 
809
        for old_name, new_name in renames:
 
810
            self.outf.write("%s => %s\n" % (old_name, new_name))
1001
811
 
1002
812
 
1003
813
class cmd_update(Command):
1015
825
 
1016
826
    def run(self, dir='.'):
1017
827
        tree = WorkingTree.open_containing(dir)[0]
1018
 
        master = tree.branch.get_master_branch()
1019
 
        if master is not None:
1020
 
            tree.lock_write()
1021
 
        else:
1022
 
            tree.lock_tree_write()
 
828
        tree.lock_write()
1023
829
        try:
1024
 
            existing_pending_merges = tree.get_parent_ids()[1:]
 
830
            existing_pending_merges = tree.pending_merges()
1025
831
            last_rev = tree.last_revision()
1026
832
            if last_rev == tree.branch.last_revision():
1027
833
                # may be up to date, check master too.
1033
839
            conflicts = tree.update()
1034
840
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
1035
841
            note('Updated to revision %d.' % (revno,))
1036
 
            if tree.get_parent_ids()[1:] != existing_pending_merges:
 
842
            if tree.pending_merges() != existing_pending_merges:
1037
843
                note('Your local commits will now show as pending merges with '
1038
844
                     "'bzr status', and can be committed with 'bzr commit'.")
1039
845
            if conflicts != 0:
1083
889
        tree, file_list = tree_files(file_list)
1084
890
        if new is False:
1085
891
            if file_list is None:
1086
 
                raise errors.BzrCommandError('Specify one or more files to'
1087
 
                                             ' remove, or use --new.')
 
892
                raise BzrCommandError('Specify one or more files to remove, or'
 
893
                                      ' use --new.')
1088
894
        else:
1089
895
            added = tree.changes_from(tree.basis_tree(),
1090
896
                specific_files=file_list).added
1091
897
            file_list = sorted([f[0] for f in added], reverse=True)
1092
898
            if len(file_list) == 0:
1093
 
                raise errors.BzrCommandError('No matching files.')
 
899
                raise BzrCommandError('No matching files.')
1094
900
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
1095
901
 
1096
902
 
1108
914
    @display_command
1109
915
    def run(self, filename):
1110
916
        tree, relpath = WorkingTree.open_containing(filename)
1111
 
        i = tree.path2id(relpath)
 
917
        i = tree.inventory.path2id(relpath)
1112
918
        if i is None:
1113
 
            raise errors.NotVersionedError(filename)
 
919
            raise BzrError("%r is not a versioned file" % filename)
1114
920
        else:
1115
921
            self.outf.write(i + '\n')
1116
922
 
1128
934
    @display_command
1129
935
    def run(self, filename):
1130
936
        tree, relpath = WorkingTree.open_containing(filename)
1131
 
        fid = tree.path2id(relpath)
 
937
        inv = tree.inventory
 
938
        fid = inv.path2id(relpath)
1132
939
        if fid is None:
1133
 
            raise errors.NotVersionedError(filename)
1134
 
        segments = osutils.splitpath(relpath)
1135
 
        for pos in range(1, len(segments) + 1):
1136
 
            path = osutils.joinpath(segments[:pos])
1137
 
            self.outf.write("%s\n" % tree.path2id(path))
 
940
            raise BzrError("%r is not a versioned file" % filename)
 
941
        for fip in inv.get_idpath(fid):
 
942
            self.outf.write(fip + '\n')
1138
943
 
1139
944
 
1140
945
class cmd_reconcile(Command):
1209
1014
 
1210
1015
    If there is a repository in a parent directory of the location, then 
1211
1016
    the history of the branch will be stored in the repository.  Otherwise
1212
 
    init creates a standalone branch which carries its own history
1213
 
    in the .bzr directory.
 
1017
    init creates a standalone branch which carries its own history in 
 
1018
    .bzr.
1214
1019
 
1215
1020
    If there is already a branch at the location but it has no working tree,
1216
1021
    the tree can be populated with 'bzr checkout'.
1224
1029
    """
1225
1030
    takes_args = ['location?']
1226
1031
    takes_options = [
1227
 
         RegistryOption('format',
1228
 
                help='Specify a format for this branch. '
1229
 
                'See "help formats".',
1230
 
                registry=bzrdir.format_registry,
1231
 
                converter=bzrdir.format_registry.make_bzrdir,
1232
 
                value_switches=True,
1233
 
                title="Branch Format",
1234
 
                ),
1235
 
         Option('append-revisions-only',
1236
 
                help='Never change revnos or the existing log.'
1237
 
                '  Append revisions to it only.')
1238
 
         ]
1239
 
    def run(self, location=None, format=None, append_revisions_only=False):
 
1032
                     Option('format', 
 
1033
                            help='Specify a format for this branch. Current'
 
1034
                                 ' formats are: default, knit, metaweave and'
 
1035
                                 ' weave. Default is knit; metaweave and'
 
1036
                                 ' weave are deprecated',
 
1037
                            type=get_format_type),
 
1038
                     ]
 
1039
    def run(self, location=None, format=None):
1240
1040
        if format is None:
1241
 
            format = bzrdir.format_registry.make_bzrdir('default')
 
1041
            format = get_format_type('default')
1242
1042
        if location is None:
1243
1043
            location = u'.'
1244
1044
 
1257
1057
                    
1258
1058
        try:
1259
1059
            existing_bzrdir = bzrdir.BzrDir.open(location)
1260
 
        except errors.NotBranchError:
 
1060
        except NotBranchError:
1261
1061
            # really a NotBzrDir error...
1262
 
            branch = bzrdir.BzrDir.create_branch_convenience(to_transport.base,
1263
 
                                                             format=format)
 
1062
            bzrdir.BzrDir.create_branch_convenience(location, format=format)
1264
1063
        else:
1265
 
            from bzrlib.transport.local import LocalTransport
1266
1064
            if existing_bzrdir.has_branch():
1267
1065
                if (isinstance(to_transport, LocalTransport)
1268
1066
                    and not existing_bzrdir.has_workingtree()):
1269
1067
                        raise errors.BranchExistsWithoutWorkingTree(location)
1270
1068
                raise errors.AlreadyBranchError(location)
1271
1069
            else:
1272
 
                branch = existing_bzrdir.create_branch()
 
1070
                existing_bzrdir.create_branch()
1273
1071
                existing_bzrdir.create_workingtree()
1274
 
        if append_revisions_only:
1275
 
            try:
1276
 
                branch.set_append_revisions_only(True)
1277
 
            except errors.UpgradeRequired:
1278
 
                raise errors.BzrCommandError('This branch format cannot be set'
1279
 
                    ' to append-revisions-only.  Try --experimental-branch6')
1280
1072
 
1281
1073
 
1282
1074
class cmd_init_repository(Command):
1283
1075
    """Create a shared repository to hold branches.
1284
1076
 
1285
1077
    New branches created under the repository directory will store their revisions
1286
 
    in the repository, not in the branch directory.
 
1078
    in the repository, not in the branch directory, if the branch format supports
 
1079
    shared storage.
1287
1080
 
1288
1081
    example:
1289
 
        bzr init-repo --no-trees repo
 
1082
        bzr init-repo repo
1290
1083
        bzr init repo/trunk
1291
1084
        bzr checkout --lightweight repo/trunk trunk-checkout
1292
1085
        cd trunk-checkout
1293
1086
        (add files here)
1294
1087
    """
1295
 
 
1296
 
    takes_args = ["location"]
1297
 
    takes_options = [RegistryOption('format',
1298
 
                            help='Specify a format for this repository. See'
1299
 
                                 ' "bzr help formats" for details',
1300
 
                            registry=bzrdir.format_registry,
1301
 
                            converter=bzrdir.format_registry.make_bzrdir,
1302
 
                            value_switches=True, title='Repository format'),
1303
 
                     Option('no-trees',
1304
 
                             help='Branches in the repository will default to'
1305
 
                                  ' not having a working tree'),
1306
 
                    ]
 
1088
    takes_args = ["location"] 
 
1089
    takes_options = [Option('format', 
 
1090
                            help='Specify a format for this repository.'
 
1091
                                 ' Current formats are: default, knit,'
 
1092
                                 ' metaweave and weave. Default is knit;'
 
1093
                                 ' metaweave and weave are deprecated',
 
1094
                            type=get_format_type),
 
1095
                     Option('trees',
 
1096
                             help='Allows branches in repository to have'
 
1097
                             ' a working tree')]
1307
1098
    aliases = ["init-repo"]
1308
 
 
1309
 
    def run(self, location, format=None, no_trees=False):
 
1099
    def run(self, location, format=None, trees=False):
1310
1100
        if format is None:
1311
 
            format = bzrdir.format_registry.make_bzrdir('default')
 
1101
            format = get_format_type('default')
1312
1102
 
1313
1103
        if location is None:
1314
1104
            location = '.'
1321
1111
 
1322
1112
        newdir = format.initialize_on_transport(to_transport)
1323
1113
        repo = newdir.create_repository(shared=True)
1324
 
        repo.set_make_working_trees(not no_trees)
 
1114
        repo.set_make_working_trees(trees)
1325
1115
 
1326
1116
 
1327
1117
class cmd_diff(Command):
1340
1130
            Difference between the working tree and revision 1
1341
1131
        bzr diff -r1..2
1342
1132
            Difference between revision 2 and revision 1
1343
 
        bzr diff --prefix old/:new/
 
1133
        bzr diff --diff-prefix old/:new/
1344
1134
            Same as 'bzr diff' but prefix paths with old/ and new/
1345
1135
        bzr diff bzr.mine bzr.dev
1346
1136
            Show the differences between the two working trees
1357
1147
    #       deleted files.
1358
1148
 
1359
1149
    # TODO: This probably handles non-Unix newlines poorly.
1360
 
 
 
1150
    
1361
1151
    takes_args = ['file*']
1362
 
    takes_options = ['revision', 'diff-options',
1363
 
        Option('prefix', type=str,
1364
 
               short_name='p',
1365
 
               help='Set prefixes to added to old and new filenames, as '
1366
 
                    'two values separated by a colon. (eg "old/:new/")'),
1367
 
        ]
 
1152
    takes_options = ['revision', 'diff-options', 'prefix']
1368
1153
    aliases = ['di', 'dif']
1369
1154
    encoding_type = 'exact'
1370
1155
 
1380
1165
        elif prefix == '1':
1381
1166
            old_label = 'old/'
1382
1167
            new_label = 'new/'
1383
 
        elif ':' in prefix:
 
1168
        else:
 
1169
            if not ':' in prefix:
 
1170
                 raise BzrError("--diff-prefix expects two values separated by a colon")
1384
1171
            old_label, new_label = prefix.split(":")
1385
 
        else:
1386
 
            raise errors.BzrCommandError(
1387
 
                '--prefix expects two values separated by a colon'
1388
 
                ' (eg "old/:new/")')
1389
 
 
1390
 
        if revision and len(revision) > 2:
1391
 
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1392
 
                                         ' one or two revision specifiers')
1393
 
 
 
1172
        
1394
1173
        try:
1395
1174
            tree1, file_list = internal_tree_files(file_list)
1396
1175
            tree2 = None
1397
1176
            b = None
1398
1177
            b2 = None
1399
 
        except errors.FileInWrongBranch:
 
1178
        except FileInWrongBranch:
1400
1179
            if len(file_list) != 2:
1401
 
                raise errors.BzrCommandError("Files are in different branches")
 
1180
                raise BzrCommandError("Files are in different branches")
1402
1181
 
1403
1182
            tree1, file1 = WorkingTree.open_containing(file_list[0])
1404
1183
            tree2, file2 = WorkingTree.open_containing(file_list[1])
1405
1184
            if file1 != "" or file2 != "":
1406
1185
                # FIXME diff those two files. rbc 20051123
1407
 
                raise errors.BzrCommandError("Files are in different branches")
 
1186
                raise BzrCommandError("Files are in different branches")
1408
1187
            file_list = None
1409
 
        except errors.NotBranchError:
 
1188
        except NotBranchError:
1410
1189
            if (revision is not None and len(revision) == 2
1411
1190
                and not revision[0].needs_branch()
1412
1191
                and not revision[1].needs_branch()):
1415
1194
                tree1, tree2 = None, None
1416
1195
            else:
1417
1196
                raise
1418
 
 
1419
 
        if tree2 is not None:
1420
 
            if revision is not None:
1421
 
                # FIXME: but there should be a clean way to diff between
1422
 
                # non-default versions of two trees, it's not hard to do
1423
 
                # internally...
1424
 
                raise errors.BzrCommandError(
1425
 
                        "Sorry, diffing arbitrary revisions across branches "
1426
 
                        "is not implemented yet")
1427
 
            return show_diff_trees(tree1, tree2, sys.stdout, 
1428
 
                                   specific_files=file_list,
1429
 
                                   external_diff_options=diff_options,
1430
 
                                   old_label=old_label, new_label=new_label)
1431
 
 
1432
 
        return diff_cmd_helper(tree1, file_list, diff_options,
1433
 
                               revision_specs=revision,
1434
 
                               old_label=old_label, new_label=new_label)
 
1197
        if revision is not None:
 
1198
            if tree2 is not None:
 
1199
                raise BzrCommandError("Can't specify -r with two branches")
 
1200
            if (len(revision) == 1) or (revision[1].spec is None):
 
1201
                return diff_cmd_helper(tree1, file_list, diff_options,
 
1202
                                       revision[0], 
 
1203
                                       old_label=old_label, new_label=new_label)
 
1204
            elif len(revision) == 2:
 
1205
                return diff_cmd_helper(tree1, file_list, diff_options,
 
1206
                                       revision[0], revision[1],
 
1207
                                       old_label=old_label, new_label=new_label)
 
1208
            else:
 
1209
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
 
1210
        else:
 
1211
            if tree2 is not None:
 
1212
                return show_diff_trees(tree1, tree2, sys.stdout, 
 
1213
                                       specific_files=file_list,
 
1214
                                       external_diff_options=diff_options,
 
1215
                                       old_label=old_label, new_label=new_label)
 
1216
            else:
 
1217
                return diff_cmd_helper(tree1, file_list, diff_options,
 
1218
                                       old_label=old_label, new_label=new_label)
1435
1219
 
1436
1220
 
1437
1221
class cmd_deleted(Command):
1448
1232
    @display_command
1449
1233
    def run(self, show_ids=False):
1450
1234
        tree = WorkingTree.open_containing(u'.')[0]
1451
 
        tree.lock_read()
1452
 
        try:
1453
 
            old = tree.basis_tree()
1454
 
            old.lock_read()
1455
 
            try:
1456
 
                for path, ie in old.inventory.iter_entries():
1457
 
                    if not tree.has_id(ie.file_id):
1458
 
                        self.outf.write(path)
1459
 
                        if show_ids:
1460
 
                            self.outf.write(' ')
1461
 
                            self.outf.write(ie.file_id)
1462
 
                        self.outf.write('\n')
1463
 
            finally:
1464
 
                old.unlock()
1465
 
        finally:
1466
 
            tree.unlock()
 
1235
        old = tree.basis_tree()
 
1236
        for path, ie in old.inventory.iter_entries():
 
1237
            if not tree.has_id(ie.file_id):
 
1238
                self.outf.write(path)
 
1239
                if show_ids:
 
1240
                    self.outf.write(' ')
 
1241
                    self.outf.write(ie.file_id)
 
1242
                self.outf.write('\n')
1467
1243
 
1468
1244
 
1469
1245
class cmd_modified(Command):
1470
 
    """List files modified in working tree.
1471
 
 
1472
 
    See also: "bzr status".
1473
 
    """
1474
 
 
 
1246
    """List files modified in working tree."""
1475
1247
    hidden = True
1476
 
 
1477
1248
    @display_command
1478
1249
    def run(self):
1479
1250
        tree = WorkingTree.open_containing(u'.')[0]
1483
1254
 
1484
1255
 
1485
1256
class cmd_added(Command):
1486
 
    """List files added in working tree.
1487
 
 
1488
 
    See also: "bzr status".
1489
 
    """
1490
 
 
 
1257
    """List files added in working tree."""
1491
1258
    hidden = True
1492
 
 
1493
1259
    @display_command
1494
1260
    def run(self):
1495
1261
        wt = WorkingTree.open_containing(u'.')[0]
1496
 
        wt.lock_read()
1497
 
        try:
1498
 
            basis = wt.basis_tree()
1499
 
            basis.lock_read()
1500
 
            try:
1501
 
                basis_inv = basis.inventory
1502
 
                inv = wt.inventory
1503
 
                for file_id in inv:
1504
 
                    if file_id in basis_inv:
1505
 
                        continue
1506
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
1507
 
                        continue
1508
 
                    path = inv.id2path(file_id)
1509
 
                    if not os.access(osutils.abspath(path), os.F_OK):
1510
 
                        continue
1511
 
                    self.outf.write(path + '\n')
1512
 
            finally:
1513
 
                basis.unlock()
1514
 
        finally:
1515
 
            wt.unlock()
 
1262
        basis_inv = wt.basis_tree().inventory
 
1263
        inv = wt.inventory
 
1264
        for file_id in inv:
 
1265
            if file_id in basis_inv:
 
1266
                continue
 
1267
            path = inv.id2path(file_id)
 
1268
            if not os.access(osutils.abspath(path), os.F_OK):
 
1269
                continue
 
1270
            self.outf.write(path + '\n')
1516
1271
 
1517
1272
 
1518
1273
class cmd_root(Command):
1550
1305
                            help='show from oldest to newest'),
1551
1306
                     'timezone', 
1552
1307
                     Option('verbose', 
1553
 
                             short_name='v',
1554
1308
                             help='show files changed in each revision'),
1555
1309
                     'show-ids', 'revision',
1556
1310
                     'log-format',
 
1311
                     'line', 'long', 
1557
1312
                     Option('message',
1558
 
                            short_name='m',
1559
1313
                            help='show revisions whose message matches this regexp',
1560
1314
                            type=str),
 
1315
                     'short',
1561
1316
                     ]
1562
1317
    encoding_type = 'replace'
1563
1318
 
1568
1323
            forward=False,
1569
1324
            revision=None,
1570
1325
            log_format=None,
1571
 
            message=None):
1572
 
        from bzrlib.log import show_log
 
1326
            message=None,
 
1327
            long=False,
 
1328
            short=False,
 
1329
            line=False):
 
1330
        from bzrlib.log import log_formatter, show_log
1573
1331
        assert message is None or isinstance(message, basestring), \
1574
1332
            "invalid message argument %r" % message
1575
1333
        direction = (forward and 'forward') or 'reverse'
1579
1337
        if location:
1580
1338
            # find the file id to log:
1581
1339
 
1582
 
            tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1583
 
                location)
 
1340
            dir, fp = bzrdir.BzrDir.open_containing(location)
 
1341
            b = dir.open_branch()
1584
1342
            if fp != '':
1585
 
                if tree is None:
1586
 
                    tree = b.basis_tree()
1587
 
                file_id = tree.path2id(fp)
1588
 
                if file_id is None:
1589
 
                    raise errors.BzrCommandError(
1590
 
                        "Path does not have any revision history: %s" %
1591
 
                        location)
 
1343
                try:
 
1344
                    # might be a tree:
 
1345
                    inv = dir.open_workingtree().inventory
 
1346
                except (errors.NotBranchError, errors.NotLocalUrl):
 
1347
                    # either no tree, or is remote.
 
1348
                    inv = b.basis_tree().inventory
 
1349
                file_id = inv.path2id(fp)
1592
1350
        else:
1593
1351
            # local dir only
1594
1352
            # FIXME ? log the current subdir only RBC 20060203 
1600
1358
            dir, relpath = bzrdir.BzrDir.open_containing(location)
1601
1359
            b = dir.open_branch()
1602
1360
 
1603
 
        b.lock_read()
1604
 
        try:
1605
 
            if revision is None:
1606
 
                rev1 = None
1607
 
                rev2 = None
1608
 
            elif len(revision) == 1:
1609
 
                rev1 = rev2 = revision[0].in_history(b).revno
1610
 
            elif len(revision) == 2:
1611
 
                if revision[1].get_branch() != revision[0].get_branch():
1612
 
                    # b is taken from revision[0].get_branch(), and
1613
 
                    # show_log will use its revision_history. Having
1614
 
                    # different branches will lead to weird behaviors.
1615
 
                    raise errors.BzrCommandError(
1616
 
                        "Log doesn't accept two revisions in different"
1617
 
                        " branches.")
1618
 
                if revision[0].spec is None:
1619
 
                    # missing begin-range means first revision
1620
 
                    rev1 = 1
1621
 
                else:
1622
 
                    rev1 = revision[0].in_history(b).revno
1623
 
 
1624
 
                if revision[1].spec is None:
1625
 
                    # missing end-range means last known revision
1626
 
                    rev2 = b.revno()
1627
 
                else:
1628
 
                    rev2 = revision[1].in_history(b).revno
1629
 
            else:
1630
 
                raise errors.BzrCommandError(
1631
 
                    'bzr log --revision takes one or two values.')
1632
 
 
1633
 
            # By this point, the revision numbers are converted to the +ve
1634
 
            # form if they were supplied in the -ve form, so we can do
1635
 
            # this comparison in relative safety
1636
 
            if rev1 > rev2:
1637
 
                (rev2, rev1) = (rev1, rev2)
1638
 
 
1639
 
            if log_format is None:
1640
 
                log_format = log.log_formatter_registry.get_default(b)
1641
 
 
1642
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
1643
 
                            show_timezone=timezone)
1644
 
 
1645
 
            show_log(b,
1646
 
                     lf,
1647
 
                     file_id,
1648
 
                     verbose=verbose,
1649
 
                     direction=direction,
1650
 
                     start_revision=rev1,
1651
 
                     end_revision=rev2,
1652
 
                     search=message)
1653
 
        finally:
1654
 
            b.unlock()
 
1361
        if revision is None:
 
1362
            rev1 = None
 
1363
            rev2 = None
 
1364
        elif len(revision) == 1:
 
1365
            rev1 = rev2 = revision[0].in_history(b).revno
 
1366
        elif len(revision) == 2:
 
1367
            if revision[1].get_branch() != revision[0].get_branch():
 
1368
                # b is taken from revision[0].get_branch(), and
 
1369
                # show_log will use its revision_history. Having
 
1370
                # different branches will lead to weird behaviors.
 
1371
                raise BzrCommandError(
 
1372
                    "Log doesn't accept two revisions in different branches.")
 
1373
            if revision[0].spec is None:
 
1374
                # missing begin-range means first revision
 
1375
                rev1 = 1
 
1376
            else:
 
1377
                rev1 = revision[0].in_history(b).revno
 
1378
 
 
1379
            if revision[1].spec is None:
 
1380
                # missing end-range means last known revision
 
1381
                rev2 = b.revno()
 
1382
            else:
 
1383
                rev2 = revision[1].in_history(b).revno
 
1384
        else:
 
1385
            raise BzrCommandError('bzr log --revision takes one or two values.')
 
1386
 
 
1387
        # By this point, the revision numbers are converted to the +ve
 
1388
        # form if they were supplied in the -ve form, so we can do
 
1389
        # this comparison in relative safety
 
1390
        if rev1 > rev2:
 
1391
            (rev2, rev1) = (rev1, rev2)
 
1392
 
 
1393
        if (log_format is None):
 
1394
            default = b.get_config().log_format()
 
1395
            log_format = get_log_format(long=long, short=short, line=line, 
 
1396
                                        default=default)
 
1397
        lf = log_formatter(log_format,
 
1398
                           show_ids=show_ids,
 
1399
                           to_file=self.outf,
 
1400
                           show_timezone=timezone)
 
1401
 
 
1402
        show_log(b,
 
1403
                 lf,
 
1404
                 file_id,
 
1405
                 verbose=verbose,
 
1406
                 direction=direction,
 
1407
                 start_revision=rev1,
 
1408
                 end_revision=rev2,
 
1409
                 search=message)
1655
1410
 
1656
1411
 
1657
1412
def get_log_format(long=False, short=False, line=False, default='long'):
1678
1433
    def run(self, filename):
1679
1434
        tree, relpath = WorkingTree.open_containing(filename)
1680
1435
        b = tree.branch
1681
 
        file_id = tree.path2id(relpath)
 
1436
        inv = tree.read_working_inventory()
 
1437
        file_id = inv.path2id(relpath)
1682
1438
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1683
1439
            self.outf.write("%6d %s\n" % (revno, what))
1684
1440
 
1686
1442
class cmd_ls(Command):
1687
1443
    """List files in a tree.
1688
1444
    """
1689
 
 
1690
 
    takes_args = ['path?']
1691
1445
    # TODO: Take a revision or remote path and list that tree instead.
 
1446
    hidden = True
1692
1447
    takes_options = ['verbose', 'revision',
1693
1448
                     Option('non-recursive',
1694
1449
                            help='don\'t recurse into sub-directories'),
1699
1454
                     Option('ignored', help='Print ignored files'),
1700
1455
 
1701
1456
                     Option('null', help='Null separate the files'),
1702
 
                     'kind', 'show-ids'
1703
1457
                    ]
1704
1458
    @display_command
1705
1459
    def run(self, revision=None, verbose=False, 
1706
1460
            non_recursive=False, from_root=False,
1707
1461
            unknown=False, versioned=False, ignored=False,
1708
 
            null=False, kind=None, show_ids=False, path=None):
1709
 
 
1710
 
        if kind and kind not in ('file', 'directory', 'symlink'):
1711
 
            raise errors.BzrCommandError('invalid kind specified')
 
1462
            null=False):
1712
1463
 
1713
1464
        if verbose and null:
1714
 
            raise errors.BzrCommandError('Cannot set both --verbose and --null')
 
1465
            raise BzrCommandError('Cannot set both --verbose and --null')
1715
1466
        all = not (unknown or versioned or ignored)
1716
1467
 
1717
1468
        selection = {'I':ignored, '?':unknown, 'V':versioned}
1718
1469
 
1719
 
        if path is None:
1720
 
            fs_path = '.'
1721
 
            prefix = ''
1722
 
        else:
1723
 
            if from_root:
1724
 
                raise errors.BzrCommandError('cannot specify both --from-root'
1725
 
                                             ' and PATH')
1726
 
            fs_path = path
1727
 
            prefix = path
1728
 
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
1729
 
            fs_path)
 
1470
        tree, relpath = WorkingTree.open_containing(u'.')
1730
1471
        if from_root:
1731
1472
            relpath = u''
1732
1473
        elif relpath:
1733
1474
            relpath += '/'
1734
1475
        if revision is not None:
1735
 
            tree = branch.repository.revision_tree(
1736
 
                revision[0].in_history(branch).rev_id)
1737
 
        elif tree is None:
1738
 
            tree = branch.basis_tree()
 
1476
            tree = tree.branch.repository.revision_tree(
 
1477
                revision[0].in_history(tree.branch).rev_id)
1739
1478
 
1740
 
        tree.lock_read()
1741
 
        try:
1742
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
1743
 
                if fp.startswith(relpath):
1744
 
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
1745
 
                    if non_recursive and '/' in fp:
1746
 
                        continue
1747
 
                    if not all and not selection[fc]:
1748
 
                        continue
1749
 
                    if kind is not None and fkind != kind:
1750
 
                        continue
1751
 
                    if verbose:
1752
 
                        kindch = entry.kind_character()
1753
 
                        outstring = '%-8s %s%s' % (fc, fp, kindch)
1754
 
                        if show_ids and fid is not None:
1755
 
                            outstring = "%-50s %s" % (outstring, fid)
1756
 
                        self.outf.write(outstring + '\n')
1757
 
                    elif null:
1758
 
                        self.outf.write(fp + '\0')
1759
 
                        if show_ids:
1760
 
                            if fid is not None:
1761
 
                                self.outf.write(fid)
1762
 
                            self.outf.write('\0')
1763
 
                        self.outf.flush()
1764
 
                    else:
1765
 
                        if fid is not None:
1766
 
                            my_id = fid
1767
 
                        else:
1768
 
                            my_id = ''
1769
 
                        if show_ids:
1770
 
                            self.outf.write('%-50s %s\n' % (fp, my_id))
1771
 
                        else:
1772
 
                            self.outf.write(fp + '\n')
1773
 
        finally:
1774
 
            tree.unlock()
 
1479
        for fp, fc, kind, fid, entry in tree.list_files():
 
1480
            if fp.startswith(relpath):
 
1481
                fp = fp[len(relpath):]
 
1482
                if non_recursive and '/' in fp:
 
1483
                    continue
 
1484
                if not all and not selection[fc]:
 
1485
                    continue
 
1486
                if verbose:
 
1487
                    kindch = entry.kind_character()
 
1488
                    self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
 
1489
                elif null:
 
1490
                    self.outf.write(fp + '\0')
 
1491
                    self.outf.flush()
 
1492
                else:
 
1493
                    self.outf.write(fp + '\n')
1775
1494
 
1776
1495
 
1777
1496
class cmd_unknowns(Command):
1778
 
    """List unknown files.
1779
 
 
1780
 
    See also: "bzr ls --unknown".
1781
 
    """
1782
 
 
1783
 
    hidden = True
1784
 
 
 
1497
    """List unknown files."""
1785
1498
    @display_command
1786
1499
    def run(self):
1787
1500
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1789
1502
 
1790
1503
 
1791
1504
class cmd_ignore(Command):
1792
 
    """Ignore specified files or patterns.
 
1505
    """Ignore a command or pattern.
1793
1506
 
1794
1507
    To remove patterns from the ignore list, edit the .bzrignore file.
1795
1508
 
1796
 
    Trailing slashes on patterns are ignored. 
1797
 
    If the pattern contains a slash or is a regular expression, it is compared 
1798
 
    to the whole path from the branch root.  Otherwise, it is compared to only
1799
 
    the last component of the path.  To match a file only in the root 
1800
 
    directory, prepend './'.
1801
 
 
1802
 
    Ignore patterns specifying absolute paths are not allowed.
1803
 
 
1804
 
    Ignore patterns may include globbing wildcards such as:
1805
 
      ? - Matches any single character except '/'
1806
 
      * - Matches 0 or more characters except '/'
1807
 
      /**/ - Matches 0 or more directories in a path
1808
 
      [a-z] - Matches a single character from within a group of characters
1809
 
 
1810
 
    Ignore patterns may also be Python regular expressions.  
1811
 
    Regular expression ignore patterns are identified by a 'RE:' prefix 
1812
 
    followed by the regular expression.  Regular expression ignore patterns
1813
 
    may not include named or numbered groups.
1814
 
 
1815
 
    Note: ignore patterns containing shell wildcards must be quoted from 
1816
 
    the shell on Unix.
 
1509
    If the pattern contains a slash, it is compared to the whole path
 
1510
    from the branch root.  Otherwise, it is compared to only the last
 
1511
    component of the path.  To match a file only in the root directory,
 
1512
    prepend './'.
 
1513
 
 
1514
    Ignore patterns are case-insensitive on case-insensitive systems.
 
1515
 
 
1516
    Note: wildcards must be quoted from the shell on Unix.
1817
1517
 
1818
1518
    examples:
1819
1519
        bzr ignore ./Makefile
1820
1520
        bzr ignore '*.class'
1821
 
        bzr ignore 'lib/**/*.o'
1822
 
        bzr ignore 'RE:lib/.*\.o'
1823
1521
    """
1824
 
    takes_args = ['name_pattern*']
 
1522
    # TODO: Complain if the filename is absolute
 
1523
    takes_args = ['name_pattern?']
1825
1524
    takes_options = [
1826
1525
                     Option('old-default-rules',
1827
1526
                            help='Out the ignore rules bzr < 0.9 always used.')
1828
1527
                     ]
1829
1528
    
1830
 
    def run(self, name_pattern_list=None, old_default_rules=None):
 
1529
    def run(self, name_pattern=None, old_default_rules=None):
1831
1530
        from bzrlib.atomicfile import AtomicFile
1832
1531
        if old_default_rules is not None:
1833
1532
            # dump the rules and exit
1834
1533
            for pattern in ignores.OLD_DEFAULTS:
1835
1534
                print pattern
1836
1535
            return
1837
 
        if not name_pattern_list:
1838
 
            raise errors.BzrCommandError("ignore requires at least one "
1839
 
                                  "NAME_PATTERN or --old-default-rules")
1840
 
        name_pattern_list = [globbing.normalize_pattern(p) 
1841
 
                             for p in name_pattern_list]
1842
 
        for name_pattern in name_pattern_list:
1843
 
            if (name_pattern[0] == '/' or 
1844
 
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
1845
 
                raise errors.BzrCommandError(
1846
 
                    "NAME_PATTERN should not be an absolute path")
 
1536
        if name_pattern is None:
 
1537
            raise BzrCommandError("ignore requires a NAME_PATTERN")
1847
1538
        tree, relpath = WorkingTree.open_containing(u'.')
1848
1539
        ifn = tree.abspath('.bzrignore')
1849
1540
        if os.path.exists(ifn):
1860
1551
 
1861
1552
        if igns and igns[-1] != '\n':
1862
1553
            igns += '\n'
1863
 
        for name_pattern in name_pattern_list:
1864
 
            igns += name_pattern + '\n'
 
1554
        igns += name_pattern + '\n'
1865
1555
 
1866
 
        f = AtomicFile(ifn, 'wb')
 
1556
        f = AtomicFile(ifn, 'wt')
1867
1557
        try:
1868
1558
            f.write(igns.encode('utf-8'))
1869
1559
            f.commit()
1870
1560
        finally:
1871
1561
            f.close()
1872
1562
 
1873
 
        if not tree.path2id('.bzrignore'):
 
1563
        inv = tree.inventory
 
1564
        if inv.path2id('.bzrignore'):
 
1565
            mutter('.bzrignore is already versioned')
 
1566
        else:
 
1567
            mutter('need to make new .bzrignore file versioned')
1874
1568
            tree.add(['.bzrignore'])
1875
1569
 
1876
1570
 
1881
1575
    @display_command
1882
1576
    def run(self):
1883
1577
        tree = WorkingTree.open_containing(u'.')[0]
1884
 
        tree.lock_read()
1885
 
        try:
1886
 
            for path, file_class, kind, file_id, entry in tree.list_files():
1887
 
                if file_class != 'I':
1888
 
                    continue
1889
 
                ## XXX: Slightly inefficient since this was already calculated
1890
 
                pat = tree.is_ignored(path)
1891
 
                print '%-50s %s' % (path, pat)
1892
 
        finally:
1893
 
            tree.unlock()
 
1578
        for path, file_class, kind, file_id, entry in tree.list_files():
 
1579
            if file_class != 'I':
 
1580
                continue
 
1581
            ## XXX: Slightly inefficient since this was already calculated
 
1582
            pat = tree.is_ignored(path)
 
1583
            print '%-50s %s' % (path, pat)
1894
1584
 
1895
1585
 
1896
1586
class cmd_lookup_revision(Command):
1907
1597
        try:
1908
1598
            revno = int(revno)
1909
1599
        except ValueError:
1910
 
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
 
1600
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1911
1601
 
1912
1602
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1913
1603
 
1914
1604
 
1915
1605
class cmd_export(Command):
1916
 
    """Export current or past revision to a destination directory or archive.
 
1606
    """Export past revision to destination directory.
1917
1607
 
1918
1608
    If no revision is specified this exports the last committed revision.
1919
1609
 
1921
1611
    given, try to find the format with the extension. If no extension
1922
1612
    is found exports to a directory (equivalent to --format=dir).
1923
1613
 
1924
 
    If root is supplied, it will be used as the root directory inside
1925
 
    container formats (tar, zip, etc). If it is not supplied it will default
1926
 
    to the exported filename. The root option has no effect for 'dir' format.
1927
 
 
1928
 
    If branch is omitted then the branch containing the current working
1929
 
    directory will be used.
1930
 
 
1931
 
    Note: Export of tree with non-ASCII filenames to zip is not supported.
 
1614
    Root may be the top directory for tar, tgz and tbz2 formats. If none
 
1615
    is given, the top directory will be the root name of the file.
 
1616
 
 
1617
    Note: export of tree with non-ascii filenames to zip is not supported.
1932
1618
 
1933
1619
     Supported formats       Autodetected by extension
1934
1620
     -----------------       -------------------------
1938
1624
         tgz                      .tar.gz, .tgz
1939
1625
         zip                          .zip
1940
1626
    """
1941
 
    takes_args = ['dest', 'branch?']
 
1627
    takes_args = ['dest']
1942
1628
    takes_options = ['revision', 'format', 'root']
1943
 
    def run(self, dest, branch=None, revision=None, format=None, root=None):
 
1629
    def run(self, dest, revision=None, format=None, root=None):
1944
1630
        from bzrlib.export import export
1945
 
 
1946
 
        if branch is None:
1947
 
            tree = WorkingTree.open_containing(u'.')[0]
1948
 
            b = tree.branch
1949
 
        else:
1950
 
            b = Branch.open(branch)
1951
 
            
 
1631
        tree = WorkingTree.open_containing(u'.')[0]
 
1632
        b = tree.branch
1952
1633
        if revision is None:
1953
1634
            # should be tree.last_revision  FIXME
1954
1635
            rev_id = b.last_revision()
1955
1636
        else:
1956
1637
            if len(revision) != 1:
1957
 
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
 
1638
                raise BzrError('bzr export --revision takes exactly 1 argument')
1958
1639
            rev_id = revision[0].in_history(b).rev_id
1959
1640
        t = b.repository.revision_tree(rev_id)
1960
1641
        try:
1961
1642
            export(t, dest, format, root)
1962
1643
        except errors.NoSuchExportFormat, e:
1963
 
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
 
1644
            raise BzrCommandError('Unsupported export format: %s' % e.format)
1964
1645
 
1965
1646
 
1966
1647
class cmd_cat(Command):
1967
 
    """Write the contents of a file as of a given revision to standard output.
1968
 
 
1969
 
    If no revision is nominated, the last revision is used.
1970
 
 
1971
 
    Note: Take care to redirect standard output when using this command on a
1972
 
    binary file. 
1973
 
    """
1974
 
 
1975
 
    takes_options = ['revision', 'name-from-revision']
 
1648
    """Write a file's text from a previous revision."""
 
1649
 
 
1650
    takes_options = ['revision']
1976
1651
    takes_args = ['filename']
1977
 
    encoding_type = 'exact'
1978
1652
 
1979
1653
    @display_command
1980
 
    def run(self, filename, revision=None, name_from_revision=False):
 
1654
    def run(self, filename, revision=None):
1981
1655
        if revision is not None and len(revision) != 1:
1982
 
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
1983
 
                                        " one number")
1984
 
 
 
1656
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1985
1657
        tree = None
1986
1658
        try:
1987
 
            tree, b, relpath = \
1988
 
                    bzrdir.BzrDir.open_containing_tree_or_branch(filename)
1989
 
        except errors.NotBranchError:
 
1659
            tree, relpath = WorkingTree.open_containing(filename)
 
1660
            b = tree.branch
 
1661
        except NotBranchError:
1990
1662
            pass
1991
1663
 
 
1664
        if tree is None:
 
1665
            b, relpath = Branch.open_containing(filename)
1992
1666
        if revision is not None and revision[0].get_branch() is not None:
1993
1667
            b = Branch.open(revision[0].get_branch())
1994
 
        if tree is None:
1995
 
            tree = b.basis_tree()
1996
1668
        if revision is None:
1997
1669
            revision_id = b.last_revision()
1998
1670
        else:
1999
1671
            revision_id = revision[0].in_history(b).rev_id
2000
 
 
2001
 
        cur_file_id = tree.path2id(relpath)
2002
 
        rev_tree = b.repository.revision_tree(revision_id)
2003
 
        old_file_id = rev_tree.path2id(relpath)
2004
 
        
2005
 
        if name_from_revision:
2006
 
            if old_file_id is None:
2007
 
                raise errors.BzrCommandError("%r is not present in revision %s"
2008
 
                                                % (filename, revision_id))
2009
 
            else:
2010
 
                rev_tree.print_file(old_file_id)
2011
 
        elif cur_file_id is not None:
2012
 
            rev_tree.print_file(cur_file_id)
2013
 
        elif old_file_id is not None:
2014
 
            rev_tree.print_file(old_file_id)
2015
 
        else:
2016
 
            raise errors.BzrCommandError("%r is not present in revision %s" %
2017
 
                                         (filename, revision_id))
 
1672
        b.print_file(relpath, revision_id)
2018
1673
 
2019
1674
 
2020
1675
class cmd_local_time_offset(Command):
2036
1691
    within it is committed.
2037
1692
 
2038
1693
    A selected-file commit may fail in some cases where the committed
2039
 
    tree would be invalid. Consider::
2040
 
 
2041
 
      bzr init foo
2042
 
      mkdir foo/bar
2043
 
      bzr add foo/bar
2044
 
      bzr commit foo -m "committing foo"
2045
 
      bzr mv foo/bar foo/baz
2046
 
      mkdir foo/bar
2047
 
      bzr add foo/bar
2048
 
      bzr commit foo/bar -m "committing bar but not baz"
2049
 
 
2050
 
    In the example above, the last commit will fail by design. This gives
2051
 
    the user the opportunity to decide whether they want to commit the
2052
 
    rename at the same time, separately first, or not at all. (As a general
2053
 
    rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2054
 
 
2055
 
    Note: A selected-file commit after a merge is not yet supported.
 
1694
    tree would be invalid, such as trying to commit a file in a
 
1695
    newly-added directory that is not itself committed.
2056
1696
    """
2057
1697
    # TODO: Run hooks on tree to-be-committed, and after commit.
2058
1698
 
2068
1708
                     Option('unchanged',
2069
1709
                            help='commit even if nothing has changed'),
2070
1710
                     Option('file', type=str, 
2071
 
                            short_name='F',
2072
1711
                            argname='msgfile',
2073
1712
                            help='file containing commit message'),
2074
1713
                     Option('strict',
2090
1729
                StrictCommitFailed)
2091
1730
        from bzrlib.msgeditor import edit_commit_message, \
2092
1731
                make_commit_message_template
 
1732
        from tempfile import TemporaryFile
2093
1733
 
2094
1734
        # TODO: Need a blackbox test for invoking the external editor; may be
2095
1735
        # slightly problematic to run this cross-platform.
2096
1736
 
2097
1737
        # TODO: do more checks that the commit will succeed before 
2098
1738
        # spending the user's valuable time typing a commit message.
 
1739
        #
 
1740
        # TODO: if the commit *does* happen to fail, then save the commit 
 
1741
        # message to a temporary file where it can be recovered
2099
1742
        tree, selected_list = tree_files(selected_list)
2100
1743
        if selected_list == ['']:
2101
1744
            # workaround - commit of root of tree should be exactly the same
2105
1748
 
2106
1749
        if local and not tree.branch.get_bound_location():
2107
1750
            raise errors.LocalRequiresBoundBranch()
 
1751
        if message is None and not file:
 
1752
            template = make_commit_message_template(tree, selected_list)
 
1753
            message = edit_commit_message(template)
 
1754
            if message is None:
 
1755
                raise BzrCommandError("please specify a commit message"
 
1756
                                      " with either --message or --file")
 
1757
        elif message and file:
 
1758
            raise BzrCommandError("please specify either --message or --file")
 
1759
        
 
1760
        if file:
 
1761
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
2108
1762
 
2109
 
        def get_message(commit_obj):
2110
 
            """Callback to get commit message"""
2111
 
            my_message = message
2112
 
            if my_message is None and not file:
2113
 
                template = make_commit_message_template(tree, selected_list)
2114
 
                my_message = edit_commit_message(template)
2115
 
                if my_message is None:
2116
 
                    raise errors.BzrCommandError("please specify a commit"
2117
 
                        " message with either --message or --file")
2118
 
            elif my_message and file:
2119
 
                raise errors.BzrCommandError(
2120
 
                    "please specify either --message or --file")
2121
 
            if file:
2122
 
                my_message = codecs.open(file, 'rt', 
2123
 
                                         bzrlib.user_encoding).read()
2124
 
            if my_message == "":
2125
 
                raise errors.BzrCommandError("empty commit message specified")
2126
 
            return my_message
 
1763
        if message == "":
 
1764
            raise BzrCommandError("empty commit message specified")
2127
1765
        
2128
1766
        if verbose:
2129
1767
            reporter = ReportCommitToLog()
2130
1768
        else:
2131
1769
            reporter = NullCommitReporter()
2132
 
 
 
1770
        
2133
1771
        try:
2134
 
            tree.commit(message_callback=get_message,
2135
 
                        specific_files=selected_list,
 
1772
            tree.commit(message, specific_files=selected_list,
2136
1773
                        allow_pointless=unchanged, strict=strict, local=local,
2137
1774
                        reporter=reporter)
2138
1775
        except PointlessCommit:
2139
1776
            # FIXME: This should really happen before the file is read in;
2140
1777
            # perhaps prepare the commit; get the message; then actually commit
2141
 
            raise errors.BzrCommandError("no changes to commit."
2142
 
                              " use --unchanged to commit anyhow")
 
1778
            raise BzrCommandError("no changes to commit."
 
1779
                                  " use --unchanged to commit anyhow")
2143
1780
        except ConflictsInTree:
2144
 
            raise errors.BzrCommandError('Conflicts detected in working '
2145
 
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
2146
 
                ' resolve.')
 
1781
            raise BzrCommandError("Conflicts detected in working tree.  "
 
1782
                'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
2147
1783
        except StrictCommitFailed:
2148
 
            raise errors.BzrCommandError("Commit refused because there are"
2149
 
                              " unknown files in the working tree.")
 
1784
            raise BzrCommandError("Commit refused because there are unknown "
 
1785
                                  "files in the working tree.")
2150
1786
        except errors.BoundBranchOutOfDate, e:
2151
 
            raise errors.BzrCommandError(str(e) + "\n"
2152
 
            'To commit to master branch, run update and then commit.\n'
2153
 
            'You can also pass --local to commit to continue working '
2154
 
            'disconnected.')
2155
 
 
 
1787
            raise BzrCommandError(str(e) + "\n"
 
1788
                'To commit to master branch, run update and then commit.\n'
 
1789
                'You can also pass --local to commit to continue working '
 
1790
                'disconnected.')
2156
1791
 
2157
1792
class cmd_check(Command):
2158
1793
    """Validate consistency of branch history.
2173
1808
        check(branch, verbose)
2174
1809
 
2175
1810
 
 
1811
class cmd_scan_cache(Command):
 
1812
    hidden = True
 
1813
    def run(self):
 
1814
        from bzrlib.hashcache import HashCache
 
1815
 
 
1816
        c = HashCache(u'.')
 
1817
        c.read()
 
1818
        c.scan()
 
1819
            
 
1820
        print '%6d stats' % c.stat_count
 
1821
        print '%6d in hashcache' % len(c._cache)
 
1822
        print '%6d files removed from cache' % c.removed_count
 
1823
        print '%6d hashes updated' % c.update_count
 
1824
        print '%6d files changed too recently to cache' % c.danger_count
 
1825
 
 
1826
        if c.needs_write:
 
1827
            c.write()
 
1828
 
 
1829
 
2176
1830
class cmd_upgrade(Command):
2177
1831
    """Upgrade branch storage to current format.
2178
1832
 
2182
1836
    """
2183
1837
    takes_args = ['url?']
2184
1838
    takes_options = [
2185
 
                    RegistryOption('format',
2186
 
                        help='Upgrade to a specific format.  See "bzr help'
2187
 
                             ' formats" for details',
2188
 
                        registry=bzrdir.format_registry,
2189
 
                        converter=bzrdir.format_registry.make_bzrdir,
2190
 
                        value_switches=True, title='Branch format'),
 
1839
                     Option('format', 
 
1840
                            help='Upgrade to a specific format. Current formats'
 
1841
                                 ' are: default, knit, metaweave and weave.'
 
1842
                                 ' Default is knit; metaweave and weave are'
 
1843
                                 ' deprecated',
 
1844
                            type=get_format_type),
2191
1845
                    ]
2192
1846
 
 
1847
 
2193
1848
    def run(self, url='.', format=None):
2194
1849
        from bzrlib.upgrade import upgrade
2195
1850
        if format is None:
2196
 
            format = bzrdir.format_registry.make_bzrdir('default')
 
1851
            format = get_format_type('default')
2197
1852
        upgrade(url, format)
2198
1853
 
2199
1854
 
2219
1874
            # use branch if we're inside one; otherwise global config
2220
1875
            try:
2221
1876
                c = Branch.open_containing('.')[0].get_config()
2222
 
            except errors.NotBranchError:
 
1877
            except NotBranchError:
2223
1878
                c = config.GlobalConfig()
2224
1879
            if email:
2225
1880
                self.outf.write(c.user_email() + '\n')
2230
1885
        # display a warning if an email address isn't included in the given name.
2231
1886
        try:
2232
1887
            config.extract_email_address(name)
2233
 
        except errors.NoEmailInUsername, e:
 
1888
        except BzrError, e:
2234
1889
            warning('"%s" does not seem to contain an email address.  '
2235
1890
                    'This is allowed, but not recommended.', name)
2236
1891
        
2258
1913
 
2259
1914
    @display_command
2260
1915
    def printme(self, branch):
2261
 
        print branch.nick
 
1916
        print branch.nick 
2262
1917
 
2263
1918
 
2264
1919
class cmd_selftest(Command):
2265
1920
    """Run internal test suite.
2266
1921
    
2267
 
    This creates temporary test directories in the working directory, but not
2268
 
    existing data is affected.  These directories are deleted if the tests
2269
 
    pass, or left behind to help in debugging if they fail and --keep-output
2270
 
    is specified.
 
1922
    This creates temporary test directories in the working directory,
 
1923
    but not existing data is affected.  These directories are deleted
 
1924
    if the tests pass, or left behind to help in debugging if they
 
1925
    fail and --keep-output is specified.
2271
1926
    
2272
 
    If arguments are given, they are regular expressions that say which tests
2273
 
    should run.  Tests matching any expression are run, and other tests are
2274
 
    not run.
2275
 
 
2276
 
    Alternatively if --first is given, matching tests are run first and then
2277
 
    all other tests are run.  This is useful if you have been working in a
2278
 
    particular area, but want to make sure nothing else was broken.
 
1927
    If arguments are given, they are regular expressions that say
 
1928
    which tests should run.
2279
1929
 
2280
1930
    If the global option '--no-plugins' is given, plugins are not loaded
2281
1931
    before running the selftests.  This has two effects: features provided or
2282
1932
    modified by plugins will not be tested, and tests provided by plugins will
2283
1933
    not be run.
2284
1934
 
2285
 
    examples::
 
1935
    examples:
2286
1936
        bzr selftest ignore
2287
 
            run only tests relating to 'ignore'
2288
1937
        bzr --no-plugins selftest -v
2289
 
            disable plugins and list tests as they're run
2290
 
 
2291
 
    For each test, that needs actual disk access, bzr create their own
2292
 
    subdirectory in the temporary testing directory (testXXXX.tmp).
2293
 
    By default the name of such subdirectory is based on the name of the test.
2294
 
    If option '--numbered-dirs' is given, bzr will use sequent numbers
2295
 
    of running tests to create such subdirectories. This is default behavior
2296
 
    on Windows because of path length limitation.
2297
1938
    """
2298
1939
    # TODO: --list should give a list of all available tests
2299
1940
 
2312
1953
            return FakeNFSServer
2313
1954
        msg = "No known transport type %s. Supported types are: sftp\n" %\
2314
1955
            (typestring)
2315
 
        raise errors.BzrCommandError(msg)
 
1956
        raise BzrCommandError(msg)
2316
1957
 
2317
1958
    hidden = True
2318
1959
    takes_args = ['testspecs*']
2319
1960
    takes_options = ['verbose',
2320
 
                     Option('one',
2321
 
                             help='stop when one test fails',
2322
 
                             short_name='1',
2323
 
                             ),
2324
 
                     Option('keep-output',
 
1961
                     Option('one', help='stop when one test fails'),
 
1962
                     Option('keep-output', 
2325
1963
                            help='keep output directories when tests fail'),
2326
 
                     Option('transport',
 
1964
                     Option('transport', 
2327
1965
                            help='Use a different transport by default '
2328
1966
                                 'throughout the test suite.',
2329
1967
                            type=get_transport_type),
2330
 
                     Option('benchmark', help='run the bzr benchmarks.'),
 
1968
                     Option('benchmark', help='run the bzr bencharks.'),
2331
1969
                     Option('lsprof-timed',
2332
1970
                            help='generate lsprof output for benchmarked'
2333
1971
                                 ' sections of code.'),
2334
1972
                     Option('cache-dir', type=str,
2335
1973
                            help='a directory to cache intermediate'
2336
1974
                                 ' benchmark steps'),
2337
 
                     Option('clean-output',
2338
 
                            help='clean temporary tests directories'
2339
 
                                 ' without running tests'),
2340
 
                     Option('first',
2341
 
                            help='run all tests, but run specified tests first',
2342
 
                            short_name='f',
2343
 
                            ),
2344
 
                     Option('numbered-dirs',
2345
 
                            help='use numbered dirs for TestCaseInTempDir'),
2346
1975
                     ]
2347
 
    encoding_type = 'replace'
2348
1976
 
2349
1977
    def run(self, testspecs_list=None, verbose=None, one=False,
2350
1978
            keep_output=False, transport=None, benchmark=None,
2351
 
            lsprof_timed=None, cache_dir=None, clean_output=False,
2352
 
            first=False, numbered_dirs=None):
 
1979
            lsprof_timed=None, cache_dir=None):
2353
1980
        import bzrlib.ui
2354
1981
        from bzrlib.tests import selftest
2355
1982
        import bzrlib.benchmarks as benchmarks
2356
1983
        from bzrlib.benchmarks import tree_creator
2357
1984
 
2358
 
        if clean_output:
2359
 
            from bzrlib.tests import clean_selftest_output
2360
 
            clean_selftest_output()
2361
 
            return 0
2362
 
 
2363
 
        if numbered_dirs is None and sys.platform == 'win32':
2364
 
            numbered_dirs = True
2365
 
 
2366
1985
        if cache_dir is not None:
2367
1986
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
 
1987
        # we don't want progress meters from the tests to go to the
 
1988
        # real output; and we don't want log messages cluttering up
 
1989
        # the real logs.
 
1990
        save_ui = ui.ui_factory
2368
1991
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
2369
1992
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
2370
1993
        print
2371
 
        if testspecs_list is not None:
2372
 
            pattern = '|'.join(testspecs_list)
2373
 
        else:
2374
 
            pattern = ".*"
2375
 
        if benchmark:
2376
 
            test_suite_factory = benchmarks.test_suite
2377
 
            if verbose is None:
2378
 
                verbose = True
2379
 
            # TODO: should possibly lock the history file...
2380
 
            benchfile = open(".perf_history", "at", buffering=1)
2381
 
        else:
2382
 
            test_suite_factory = None
2383
 
            if verbose is None:
2384
 
                verbose = False
2385
 
            benchfile = None
 
1994
        info('running tests...')
2386
1995
        try:
2387
 
            result = selftest(verbose=verbose, 
2388
 
                              pattern=pattern,
2389
 
                              stop_on_failure=one, 
2390
 
                              keep_output=keep_output,
2391
 
                              transport=transport,
2392
 
                              test_suite_factory=test_suite_factory,
2393
 
                              lsprof_timed=lsprof_timed,
2394
 
                              bench_history=benchfile,
2395
 
                              matching_tests_first=first,
2396
 
                              numbered_dirs=numbered_dirs,
2397
 
                              )
 
1996
            ui.ui_factory = ui.SilentUIFactory()
 
1997
            if testspecs_list is not None:
 
1998
                pattern = '|'.join(testspecs_list)
 
1999
            else:
 
2000
                pattern = ".*"
 
2001
            if benchmark:
 
2002
                test_suite_factory = benchmarks.test_suite
 
2003
                if verbose is None:
 
2004
                    verbose = True
 
2005
                benchfile = open(".perf_history", "at")
 
2006
            else:
 
2007
                test_suite_factory = None
 
2008
                if verbose is None:
 
2009
                    verbose = False
 
2010
                benchfile = None
 
2011
            try:
 
2012
                result = selftest(verbose=verbose, 
 
2013
                                  pattern=pattern,
 
2014
                                  stop_on_failure=one, 
 
2015
                                  keep_output=keep_output,
 
2016
                                  transport=transport,
 
2017
                                  test_suite_factory=test_suite_factory,
 
2018
                                  lsprof_timed=lsprof_timed,
 
2019
                                  bench_history=benchfile)
 
2020
            finally:
 
2021
                if benchfile is not None:
 
2022
                    benchfile.close()
 
2023
            if result:
 
2024
                info('tests passed')
 
2025
            else:
 
2026
                info('tests failed')
 
2027
            return int(not result)
2398
2028
        finally:
2399
 
            if benchfile is not None:
2400
 
                benchfile.close()
2401
 
        if result:
2402
 
            info('tests passed')
2403
 
        else:
2404
 
            info('tests failed')
2405
 
        return int(not result)
 
2029
            ui.ui_factory = save_ui
2406
2030
 
2407
2031
 
2408
2032
class cmd_version(Command):
2421
2045
 
2422
2046
    @display_command
2423
2047
    def run(self):
2424
 
        print "It sure does!"
 
2048
        print "it sure does!"
2425
2049
 
2426
2050
 
2427
2051
class cmd_find_merge_base(Command):
2433
2057
    
2434
2058
    @display_command
2435
2059
    def run(self, branch, other):
2436
 
        from bzrlib.revision import MultipleRevisionSources
 
2060
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
2437
2061
        
2438
2062
        branch1 = Branch.open_containing(branch)[0]
2439
2063
        branch2 = Branch.open_containing(other)[0]
2440
2064
 
 
2065
        history_1 = branch1.revision_history()
 
2066
        history_2 = branch2.revision_history()
 
2067
 
2441
2068
        last1 = branch1.last_revision()
2442
2069
        last2 = branch2.last_revision()
2443
2070
 
2474
2101
    default, use --remember. The value will only be saved if the remote
2475
2102
    location can be accessed.
2476
2103
 
2477
 
    The results of the merge are placed into the destination working
2478
 
    directory, where they can be reviewed (with bzr diff), tested, and then
2479
 
    committed to record the result of the merge.
2480
 
 
2481
2104
    Examples:
2482
2105
 
2483
 
    To merge the latest revision from bzr.dev:
2484
 
        bzr merge ../bzr.dev
 
2106
    To merge the latest revision from bzr.dev
 
2107
    bzr merge ../bzr.dev
2485
2108
 
2486
 
    To merge changes up to and including revision 82 from bzr.dev:
2487
 
        bzr merge -r 82 ../bzr.dev
 
2109
    To merge changes up to and including revision 82 from bzr.dev
 
2110
    bzr merge -r 82 ../bzr.dev
2488
2111
 
2489
2112
    To merge the changes introduced by 82, without previous changes:
2490
 
        bzr merge -r 81..82 ../bzr.dev
 
2113
    bzr merge -r 81..82 ../bzr.dev
2491
2114
    
2492
2115
    merge refuses to run if there are any uncommitted changes, unless
2493
2116
    --force is given.
 
2117
 
 
2118
    The following merge types are available:
2494
2119
    """
2495
2120
    takes_args = ['branch?']
2496
2121
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2497
 
        Option('show-base', help="Show base revision text in "
2498
 
               "conflicts"),
2499
 
        Option('uncommitted', help='Apply uncommitted changes'
2500
 
               ' from a working copy, instead of branch changes'),
2501
 
        Option('pull', help='If the destination is already'
2502
 
                ' completely merged into the source, pull from the'
2503
 
                ' source rather than merging. When this happens,'
2504
 
                ' you do not need to commit the result.'),
2505
 
        Option('directory',
2506
 
            help='Branch to merge into, '
2507
 
                 'rather than the one containing the working directory',
2508
 
            short_name='d',
2509
 
            type=unicode,
2510
 
            ),
2511
 
    ]
 
2122
                     Option('show-base', help="Show base revision text in "
 
2123
                            "conflicts"), 
 
2124
                     Option('uncommitted', help='Apply uncommitted changes'
 
2125
                            ' from a working copy, instead of branch changes')]
 
2126
 
 
2127
    def help(self):
 
2128
        from merge import merge_type_help
 
2129
        from inspect import getdoc
 
2130
        return getdoc(self) + '\n' + merge_type_help() 
2512
2131
 
2513
2132
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2514
 
            show_base=False, reprocess=False, remember=False,
2515
 
            uncommitted=False, pull=False,
2516
 
            directory=None,
2517
 
            ):
2518
 
        from bzrlib.tag import _merge_tags_if_possible
2519
 
        other_revision_id = None
 
2133
            show_base=False, reprocess=False, remember=False, 
 
2134
            uncommitted=False):
2520
2135
        if merge_type is None:
2521
 
            merge_type = _mod_merge.Merge3Merger
 
2136
            merge_type = Merge3Merger
2522
2137
 
2523
 
        if directory is None: directory = u'.'
2524
 
        # XXX: jam 20070225 WorkingTree should be locked before you extract its
2525
 
        #      inventory. Because merge is a mutating operation, it really
2526
 
        #      should be a lock_write() for the whole cmd_merge operation.
2527
 
        #      However, cmd_merge open's its own tree in _merge_helper, which
2528
 
        #      means if we lock here, the later lock_write() will always block.
2529
 
        #      Either the merge helper code should be updated to take a tree,
2530
 
        #      (What about tree.merge_from_branch?)
2531
 
        tree = WorkingTree.open_containing(directory)[0]
2532
 
        change_reporter = delta._ChangeReporter(
2533
 
            unversioned_filter=tree.is_ignored)
 
2138
        tree = WorkingTree.open_containing(u'.')[0]
2534
2139
 
2535
2140
        if branch is not None:
2536
2141
            try:
2537
 
                mergeable = bundle.read_mergeable_from_url(
2538
 
                    branch)
2539
 
            except errors.NotABundle:
 
2142
                reader = bundle.read_bundle_from_url(branch)
 
2143
            except NotABundle:
2540
2144
                pass # Continue on considering this url a Branch
2541
2145
            else:
2542
 
                if revision is not None:
2543
 
                    raise errors.BzrCommandError(
2544
 
                        'Cannot use -r with merge directives or bundles')
2545
 
                other_revision_id = mergeable.install_revisions(
2546
 
                    tree.branch.repository)
2547
 
                revision = [RevisionSpec.from_string(
2548
 
                    'revid:' + other_revision_id)]
 
2146
                conflicts = merge_bundle(reader, tree, not force, merge_type,
 
2147
                                            reprocess, show_base)
 
2148
                if conflicts == 0:
 
2149
                    return 0
 
2150
                else:
 
2151
                    return 1
2549
2152
 
2550
2153
        if revision is None \
2551
2154
                or len(revision) < 1 or revision[0].needs_branch():
2561
2164
            other_branch, path = Branch.open_containing(branch)
2562
2165
        else:
2563
2166
            if uncommitted:
2564
 
                raise errors.BzrCommandError('Cannot use --uncommitted and'
2565
 
                                             ' --revision at the same time.')
 
2167
                raise BzrCommandError('Cannot use --uncommitted and --revision'
 
2168
                                      ' at the same time.')
2566
2169
            branch = revision[0].get_branch() or branch
2567
2170
            if len(revision) == 1:
2568
2171
                base = [None, None]
2569
 
                if other_revision_id is not None:
2570
 
                    other_branch = None
2571
 
                    path = ""
2572
 
                    other = None
2573
 
                else:
2574
 
                    other_branch, path = Branch.open_containing(branch)
2575
 
                    revno = revision[0].in_history(other_branch).revno
2576
 
                    other = [branch, revno]
 
2172
                other_branch, path = Branch.open_containing(branch)
 
2173
                revno = revision[0].in_history(other_branch).revno
 
2174
                other = [branch, revno]
2577
2175
            else:
2578
2176
                assert len(revision) == 2
2579
2177
                if None in revision:
2580
 
                    raise errors.BzrCommandError(
 
2178
                    raise BzrCommandError(
2581
2179
                        "Merge doesn't permit empty revision specifier.")
2582
2180
                base_branch, path = Branch.open_containing(branch)
2583
2181
                branch1 = revision[1].get_branch() or branch
2589
2187
                base = [branch, revision[0].in_history(base_branch).revno]
2590
2188
                other = [branch1, revision[1].in_history(other_branch).revno]
2591
2189
 
2592
 
        if ((tree.branch.get_parent() is None or remember) and
2593
 
            other_branch is not None):
 
2190
        if tree.branch.get_parent() is None or remember:
2594
2191
            tree.branch.set_parent(other_branch.base)
2595
2192
 
2596
 
        # pull tags now... it's a bit inconsistent to do it ahead of copying
2597
 
        # the history but that's done inside the merge code
2598
 
        if other_branch is not None:
2599
 
            _merge_tags_if_possible(other_branch, tree.branch)
2600
 
 
2601
2193
        if path != "":
2602
2194
            interesting_files = [path]
2603
2195
        else:
2605
2197
        pb = ui.ui_factory.nested_progress_bar()
2606
2198
        try:
2607
2199
            try:
2608
 
                conflict_count = _merge_helper(
2609
 
                    other, base, other_rev_id=other_revision_id,
2610
 
                    check_clean=(not force),
2611
 
                    merge_type=merge_type,
2612
 
                    reprocess=reprocess,
2613
 
                    show_base=show_base,
2614
 
                    pull=pull,
2615
 
                    this_dir=directory,
2616
 
                    pb=pb, file_list=interesting_files,
2617
 
                    change_reporter=change_reporter)
 
2200
                conflict_count = merge(other, base, check_clean=(not force),
 
2201
                                       merge_type=merge_type,
 
2202
                                       reprocess=reprocess,
 
2203
                                       show_base=show_base,
 
2204
                                       pb=pb, file_list=interesting_files)
2618
2205
            finally:
2619
2206
                pb.finished()
2620
2207
            if conflict_count != 0:
2641
2228
        stored_location = tree.branch.get_parent()
2642
2229
        mutter("%s", stored_location)
2643
2230
        if stored_location is None:
2644
 
            raise errors.BzrCommandError("No location specified or remembered")
 
2231
            raise BzrCommandError("No location specified or remembered")
2645
2232
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2646
2233
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
2647
2234
        return stored_location
2659
2246
    pending merge, and it lets you specify particular files.
2660
2247
 
2661
2248
    Examples:
2662
 
 
2663
2249
    $ bzr remerge --show-base
2664
2250
        Re-do the merge of all conflicted files, and show the base text in
2665
2251
        conflict regions, in addition to the usual THIS and OTHER texts.
2667
2253
    $ bzr remerge --merge-type weave --reprocess foobar
2668
2254
        Re-do the merge of "foobar", using the weave merge algorithm, with
2669
2255
        additional processing to reduce the size of conflict regions.
2670
 
    """
 
2256
    
 
2257
    The following merge types are available:"""
2671
2258
    takes_args = ['file*']
2672
2259
    takes_options = ['merge-type', 'reprocess',
2673
2260
                     Option('show-base', help="Show base revision text in "
2674
2261
                            "conflicts")]
2675
2262
 
 
2263
    def help(self):
 
2264
        from merge import merge_type_help
 
2265
        from inspect import getdoc
 
2266
        return getdoc(self) + '\n' + merge_type_help() 
 
2267
 
2676
2268
    def run(self, file_list=None, merge_type=None, show_base=False,
2677
2269
            reprocess=False):
 
2270
        from bzrlib.merge import merge_inner, transform_tree
2678
2271
        if merge_type is None:
2679
 
            merge_type = _mod_merge.Merge3Merger
 
2272
            merge_type = Merge3Merger
2680
2273
        tree, file_list = tree_files(file_list)
2681
2274
        tree.lock_write()
2682
2275
        try:
2683
2276
            parents = tree.get_parent_ids()
2684
2277
            if len(parents) != 2:
2685
 
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
2686
 
                                             " merges.  Not cherrypicking or"
2687
 
                                             " multi-merges.")
 
2278
                raise BzrCommandError("Sorry, remerge only works after normal"
 
2279
                                      " merges.  Not cherrypicking or"
 
2280
                                      " multi-merges.")
2688
2281
            repository = tree.branch.repository
2689
2282
            base_revision = common_ancestor(parents[0],
2690
2283
                                            parents[1], repository)
2698
2291
                for filename in file_list:
2699
2292
                    file_id = tree.path2id(filename)
2700
2293
                    if file_id is None:
2701
 
                        raise errors.NotVersionedError(filename)
 
2294
                        raise NotVersionedError(filename)
2702
2295
                    interesting_ids.add(file_id)
2703
2296
                    if tree.kind(file_id) != "directory":
2704
2297
                        continue
2706
2299
                    for name, ie in tree.inventory.iter_entries(file_id):
2707
2300
                        interesting_ids.add(ie.file_id)
2708
2301
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2709
 
            else:
2710
 
                # Remerge only supports resolving contents conflicts
2711
 
                allowed_conflicts = ('text conflict', 'contents conflict')
2712
 
                restore_files = [c.path for c in conflicts
2713
 
                                 if c.typestring in allowed_conflicts]
2714
 
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
2302
            transform_tree(tree, tree.basis_tree(), interesting_ids)
2715
2303
            tree.set_conflicts(ConflictList(new_conflicts))
2716
 
            if file_list is not None:
 
2304
            if file_list is None:
 
2305
                restore_files = list(tree.iter_conflicts())
 
2306
            else:
2717
2307
                restore_files = file_list
2718
2308
            for filename in restore_files:
2719
2309
                try:
2720
2310
                    restore(tree.abspath(filename))
2721
 
                except errors.NotConflicted:
 
2311
                except NotConflicted:
2722
2312
                    pass
2723
 
            conflicts = _mod_merge.merge_inner(
2724
 
                                      tree.branch, other_tree, base_tree,
2725
 
                                      this_tree=tree,
2726
 
                                      interesting_ids=interesting_ids,
2727
 
                                      other_rev_id=parents[1],
2728
 
                                      merge_type=merge_type,
2729
 
                                      show_base=show_base,
2730
 
                                      reprocess=reprocess)
 
2313
            conflicts = merge_inner(tree.branch, other_tree, base_tree,
 
2314
                                    this_tree=tree,
 
2315
                                    interesting_ids=interesting_ids,
 
2316
                                    other_rev_id=parents[1],
 
2317
                                    merge_type=merge_type,
 
2318
                                    show_base=show_base,
 
2319
                                    reprocess=reprocess)
2731
2320
        finally:
2732
2321
            tree.unlock()
2733
2322
        if conflicts > 0:
2735
2324
        else:
2736
2325
            return 0
2737
2326
 
2738
 
 
2739
2327
class cmd_revert(Command):
2740
 
    """Revert files to a previous revision.
2741
 
 
2742
 
    Giving a list of files will revert only those files.  Otherwise, all files
2743
 
    will be reverted.  If the revision is not specified with '--revision', the
2744
 
    last committed revision is used.
2745
 
 
2746
 
    To remove only some changes, without reverting to a prior version, use
2747
 
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
2748
 
    introduced by -2, without affecting the changes introduced by -1.  Or
2749
 
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
2750
 
    
2751
 
    By default, any files that have been manually changed will be backed up
2752
 
    first.  (Files changed only by merge are not backed up.)  Backup files have
2753
 
    '.~#~' appended to their name, where # is a number.
2754
 
 
2755
 
    When you provide files, you can use their current pathname or the pathname
2756
 
    from the target revision.  So you can use revert to "undelete" a file by
2757
 
    name.  If you name a directory, all the contents of that directory will be
2758
 
    reverted.
 
2328
    """Reverse all changes since the last commit.
 
2329
 
 
2330
    Only versioned files are affected.  Specify filenames to revert only 
 
2331
    those files.  By default, any files that are changed will be backed up
 
2332
    first.  Backup files have a '~' appended to their name.
2759
2333
    """
2760
2334
    takes_options = ['revision', 'no-backup']
2761
2335
    takes_args = ['file*']
 
2336
    aliases = ['merge-revert']
2762
2337
 
2763
2338
    def run(self, revision=None, no_backup=False, file_list=None):
 
2339
        from bzrlib.commands import parse_spec
2764
2340
        if file_list is not None:
2765
2341
            if len(file_list) == 0:
2766
 
                raise errors.BzrCommandError("No files specified")
 
2342
                raise BzrCommandError("No files specified")
2767
2343
        else:
2768
2344
            file_list = []
2769
2345
        
2772
2348
            # FIXME should be tree.last_revision
2773
2349
            rev_id = tree.last_revision()
2774
2350
        elif len(revision) != 1:
2775
 
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
 
2351
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
2776
2352
        else:
2777
2353
            rev_id = revision[0].in_history(tree.branch).rev_id
2778
2354
        pb = ui.ui_factory.nested_progress_bar()
2779
2355
        try:
2780
2356
            tree.revert(file_list, 
2781
2357
                        tree.branch.repository.revision_tree(rev_id),
2782
 
                        not no_backup, pb, report_changes=True)
 
2358
                        not no_backup, pb)
2783
2359
        finally:
2784
2360
            pb.finished()
2785
2361
 
2786
2362
 
2787
2363
class cmd_assert_fail(Command):
2788
2364
    """Test reporting of assertion failures"""
2789
 
    # intended just for use in testing
2790
 
 
2791
2365
    hidden = True
2792
 
 
2793
2366
    def run(self):
2794
 
        raise AssertionError("always fails")
 
2367
        assert False, "always fails"
2795
2368
 
2796
2369
 
2797
2370
class cmd_help(Command):
2798
2371
    """Show help on a command or other topic.
2799
2372
 
2800
 
    For a list of all available commands, say 'bzr help commands'.
2801
 
    """
 
2373
    For a list of all available commands, say 'bzr help commands'."""
2802
2374
    takes_options = [Option('long', 'show help on all commands')]
2803
2375
    takes_args = ['topic?']
2804
2376
    aliases = ['?', '--help', '-?', '-h']
2805
2377
    
2806
2378
    @display_command
2807
2379
    def run(self, topic=None, long=False):
2808
 
        import bzrlib.help
 
2380
        import help
2809
2381
        if topic is None and long:
2810
2382
            topic = "commands"
2811
 
        bzrlib.help.help(topic)
 
2383
        help.help(topic)
2812
2384
 
2813
2385
 
2814
2386
class cmd_shell_complete(Command):
2815
2387
    """Show appropriate completions for context.
2816
2388
 
2817
 
    For a list of all available commands, say 'bzr shell-complete'.
2818
 
    """
 
2389
    For a list of all available commands, say 'bzr shell-complete'."""
2819
2390
    takes_args = ['context?']
2820
2391
    aliases = ['s-c']
2821
2392
    hidden = True
2829
2400
class cmd_fetch(Command):
2830
2401
    """Copy in history from another branch but don't merge it.
2831
2402
 
2832
 
    This is an internal method used for pull and merge.
2833
 
    """
 
2403
    This is an internal method used for pull and merge."""
2834
2404
    hidden = True
2835
2405
    takes_args = ['from_branch', 'to_branch']
2836
2406
    def run(self, from_branch, to_branch):
2843
2413
class cmd_missing(Command):
2844
2414
    """Show unmerged/unpulled revisions between two branches.
2845
2415
 
2846
 
    OTHER_BRANCH may be local or remote.
2847
 
    """
 
2416
    OTHER_BRANCH may be local or remote."""
2848
2417
    takes_args = ['other_branch?']
2849
2418
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
2850
2419
                     Option('mine-only', 
2852
2421
                     Option('theirs-only', 
2853
2422
                            'Display changes in the remote branch only'), 
2854
2423
                     'log-format',
 
2424
                     'line',
 
2425
                     'long', 
 
2426
                     'short',
2855
2427
                     'show-ids',
2856
2428
                     'verbose'
2857
2429
                     ]
2868
2440
        if other_branch is None:
2869
2441
            other_branch = parent
2870
2442
            if other_branch is None:
2871
 
                raise errors.BzrCommandError("No peer location known or specified.")
2872
 
            display_url = urlutils.unescape_for_display(parent,
2873
 
                                                        self.outf.encoding)
2874
 
            print "Using last location: " + display_url
2875
 
 
 
2443
                raise BzrCommandError("No peer location known or specified.")
 
2444
            print "Using last location: " + local_branch.get_parent()
2876
2445
        remote_branch = Branch.open(other_branch)
2877
2446
        if remote_branch.base == local_branch.base:
2878
2447
            remote_branch = local_branch
2882
2451
            try:
2883
2452
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
2884
2453
                if (log_format is None):
2885
 
                    log_format = log.log_formatter_registry.get_default(
2886
 
                        local_branch)
2887
 
                lf = log_format(to_file=self.outf,
2888
 
                                show_ids=show_ids,
2889
 
                                show_timezone='original')
 
2454
                    default = local_branch.get_config().log_format()
 
2455
                    log_format = get_log_format(long=long, short=short, 
 
2456
                                                line=line, default=default)
 
2457
                lf = log_formatter(log_format,
 
2458
                                   to_file=self.outf,
 
2459
                                   show_ids=show_ids,
 
2460
                                   show_timezone='original')
2890
2461
                if reverse is False:
2891
2462
                    local_extra.reverse()
2892
2463
                    remote_extra.reverse()
2991
2562
    takes_args = ['filename']
2992
2563
    takes_options = [Option('all', help='show annotations on all lines'),
2993
2564
                     Option('long', help='show date in annotations'),
2994
 
                     'revision',
2995
 
                     'show-ids',
 
2565
                     'revision'
2996
2566
                     ]
2997
2567
 
2998
2568
    @display_command
2999
 
    def run(self, filename, all=False, long=False, revision=None,
3000
 
            show_ids=False):
 
2569
    def run(self, filename, all=False, long=False, revision=None):
3001
2570
        from bzrlib.annotate import annotate_file
3002
2571
        tree, relpath = WorkingTree.open_containing(filename)
3003
2572
        branch = tree.branch
3006
2575
            if revision is None:
3007
2576
                revision_id = branch.last_revision()
3008
2577
            elif len(revision) != 1:
3009
 
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
 
2578
                raise BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3010
2579
            else:
3011
2580
                revision_id = revision[0].in_history(branch).rev_id
3012
 
            file_id = tree.path2id(relpath)
 
2581
            file_id = tree.inventory.path2id(relpath)
3013
2582
            tree = branch.repository.revision_tree(revision_id)
3014
2583
            file_version = tree.inventory[file_id].revision
3015
 
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
3016
 
                          show_ids=show_ids)
 
2584
            annotate_file(branch, file_version, file_id, long, all, sys.stdout)
3017
2585
        finally:
3018
2586
            branch.unlock()
3019
2587
 
3029
2597
    def run(self, revision_id_list=None, revision=None):
3030
2598
        import bzrlib.gpg as gpg
3031
2599
        if revision_id_list is not None and revision is not None:
3032
 
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
 
2600
            raise BzrCommandError('You can only supply one of revision_id or --revision')
3033
2601
        if revision_id_list is None and revision is None:
3034
 
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
 
2602
            raise BzrCommandError('You must supply either --revision or a revision_id')
3035
2603
        b = WorkingTree.open_containing(u'.')[0].branch
3036
2604
        gpg_strategy = gpg.GPGStrategy(b.get_config())
3037
2605
        if revision_id_list is not None:
3050
2618
                if to_revid is None:
3051
2619
                    to_revno = b.revno()
3052
2620
                if from_revno is None or to_revno is None:
3053
 
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
 
2621
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
3054
2622
                for revno in range(from_revno, to_revno + 1):
3055
2623
                    b.repository.sign_revision(b.get_rev_id(revno), 
3056
2624
                                               gpg_strategy)
3057
2625
            else:
3058
 
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
 
2626
                raise BzrCommandError('Please supply either one revision, or a range.')
3059
2627
 
3060
2628
 
3061
2629
class cmd_bind(Command):
3062
 
    """Convert the current branch into a checkout of the supplied branch.
3063
 
 
3064
 
    Once converted into a checkout, commits must succeed on the master branch
3065
 
    before they will be applied to the local branch.
3066
 
 
3067
 
    See "help checkouts" for more information on checkouts.
 
2630
    """Bind the current branch to a master branch.
 
2631
 
 
2632
    After binding, commits must succeed on the master branch
 
2633
    before they are executed on the local one.
3068
2634
    """
3069
2635
 
3070
 
    takes_args = ['location?']
 
2636
    takes_args = ['location']
3071
2637
    takes_options = []
3072
2638
 
3073
2639
    def run(self, location=None):
3074
2640
        b, relpath = Branch.open_containing(u'.')
3075
 
        if location is None:
3076
 
            try:
3077
 
                location = b.get_old_bound_location()
3078
 
            except errors.UpgradeRequired:
3079
 
                raise errors.BzrCommandError('No location supplied.  '
3080
 
                    'This format does not remember old locations.')
3081
 
            else:
3082
 
                if location is None:
3083
 
                    raise errors.BzrCommandError('No location supplied and no '
3084
 
                        'previous location known')
3085
2641
        b_other = Branch.open(location)
3086
2642
        try:
3087
2643
            b.bind(b_other)
3088
 
        except errors.DivergedBranches:
3089
 
            raise errors.BzrCommandError('These branches have diverged.'
3090
 
                                         ' Try merging, and then bind again.')
 
2644
        except DivergedBranches:
 
2645
            raise BzrCommandError('These branches have diverged.'
 
2646
                                  ' Try merging, and then bind again.')
3091
2647
 
3092
2648
 
3093
2649
class cmd_unbind(Command):
3094
 
    """Convert the current checkout into a regular branch.
3095
 
 
3096
 
    After unbinding, the local branch is considered independent and subsequent
3097
 
    commits will be local only.
3098
 
 
3099
 
    See "help checkouts" for more information on checkouts.
 
2650
    """Unbind the current branch from its master branch.
 
2651
 
 
2652
    After unbinding, the local branch is considered independent.
 
2653
    All subsequent commits will be local.
3100
2654
    """
3101
2655
 
3102
2656
    takes_args = []
3105
2659
    def run(self):
3106
2660
        b, relpath = Branch.open_containing(u'.')
3107
2661
        if not b.unbind():
3108
 
            raise errors.BzrCommandError('Local branch is not bound')
 
2662
            raise BzrCommandError('Local branch is not bound')
3109
2663
 
3110
2664
 
3111
2665
class cmd_uncommit(Command):
3213
2767
            pass
3214
2768
        
3215
2769
 
3216
 
class cmd_wait_until_signalled(Command):
3217
 
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
3218
 
 
3219
 
    This just prints a line to signal when it is ready, then blocks on stdin.
3220
 
    """
3221
 
 
3222
 
    hidden = True
3223
 
 
3224
 
    def run(self):
3225
 
        sys.stdout.write("running\n")
3226
 
        sys.stdout.flush()
3227
 
        sys.stdin.readline()
3228
 
 
3229
 
 
3230
 
class cmd_serve(Command):
3231
 
    """Run the bzr server."""
3232
 
 
3233
 
    aliases = ['server']
3234
 
 
3235
 
    takes_options = [
3236
 
        Option('inet',
3237
 
               help='serve on stdin/out for use from inetd or sshd'),
3238
 
        Option('port',
3239
 
               help='listen for connections on nominated port of the form '
3240
 
                    '[hostname:]portnumber. Passing 0 as the port number will '
3241
 
                    'result in a dynamically allocated port. Default port is '
3242
 
                    '4155.',
3243
 
               type=str),
3244
 
        Option('directory',
3245
 
               help='serve contents of directory',
3246
 
               type=unicode),
3247
 
        Option('allow-writes',
3248
 
               help='By default the server is a readonly server. Supplying '
3249
 
                    '--allow-writes enables write access to the contents of '
3250
 
                    'the served directory and below. '
3251
 
                ),
3252
 
        ]
3253
 
 
3254
 
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
3255
 
        from bzrlib.smart import server, medium
3256
 
        from bzrlib.transport import get_transport
3257
 
        from bzrlib.transport.remote import BZR_DEFAULT_PORT
3258
 
        if directory is None:
3259
 
            directory = os.getcwd()
3260
 
        url = urlutils.local_path_to_url(directory)
3261
 
        if not allow_writes:
3262
 
            url = 'readonly+' + url
3263
 
        t = get_transport(url)
3264
 
        if inet:
3265
 
            smart_server = medium.SmartServerPipeStreamMedium(
3266
 
                sys.stdin, sys.stdout, t)
3267
 
        else:
3268
 
            if port is None:
3269
 
                port = BZR_DEFAULT_PORT
3270
 
                host = '127.0.0.1'
3271
 
            else:
3272
 
                if ':' in port:
3273
 
                    host, port = port.split(':')
3274
 
                else:
3275
 
                    host = '127.0.0.1'
3276
 
                port = int(port)
3277
 
            smart_server = server.SmartTCPServer(t, host=host, port=port)
3278
 
            print 'listening on port: ', smart_server.port
3279
 
            sys.stdout.flush()
3280
 
        smart_server.serve()
3281
 
 
3282
 
class cmd_join(Command):
3283
 
    """Combine a subtree into its containing tree.
3284
 
    
3285
 
    This command is for experimental use only.  It requires the target tree
3286
 
    to be in dirstate-with-subtree format, which cannot be converted into
3287
 
    earlier formats.
3288
 
 
3289
 
    The TREE argument should be an independent tree, inside another tree, but
3290
 
    not part of it.  (Such trees can be produced by "bzr split", but also by
3291
 
    running "bzr branch" with the target inside a tree.)
3292
 
 
3293
 
    The result is a combined tree, with the subtree no longer an independant
3294
 
    part.  This is marked as a merge of the subtree into the containing tree,
3295
 
    and all history is preserved.
3296
 
 
3297
 
    If --reference is specified, the subtree retains its independence.  It can
3298
 
    be branched by itself, and can be part of multiple projects at the same
3299
 
    time.  But operations performed in the containing tree, such as commit
3300
 
    and merge, will recurse into the subtree.
3301
 
    """
3302
 
 
3303
 
    takes_args = ['tree']
3304
 
    takes_options = [Option('reference', 'join by reference')]
3305
 
    hidden = True
3306
 
 
3307
 
    def run(self, tree, reference=False):
3308
 
        sub_tree = WorkingTree.open(tree)
3309
 
        parent_dir = osutils.dirname(sub_tree.basedir)
3310
 
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
3311
 
        repo = containing_tree.branch.repository
3312
 
        if not repo.supports_rich_root():
3313
 
            raise errors.BzrCommandError(
3314
 
                "Can't join trees because %s doesn't support rich root data.\n"
3315
 
                "You can use bzr upgrade on the repository."
3316
 
                % (repo,))
3317
 
        if reference:
3318
 
            try:
3319
 
                containing_tree.add_reference(sub_tree)
3320
 
            except errors.BadReferenceTarget, e:
3321
 
                # XXX: Would be better to just raise a nicely printable
3322
 
                # exception from the real origin.  Also below.  mbp 20070306
3323
 
                raise errors.BzrCommandError("Cannot join %s.  %s" %
3324
 
                                             (tree, e.reason))
3325
 
        else:
3326
 
            try:
3327
 
                containing_tree.subsume(sub_tree)
3328
 
            except errors.BadSubsumeSource, e:
3329
 
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
3330
 
                                             (tree, e.reason))
3331
 
 
3332
 
 
3333
 
class cmd_split(Command):
3334
 
    """Split a tree into two trees.
3335
 
 
3336
 
    This command is for experimental use only.  It requires the target tree
3337
 
    to be in dirstate-with-subtree format, which cannot be converted into
3338
 
    earlier formats.
3339
 
 
3340
 
    The TREE argument should be a subdirectory of a working tree.  That
3341
 
    subdirectory will be converted into an independent tree, with its own
3342
 
    branch.  Commits in the top-level tree will not apply to the new subtree.
3343
 
    If you want that behavior, do "bzr join --reference TREE".
3344
 
 
3345
 
    To undo this operation, do "bzr join TREE".
3346
 
    """
3347
 
 
3348
 
    takes_args = ['tree']
3349
 
 
3350
 
    hidden = True
3351
 
 
3352
 
    def run(self, tree):
3353
 
        containing_tree, subdir = WorkingTree.open_containing(tree)
3354
 
        sub_id = containing_tree.path2id(subdir)
3355
 
        if sub_id is None:
3356
 
            raise errors.NotVersionedError(subdir)
3357
 
        try:
3358
 
            containing_tree.extract(sub_id)
3359
 
        except errors.RootNotRich:
3360
 
            raise errors.UpgradeRequired(containing_tree.branch.base)
3361
 
 
3362
 
 
3363
 
 
3364
 
class cmd_merge_directive(Command):
3365
 
    """Generate a merge directive for auto-merge tools.
3366
 
 
3367
 
    A directive requests a merge to be performed, and also provides all the
3368
 
    information necessary to do so.  This means it must either include a
3369
 
    revision bundle, or the location of a branch containing the desired
3370
 
    revision.
3371
 
 
3372
 
    A submit branch (the location to merge into) must be supplied the first
3373
 
    time the command is issued.  After it has been supplied once, it will
3374
 
    be remembered as the default.
3375
 
 
3376
 
    A public branch is optional if a revision bundle is supplied, but required
3377
 
    if --diff or --plain is specified.  It will be remembered as the default
3378
 
    after the first use.
3379
 
    """
3380
 
 
3381
 
    takes_args = ['submit_branch?', 'public_branch?']
3382
 
 
3383
 
    takes_options = [
3384
 
        RegistryOption.from_kwargs('patch-type',
3385
 
            'The type of patch to include in the directive',
3386
 
            title='Patch type', value_switches=True, enum_switch=False,
3387
 
            bundle='Bazaar revision bundle (default)',
3388
 
            diff='Normal unified diff',
3389
 
            plain='No patch, just directive'),
3390
 
        Option('sign', help='GPG-sign the directive'), 'revision',
3391
 
        Option('mail-to', type=str,
3392
 
            help='Instead of printing the directive, email to this address'),
3393
 
        Option('message', type=str, short_name='m',
3394
 
            help='Message to use when committing this merge')
3395
 
        ]
3396
 
 
3397
 
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
3398
 
            sign=False, revision=None, mail_to=None, message=None):
3399
 
        if patch_type == 'plain':
3400
 
            patch_type = None
3401
 
        branch = Branch.open('.')
3402
 
        stored_submit_branch = branch.get_submit_branch()
3403
 
        if submit_branch is None:
3404
 
            submit_branch = stored_submit_branch
3405
 
        else:
3406
 
            if stored_submit_branch is None:
3407
 
                branch.set_submit_branch(submit_branch)
3408
 
        if submit_branch is None:
3409
 
            submit_branch = branch.get_parent()
3410
 
        if submit_branch is None:
3411
 
            raise errors.BzrCommandError('No submit branch specified or known')
3412
 
 
3413
 
        stored_public_branch = branch.get_public_branch()
3414
 
        if public_branch is None:
3415
 
            public_branch = stored_public_branch
3416
 
        elif stored_public_branch is None:
3417
 
            branch.set_public_branch(public_branch)
3418
 
        if patch_type != "bundle" and public_branch is None:
3419
 
            raise errors.BzrCommandError('No public branch specified or'
3420
 
                                         ' known')
3421
 
        if revision is not None:
3422
 
            if len(revision) != 1:
3423
 
                raise errors.BzrCommandError('bzr merge-directive takes '
3424
 
                    'exactly one revision identifier')
3425
 
            else:
3426
 
                revision_id = revision[0].in_history(branch).rev_id
3427
 
        else:
3428
 
            revision_id = branch.last_revision()
3429
 
        directive = merge_directive.MergeDirective.from_objects(
3430
 
            branch.repository, revision_id, time.time(),
3431
 
            osutils.local_time_offset(), submit_branch,
3432
 
            public_branch=public_branch, patch_type=patch_type,
3433
 
            message=message)
3434
 
        if mail_to is None:
3435
 
            if sign:
3436
 
                self.outf.write(directive.to_signed(branch))
3437
 
            else:
3438
 
                self.outf.writelines(directive.to_lines())
3439
 
        else:
3440
 
            message = directive.to_email(mail_to, branch, sign)
3441
 
            s = smtplib.SMTP()
3442
 
            server = branch.get_config().get_user_option('smtp_server')
3443
 
            if not server:
3444
 
                server = 'localhost'
3445
 
            s.connect(server)
3446
 
            s.sendmail(message['From'], message['To'], message.as_string())
3447
 
 
3448
 
 
3449
 
class cmd_tag(Command):
3450
 
    """Create a tag naming a revision.
3451
 
    
3452
 
    Tags give human-meaningful names to revisions.  Commands that take a -r
3453
 
    (--revision) option can be given -rtag:X, where X is any previously
3454
 
    created tag.
3455
 
 
3456
 
    Tags are stored in the branch.  Tags are copied from one branch to another
3457
 
    along when you branch, push, pull or merge.
3458
 
 
3459
 
    It is an error to give a tag name that already exists unless you pass 
3460
 
    --force, in which case the tag is moved to point to the new revision.
3461
 
    """
3462
 
 
3463
 
    takes_args = ['tag_name']
3464
 
    takes_options = [
3465
 
        Option('delete',
3466
 
            help='Delete this tag rather than placing it.',
3467
 
            ),
3468
 
        Option('directory',
3469
 
            help='Branch in which to place the tag.',
3470
 
            short_name='d',
3471
 
            type=unicode,
3472
 
            ),
3473
 
        Option('force',
3474
 
            help='Replace existing tags',
3475
 
            ),
3476
 
        'revision',
3477
 
        ]
3478
 
 
3479
 
    def run(self, tag_name,
3480
 
            delete=None,
3481
 
            directory='.',
3482
 
            force=None,
3483
 
            revision=None,
3484
 
            ):
3485
 
        branch, relpath = Branch.open_containing(directory)
3486
 
        branch.lock_write()
3487
 
        try:
3488
 
            if delete:
3489
 
                branch.tags.delete_tag(tag_name)
3490
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
3491
 
            else:
3492
 
                if revision:
3493
 
                    if len(revision) != 1:
3494
 
                        raise errors.BzrCommandError(
3495
 
                            "Tags can only be placed on a single revision, "
3496
 
                            "not on a range")
3497
 
                    revision_id = revision[0].in_history(branch).rev_id
3498
 
                else:
3499
 
                    revision_id = branch.last_revision()
3500
 
                if (not force) and branch.tags.has_tag(tag_name):
3501
 
                    raise errors.TagAlreadyExists(tag_name)
3502
 
                branch.tags.set_tag(tag_name, revision_id)
3503
 
                self.outf.write('Created tag %s.\n' % tag_name)
3504
 
        finally:
3505
 
            branch.unlock()
3506
 
 
3507
 
 
3508
 
class cmd_tags(Command):
3509
 
    """List tags.
3510
 
 
3511
 
    This tag shows a table of tag names and the revisions they reference.
3512
 
    """
3513
 
 
3514
 
    takes_options = [
3515
 
        Option('directory',
3516
 
            help='Branch whose tags should be displayed',
3517
 
            short_name='d',
3518
 
            type=unicode,
3519
 
            ),
3520
 
    ]
3521
 
 
3522
 
    @display_command
3523
 
    def run(self,
3524
 
            directory='.',
3525
 
            ):
3526
 
        branch, relpath = Branch.open_containing(directory)
3527
 
        for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
3528
 
            self.outf.write('%-20s %s\n' % (tag_name, target))
3529
 
 
3530
2770
 
3531
2771
# command-line interpretation helper for merge-related commands
3532
 
def _merge_helper(other_revision, base_revision,
3533
 
                  check_clean=True, ignore_zero=False,
3534
 
                  this_dir=None, backup_files=False,
3535
 
                  merge_type=None,
3536
 
                  file_list=None, show_base=False, reprocess=False,
3537
 
                  pull=False,
3538
 
                  pb=DummyProgress(),
3539
 
                  change_reporter=None,
3540
 
                  other_rev_id=None):
 
2772
def merge(other_revision, base_revision,
 
2773
          check_clean=True, ignore_zero=False,
 
2774
          this_dir=None, backup_files=False, merge_type=Merge3Merger,
 
2775
          file_list=None, show_base=False, reprocess=False,
 
2776
          pb=DummyProgress()):
3541
2777
    """Merge changes into a tree.
3542
2778
 
3543
2779
    base_revision
3565
2801
    clients might prefer to call merge.merge_inner(), which has less magic 
3566
2802
    behavior.
3567
2803
    """
3568
 
    # Loading it late, so that we don't always have to import bzrlib.merge
3569
 
    if merge_type is None:
3570
 
        merge_type = _mod_merge.Merge3Merger
 
2804
    from bzrlib.merge import Merger
3571
2805
    if this_dir is None:
3572
2806
        this_dir = u'.'
3573
2807
    this_tree = WorkingTree.open_containing(this_dir)[0]
3574
 
    if show_base and not merge_type is _mod_merge.Merge3Merger:
3575
 
        raise errors.BzrCommandError("Show-base is not supported for this merge"
3576
 
                                     " type. %s" % merge_type)
 
2808
    if show_base and not merge_type is Merge3Merger:
 
2809
        raise BzrCommandError("Show-base is not supported for this merge"
 
2810
                              " type. %s" % merge_type)
3577
2811
    if reprocess and not merge_type.supports_reprocess:
3578
 
        raise errors.BzrCommandError("Conflict reduction is not supported for merge"
3579
 
                                     " type %s." % merge_type)
 
2812
        raise BzrCommandError("Conflict reduction is not supported for merge"
 
2813
                              " type %s." % merge_type)
3580
2814
    if reprocess and show_base:
3581
 
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
3582
 
    # TODO: jam 20070226 We should really lock these trees earlier. However, we
3583
 
    #       only want to take out a lock_tree_write() if we don't have to pull
3584
 
    #       any ancestry. But merge might fetch ancestry in the middle, in
3585
 
    #       which case we would need a lock_write().
3586
 
    #       Because we cannot upgrade locks, for now we live with the fact that
3587
 
    #       the tree will be locked multiple times during a merge. (Maybe
3588
 
    #       read-only some of the time, but it means things will get read
3589
 
    #       multiple times.)
 
2815
        raise BzrCommandError("Cannot do conflict reduction and show base.")
3590
2816
    try:
3591
 
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
3592
 
                                   pb=pb, change_reporter=change_reporter)
 
2817
        merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
3593
2818
        merger.pp = ProgressPhase("Merge phase", 5, pb)
3594
2819
        merger.pp.next_phase()
3595
2820
        merger.check_basis(check_clean)
3596
 
        if other_rev_id is not None:
3597
 
            merger.set_other_revision(other_rev_id, this_tree.branch)
3598
 
        else:
3599
 
            merger.set_other(other_revision)
 
2821
        merger.set_other(other_revision)
3600
2822
        merger.pp.next_phase()
3601
2823
        merger.set_base(base_revision)
3602
2824
        if merger.base_rev_id == merger.other_rev_id:
3603
2825
            note('Nothing to do.')
3604
2826
            return 0
3605
 
        if file_list is None:
3606
 
            if pull and merger.base_rev_id == merger.this_rev_id:
3607
 
                # FIXME: deduplicate with pull
3608
 
                result = merger.this_tree.pull(merger.this_branch,
3609
 
                        False, merger.other_rev_id)
3610
 
                if result.old_revid == result.new_revid:
3611
 
                    note('No revisions to pull.')
3612
 
                else:
3613
 
                    note('Now on revision %d.' % result.new_revno)
3614
 
                return 0
3615
2827
        merger.backup_files = backup_files
3616
2828
        merger.merge_type = merge_type 
3617
2829
        merger.set_interesting_files(file_list)
3625
2837
    return conflicts
3626
2838
 
3627
2839
 
3628
 
# Compatibility
3629
 
merge = _merge_helper
3630
 
 
3631
 
 
3632
2840
# these get imported and then picked up by the scan for cmd_*
3633
2841
# TODO: Some more consistent way to split command definitions across files;
3634
2842
# we do need to load at least some information about them to know of 
3635
2843
# aliases.  ideally we would avoid loading the implementation until the
3636
2844
# details were needed.
3637
 
from bzrlib.cmd_version_info import cmd_version_info
3638
2845
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
3639
2846
from bzrlib.bundle.commands import cmd_bundle_revisions
3640
2847
from bzrlib.sign_my_commits import cmd_sign_my_commits