~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: John Arbash Meinel
  • Date: 2007-04-28 15:04:17 UTC
  • mfrom: (2466 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2566.
  • Revision ID: john@arbash-meinel.com-20070428150417-trp3pi0pzd411pu4
[merge] bzr.dev 2466

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006, 2007 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
22
22
from bzrlib.lazy_import import lazy_import
23
23
lazy_import(globals(), """
24
24
import codecs
 
25
import errno
 
26
import smtplib
25
27
import sys
 
28
import tempfile
26
29
import time
27
30
 
28
31
import bzrlib
29
32
from bzrlib import (
 
33
    branch,
30
34
    bugtracker,
31
35
    bundle,
32
36
    bzrdir,
39
43
    merge as _mod_merge,
40
44
    merge_directive,
41
45
    osutils,
42
 
    reconfigure,
43
 
    revision as _mod_revision,
 
46
    registry,
 
47
    repository,
44
48
    symbol_versioning,
45
49
    transport,
46
50
    tree as _mod_tree,
48
52
    urlutils,
49
53
    )
50
54
from bzrlib.branch import Branch
 
55
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
51
56
from bzrlib.conflicts import ConflictList
 
57
from bzrlib.revision import common_ancestor
52
58
from bzrlib.revisionspec import RevisionSpec
53
 
from bzrlib.smtp_connection import SMTPConnection
54
59
from bzrlib.workingtree import WorkingTree
55
60
""")
56
61
 
57
62
from bzrlib.commands import Command, display_command
58
 
from bzrlib.option import ListOption, Option, RegistryOption, custom_help
59
 
from bzrlib.trace import mutter, note, warning, is_quiet, info
 
63
from bzrlib.option import ListOption, Option, RegistryOption
 
64
from bzrlib.progress import DummyProgress, ProgressPhase
 
65
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
60
66
 
61
67
 
62
68
def tree_files(file_list, default_branch=u'.'):
87
93
    if file_list is None or len(file_list) == 0:
88
94
        return WorkingTree.open_containing(default_branch)[0], file_list
89
95
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
90
 
    return tree, safe_relpath_files(tree, file_list)
91
 
 
92
 
 
93
 
def safe_relpath_files(tree, file_list):
94
 
    """Convert file_list into a list of relpaths in tree.
95
 
 
96
 
    :param tree: A tree to operate on.
97
 
    :param file_list: A list of user provided paths or None.
98
 
    :return: A list of relative paths.
99
 
    :raises errors.PathNotChild: When a provided path is in a different tree
100
 
        than tree.
101
 
    """
102
 
    if file_list is None:
103
 
        return None
104
96
    new_list = []
105
97
    for filename in file_list:
106
98
        try:
107
99
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
108
100
        except errors.PathNotChild:
109
101
            raise errors.FileInWrongBranch(tree.branch, filename)
110
 
    return new_list
 
102
    return tree, new_list
 
103
 
 
104
 
 
105
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
 
106
def get_format_type(typestring):
 
107
    """Parse and return a format specifier."""
 
108
    # Have to use BzrDirMetaFormat1 directly, so that
 
109
    # RepositoryFormat.set_default_format works
 
110
    if typestring == "default":
 
111
        return bzrdir.BzrDirMetaFormat1()
 
112
    try:
 
113
        return bzrdir.format_registry.make_bzrdir(typestring)
 
114
    except KeyError:
 
115
        msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
 
116
        raise errors.BzrCommandError(msg)
111
117
 
112
118
 
113
119
# TODO: Make sure no commands unconditionally use the working directory as a
146
152
    To see ignored files use 'bzr ignored'.  For details on the
147
153
    changes to file texts, use 'bzr diff'.
148
154
    
149
 
    Note that --short or -S gives status flags for each item, similar
150
 
    to Subversion's status command. To get output similar to svn -q,
151
 
    use bzr status -SV.
 
155
    --short gives a status flags for each item, similar to the SVN's status
 
156
    command.
 
157
 
 
158
    Column 1: versioning / renames
 
159
      + File versioned
 
160
      - File unversioned
 
161
      R File renamed
 
162
      ? File unknown
 
163
      C File has conflicts
 
164
      P Entry for a pending merge (not a file)
 
165
 
 
166
    Column 2: Contents
 
167
      N File created
 
168
      D File deleted
 
169
      K File kind changed
 
170
      M File modified
 
171
 
 
172
    Column 3: Execute
 
173
      * The execute bit was changed
152
174
 
153
175
    If no arguments are specified, the status of the entire working
154
176
    directory is shown.  Otherwise, only the status of the specified
162
184
    # TODO: --no-recurse, --recurse options
163
185
    
164
186
    takes_args = ['file*']
165
 
    takes_options = ['show-ids', 'revision', 'change',
166
 
                     Option('short', help='Use short status indicators.',
167
 
                            short_name='S'),
168
 
                     Option('versioned', help='Only show versioned files.',
169
 
                            short_name='V'),
170
 
                     Option('no-pending', help='Don\'t show pending merges.',
171
 
                           ),
172
 
                     ]
 
187
    takes_options = ['show-ids', 'revision',
 
188
                     Option('short', help='Give short SVN-style status lines'),
 
189
                     Option('versioned', help='Only show versioned files')]
173
190
    aliases = ['st', 'stat']
174
191
 
175
192
    encoding_type = 'replace'
176
 
    _see_also = ['diff', 'revert', 'status-flags']
 
193
    _see_also = ['diff', 'revert']
177
194
    
178
195
    @display_command
179
196
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
180
 
            versioned=False, no_pending=False):
 
197
            versioned=False):
181
198
        from bzrlib.status import show_tree_status
182
199
 
183
 
        if revision and len(revision) > 2:
184
 
            raise errors.BzrCommandError('bzr status --revision takes exactly'
185
 
                                         ' one or two revision specifiers')
186
 
 
187
 
        tree, relfile_list = tree_files(file_list)
188
 
        # Avoid asking for specific files when that is not needed.
189
 
        if relfile_list == ['']:
190
 
            relfile_list = None
191
 
            # Don't disable pending merges for full trees other than '.'.
192
 
            if file_list == ['.']:
193
 
                no_pending = True
194
 
        # A specific path within a tree was given.
195
 
        elif relfile_list is not None:
196
 
            no_pending = True
 
200
        tree, file_list = tree_files(file_list)
 
201
            
197
202
        show_tree_status(tree, show_ids=show_ids,
198
 
                         specific_files=relfile_list, revision=revision,
199
 
                         to_file=self.outf, short=short, versioned=versioned,
200
 
                         show_pending=(not no_pending))
 
203
                         specific_files=file_list, revision=revision,
 
204
                         to_file=self.outf, short=short, versioned=versioned)
201
205
 
202
206
 
203
207
class cmd_cat_revision(Command):
215
219
    
216
220
    @display_command
217
221
    def run(self, revision_id=None, revision=None):
 
222
 
 
223
        revision_id = osutils.safe_revision_id(revision_id, warn=False)
218
224
        if revision_id is not None and revision is not None:
219
225
            raise errors.BzrCommandError('You can only supply one of'
220
226
                                         ' revision_id or --revision')
225
231
 
226
232
        # TODO: jam 20060112 should cat-revision always output utf-8?
227
233
        if revision_id is not None:
228
 
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
229
 
            try:
230
 
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
231
 
            except errors.NoSuchRevision:
232
 
                msg = "The repository %s contains no revision %s." % (b.repository.base,
233
 
                    revision_id)
234
 
                raise errors.BzrCommandError(msg)
 
234
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
235
235
        elif revision is not None:
236
236
            for rev in revision:
237
237
                if rev is None:
238
238
                    raise errors.BzrCommandError('You cannot specify a NULL'
239
239
                                                 ' revision.')
240
 
                rev_id = rev.as_revision_id(b)
 
240
                revno, rev_id = rev.in_history(b)
241
241
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
242
242
    
243
243
 
249
249
 
250
250
    To re-create the working tree, use "bzr checkout".
251
251
    """
252
 
    _see_also = ['checkout', 'working-trees']
 
252
    _see_also = ['checkout']
253
253
 
254
254
    takes_args = ['location?']
255
255
 
304
304
        if revision_info_list is not None:
305
305
            for rev in revision_info_list:
306
306
                revs.append(RevisionSpec.from_string(rev))
307
 
 
308
 
        b = Branch.open_containing(u'.')[0]
309
 
 
310
307
        if len(revs) == 0:
311
 
            revs.append(RevisionSpec.from_string('-1'))
 
308
            raise errors.BzrCommandError('You must supply a revision identifier')
 
309
 
 
310
        b = WorkingTree.open_containing(u'.')[0].branch
312
311
 
313
312
        for rev in revs:
314
 
            revision_id = rev.as_revision_id(b)
315
 
            try:
316
 
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
317
 
            except errors.NoSuchRevision:
318
 
                dotted_map = b.get_revision_id_to_revno_map()
319
 
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
320
 
            print '%s %s' % (revno, revision_id)
 
313
            revinfo = rev.in_history(b)
 
314
            if revinfo.revno is None:
 
315
                print '     %s' % revinfo.rev_id
 
316
            else:
 
317
                print '%4d %s' % (revinfo.revno, revinfo.rev_id)
321
318
 
322
319
    
323
320
class cmd_add(Command):
355
352
    into a subdirectory of this one.
356
353
    """
357
354
    takes_args = ['file*']
358
 
    takes_options = [
359
 
        Option('no-recurse',
360
 
               help="Don't recursively add the contents of directories."),
361
 
        Option('dry-run',
362
 
               help="Show what would be done, but don't actually do anything."),
363
 
        'verbose',
364
 
        Option('file-ids-from',
365
 
               type=unicode,
366
 
               help='Lookup file ids from this tree.'),
367
 
        ]
 
355
    takes_options = ['no-recurse', 'dry-run', 'verbose',
 
356
                     Option('file-ids-from', type=unicode,
 
357
                            help='Lookup file ids from here')]
368
358
    encoding_type = 'replace'
369
359
    _see_also = ['remove']
370
360
 
391
381
        if base_tree:
392
382
            base_tree.lock_read()
393
383
        try:
394
 
            file_list = self._maybe_expand_globs(file_list)
395
 
            if file_list:
396
 
                tree = WorkingTree.open_containing(file_list[0])[0]
397
 
            else:
398
 
                tree = WorkingTree.open_containing(u'.')[0]
399
 
            added, ignored = tree.smart_add(file_list, not
400
 
                no_recurse, action=action, save=not dry_run)
 
384
            added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
 
385
                action=action, save=not dry_run)
401
386
        finally:
402
387
            if base_tree is not None:
403
388
                base_tree.unlock()
460
445
 
461
446
    hidden = True
462
447
    _see_also = ['ls']
463
 
    takes_options = [
464
 
        'revision',
465
 
        'show-ids',
466
 
        Option('kind',
467
 
               help='List entries of a particular kind: file, directory, symlink.',
468
 
               type=unicode),
469
 
        ]
 
448
    takes_options = ['revision', 'show-ids', 'kind']
470
449
    takes_args = ['file*']
471
450
 
472
451
    @display_command
473
452
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
474
453
        if kind and kind not in ['file', 'directory', 'symlink']:
475
 
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
 
454
            raise errors.BzrCommandError('invalid kind specified')
476
455
 
477
456
        work_tree, file_list = tree_files(file_list)
478
457
        work_tree.lock_read()
482
461
                    raise errors.BzrCommandError(
483
462
                        'bzr inventory --revision takes exactly one revision'
484
463
                        ' identifier')
485
 
                revision_id = revision[0].as_revision_id(work_tree.branch)
 
464
                revision_id = revision[0].in_history(work_tree.branch).rev_id
486
465
                tree = work_tree.branch.repository.revision_tree(revision_id)
487
466
 
488
467
                extra_trees = [work_tree]
518
497
class cmd_mv(Command):
519
498
    """Move or rename a file.
520
499
 
521
 
    :Usage:
 
500
    usage:
522
501
        bzr mv OLDNAME NEWNAME
523
 
 
524
502
        bzr mv SOURCE... DESTINATION
525
503
 
526
504
    If the last argument is a versioned directory, all the other names
537
515
    """
538
516
 
539
517
    takes_args = ['names*']
540
 
    takes_options = [Option("after", help="Move only the bzr identifier"
541
 
        " of the file, because the file has already been moved."),
542
 
        ]
 
518
    takes_options = [Option("after", help="move only the bzr identifier"
 
519
        " of the file (file has already been moved). Use this flag if"
 
520
        " bzr is not able to detect this itself.")]
543
521
    aliases = ['move', 'rename']
544
522
    encoding_type = 'replace'
545
523
 
550
528
        if len(names_list) < 2:
551
529
            raise errors.BzrCommandError("missing file argument")
552
530
        tree, rel_names = tree_files(names_list)
553
 
        tree.lock_write()
554
 
        try:
555
 
            self._run(tree, names_list, rel_names, after)
556
 
        finally:
557
 
            tree.unlock()
558
 
 
559
 
    def _run(self, tree, names_list, rel_names, after):
560
 
        into_existing = osutils.isdir(names_list[-1])
561
 
        if into_existing and len(names_list) == 2:
562
 
            # special cases:
563
 
            # a. case-insensitive filesystem and change case of dir
564
 
            # b. move directory after the fact (if the source used to be
565
 
            #    a directory, but now doesn't exist in the working tree
566
 
            #    and the target is an existing directory, just rename it)
567
 
            if (not tree.case_sensitive
568
 
                and rel_names[0].lower() == rel_names[1].lower()):
569
 
                into_existing = False
570
 
            else:
571
 
                inv = tree.inventory
572
 
                from_id = tree.path2id(rel_names[0])
573
 
                if (not osutils.lexists(names_list[0]) and
574
 
                    from_id and inv.get_file_kind(from_id) == "directory"):
575
 
                    into_existing = False
576
 
        # move/rename
577
 
        if into_existing:
 
531
        
 
532
        if os.path.isdir(names_list[-1]):
578
533
            # move into existing directory
579
534
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
580
535
                self.outf.write("%s => %s\n" % pair)
585
540
                                             ' directory')
586
541
            tree.rename_one(rel_names[0], rel_names[1], after=after)
587
542
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
588
 
 
589
 
 
 
543
            
 
544
    
590
545
class cmd_pull(Command):
591
546
    """Turn this branch into a mirror of another branch.
592
547
 
605
560
    that, you can omit the location to use the default.  To change the
606
561
    default, use --remember. The value will only be saved if the remote
607
562
    location can be accessed.
608
 
 
609
 
    Note: The location can be specified either in the form of a branch,
610
 
    or in the form of a path to a file containing a merge directive generated
611
 
    with bzr send.
612
563
    """
613
564
 
614
 
    _see_also = ['push', 'update', 'status-flags']
615
 
    takes_options = ['remember', 'overwrite', 'revision',
616
 
        custom_help('verbose',
617
 
            help='Show logs of pulled revisions.'),
 
565
    _see_also = ['push', 'update']
 
566
    takes_options = ['remember', 'overwrite', 'revision', 'verbose',
618
567
        Option('directory',
619
 
            help='Branch to pull into, '
620
 
                 'rather than the one containing the working directory.',
 
568
            help='branch to pull into, '
 
569
                 'rather than the one containing the working directory',
621
570
            short_name='d',
622
571
            type=unicode,
623
572
            ),
628
577
    def run(self, location=None, remember=False, overwrite=False,
629
578
            revision=None, verbose=False,
630
579
            directory=None):
 
580
        from bzrlib.tag import _merge_tags_if_possible
631
581
        # FIXME: too much stuff is in the command class
632
582
        revision_id = None
633
583
        mergeable = None
640
590
            tree_to = None
641
591
            branch_to = Branch.open_containing(directory)[0]
642
592
 
643
 
        possible_transports = []
 
593
        reader = None
644
594
        if location is not None:
645
595
            try:
646
 
                mergeable = bundle.read_mergeable_from_url(location,
647
 
                    possible_transports=possible_transports)
 
596
                mergeable = bundle.read_mergeable_from_url(
 
597
                    location)
648
598
            except errors.NotABundle:
649
 
                mergeable = None
 
599
                pass # Continue on considering this url a Branch
650
600
 
651
601
        stored_loc = branch_to.get_parent()
652
602
        if location is None:
656
606
            else:
657
607
                display_url = urlutils.unescape_for_display(stored_loc,
658
608
                        self.outf.encoding)
659
 
                if not is_quiet():
660
 
                    self.outf.write("Using saved parent location: %s\n" % display_url)
 
609
                self.outf.write("Using saved location: %s\n" % display_url)
661
610
                location = stored_loc
662
611
 
663
612
        if mergeable is not None:
664
613
            if revision is not None:
665
614
                raise errors.BzrCommandError(
666
615
                    'Cannot use -r with merge directives or bundles')
667
 
            mergeable.install_revisions(branch_to.repository)
668
 
            base_revision_id, revision_id, verified = \
669
 
                mergeable.get_merge_request(branch_to.repository)
 
616
            revision_id = mergeable.install_revisions(branch_to.repository)
670
617
            branch_from = branch_to
671
618
        else:
672
 
            branch_from = Branch.open(location,
673
 
                possible_transports=possible_transports)
 
619
            branch_from = Branch.open(location)
674
620
 
675
621
            if branch_to.get_parent() is None or remember:
676
622
                branch_to.set_parent(branch_from.base)
677
623
 
678
624
        if revision is not None:
679
625
            if len(revision) == 1:
680
 
                revision_id = revision[0].as_revision_id(branch_from)
 
626
                revision_id = revision[0].in_history(branch_from).rev_id
681
627
            else:
682
628
                raise errors.BzrCommandError(
683
629
                    'bzr pull --revision takes one value.')
684
630
 
685
 
        branch_to.lock_write()
686
 
        try:
687
 
            if tree_to is not None:
688
 
                change_reporter = delta._ChangeReporter(
689
 
                    unversioned_filter=tree_to.is_ignored)
690
 
                result = tree_to.pull(branch_from, overwrite, revision_id,
691
 
                                      change_reporter,
692
 
                                      possible_transports=possible_transports)
693
 
            else:
694
 
                result = branch_to.pull(branch_from, overwrite, revision_id)
 
631
        old_rh = branch_to.revision_history()
 
632
        if tree_to is not None:
 
633
            result = tree_to.pull(branch_from, overwrite, revision_id,
 
634
                delta._ChangeReporter(unversioned_filter=tree_to.is_ignored))
 
635
        else:
 
636
            result = branch_to.pull(branch_from, overwrite, revision_id)
695
637
 
696
 
            result.report(self.outf)
697
 
            if verbose and result.old_revid != result.new_revid:
698
 
                old_rh = list(
699
 
                    branch_to.repository.iter_reverse_revision_history(
700
 
                    result.old_revid))
701
 
                old_rh.reverse()
702
 
                new_rh = branch_to.revision_history()
703
 
                log.show_changed_revisions(branch_to, old_rh, new_rh,
704
 
                                           to_file=self.outf)
705
 
        finally:
706
 
            branch_to.unlock()
 
638
        result.report(self.outf)
 
639
        if verbose:
 
640
            from bzrlib.log import show_changed_revisions
 
641
            new_rh = branch_to.revision_history()
 
642
            show_changed_revisions(branch_to, old_rh, new_rh,
 
643
                                   to_file=self.outf)
707
644
 
708
645
 
709
646
class cmd_push(Command):
732
669
    location can be accessed.
733
670
    """
734
671
 
735
 
    _see_also = ['pull', 'update', 'working-trees']
736
 
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
 
672
    _see_also = ['pull', 'update']
 
673
    takes_options = ['remember', 'overwrite', 'verbose',
737
674
        Option('create-prefix',
738
675
               help='Create the path leading up to the branch '
739
 
                    'if it does not already exist.'),
 
676
                    'if it does not already exist'),
740
677
        Option('directory',
741
 
            help='Branch to push from, '
742
 
                 'rather than the one containing the working directory.',
 
678
            help='branch to push from, '
 
679
                 'rather than the one containing the working directory',
743
680
            short_name='d',
744
681
            type=unicode,
745
682
            ),
746
683
        Option('use-existing-dir',
747
684
               help='By default push will fail if the target'
748
685
                    ' directory exists, but does not already'
749
 
                    ' have a control directory.  This flag will'
 
686
                    ' have a control directory. This flag will'
750
687
                    ' allow push to proceed.'),
751
 
        Option('stacked',
752
 
            help='Create a stacked branch that references the public location '
753
 
                'of the parent branch.'),
754
 
        Option('stacked-on',
755
 
            help='Create a stacked branch that refers to another branch '
756
 
                'for the commit history. Only the work not present in the '
757
 
                'referenced branch is included in the branch created.',
758
 
            type=unicode),
759
688
        ]
760
689
    takes_args = ['location?']
761
690
    encoding_type = 'replace'
762
691
 
763
692
    def run(self, location=None, remember=False, overwrite=False,
764
 
        create_prefix=False, verbose=False, revision=None,
765
 
        use_existing_dir=False, directory=None, stacked_on=None,
766
 
        stacked=False):
767
 
        from bzrlib.push import _show_push_branch
768
 
 
769
 
        # Get the source branch and revision_id
 
693
            create_prefix=False, verbose=False,
 
694
            use_existing_dir=False,
 
695
            directory=None):
 
696
        # FIXME: Way too big!  Put this into a function called from the
 
697
        # command.
770
698
        if directory is None:
771
699
            directory = '.'
772
700
        br_from = Branch.open_containing(directory)[0]
773
 
        if revision is not None:
774
 
            if len(revision) == 1:
775
 
                revision_id = revision[0].in_history(br_from).rev_id
776
 
            else:
777
 
                raise errors.BzrCommandError(
778
 
                    'bzr push --revision takes one value.')
779
 
        else:
780
 
            revision_id = br_from.last_revision()
781
 
 
782
 
        # Get the stacked_on branch, if any
783
 
        if stacked_on is not None:
784
 
            stacked_on = urlutils.normalize_url(stacked_on)
785
 
        elif stacked:
786
 
            parent_url = br_from.get_parent()
787
 
            if parent_url:
788
 
                parent = Branch.open(parent_url)
789
 
                stacked_on = parent.get_public_branch()
790
 
                if not stacked_on:
791
 
                    # I considered excluding non-http url's here, thus forcing
792
 
                    # 'public' branches only, but that only works for some
793
 
                    # users, so it's best to just depend on the user spotting an
794
 
                    # error by the feedback given to them. RBC 20080227.
795
 
                    stacked_on = parent_url
796
 
            if not stacked_on:
797
 
                raise errors.BzrCommandError(
798
 
                    "Could not determine branch to refer to.")
799
 
 
800
 
        # Get the destination location
 
701
        stored_loc = br_from.get_push_location()
801
702
        if location is None:
802
 
            stored_loc = br_from.get_push_location()
803
703
            if stored_loc is None:
804
 
                raise errors.BzrCommandError(
805
 
                    "No push location known or specified.")
 
704
                raise errors.BzrCommandError("No push location known or specified.")
806
705
            else:
807
706
                display_url = urlutils.unescape_for_display(stored_loc,
808
707
                        self.outf.encoding)
809
 
                self.outf.write("Using saved push location: %s\n" % display_url)
 
708
                self.outf.write("Using saved location: %s\n" % display_url)
810
709
                location = stored_loc
811
710
 
812
 
        _show_push_branch(br_from, revision_id, location, self.outf,
813
 
            verbose=verbose, overwrite=overwrite, remember=remember,
814
 
            stacked_on=stacked_on, create_prefix=create_prefix,
815
 
            use_existing_dir=use_existing_dir)
 
711
        to_transport = transport.get_transport(location)
 
712
        location_url = to_transport.base
 
713
 
 
714
        br_to = repository_to = dir_to = None
 
715
        try:
 
716
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
 
717
        except errors.NotBranchError:
 
718
            pass # Didn't find anything
 
719
        else:
 
720
            # If we can open a branch, use its direct repository, otherwise see
 
721
            # if there is a repository without a branch.
 
722
            try:
 
723
                br_to = dir_to.open_branch()
 
724
            except errors.NotBranchError:
 
725
                # Didn't find a branch, can we find a repository?
 
726
                try:
 
727
                    repository_to = dir_to.find_repository()
 
728
                except errors.NoRepositoryPresent:
 
729
                    pass
 
730
            else:
 
731
                # Found a branch, so we must have found a repository
 
732
                repository_to = br_to.repository
 
733
        push_result = None
 
734
        old_rh = []
 
735
        if dir_to is None:
 
736
            # The destination doesn't exist; create it.
 
737
            # XXX: Refactor the create_prefix/no_create_prefix code into a
 
738
            #      common helper function
 
739
            try:
 
740
                to_transport.mkdir('.')
 
741
            except errors.FileExists:
 
742
                if not use_existing_dir:
 
743
                    raise errors.BzrCommandError("Target directory %s"
 
744
                         " already exists, but does not have a valid .bzr"
 
745
                         " directory. Supply --use-existing-dir to push"
 
746
                         " there anyway." % location)
 
747
            except errors.NoSuchFile:
 
748
                if not create_prefix:
 
749
                    raise errors.BzrCommandError("Parent directory of %s"
 
750
                        " does not exist."
 
751
                        "\nYou may supply --create-prefix to create all"
 
752
                        " leading parent directories."
 
753
                        % location)
 
754
 
 
755
                cur_transport = to_transport
 
756
                needed = [cur_transport]
 
757
                # Recurse upwards until we can create a directory successfully
 
758
                while True:
 
759
                    new_transport = cur_transport.clone('..')
 
760
                    if new_transport.base == cur_transport.base:
 
761
                        raise errors.BzrCommandError("Failed to create path"
 
762
                                                     " prefix for %s."
 
763
                                                     % location)
 
764
                    try:
 
765
                        new_transport.mkdir('.')
 
766
                    except errors.NoSuchFile:
 
767
                        needed.append(new_transport)
 
768
                        cur_transport = new_transport
 
769
                    else:
 
770
                        break
 
771
 
 
772
                # Now we only need to create child directories
 
773
                while needed:
 
774
                    cur_transport = needed.pop()
 
775
                    cur_transport.mkdir('.')
 
776
            
 
777
            # Now the target directory exists, but doesn't have a .bzr
 
778
            # directory. So we need to create it, along with any work to create
 
779
            # all of the dependent branches, etc.
 
780
            dir_to = br_from.bzrdir.clone(location_url,
 
781
                revision_id=br_from.last_revision())
 
782
            br_to = dir_to.open_branch()
 
783
            # TODO: Some more useful message about what was copied
 
784
            note('Created new branch.')
 
785
            # We successfully created the target, remember it
 
786
            if br_from.get_push_location() is None or remember:
 
787
                br_from.set_push_location(br_to.base)
 
788
        elif repository_to is None:
 
789
            # we have a bzrdir but no branch or repository
 
790
            # XXX: Figure out what to do other than complain.
 
791
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
 
792
                " directory, but not a branch or repository. This is an"
 
793
                " unsupported configuration. Please move the target directory"
 
794
                " out of the way and try again."
 
795
                % location)
 
796
        elif br_to is None:
 
797
            # We have a repository but no branch, copy the revisions, and then
 
798
            # create a branch.
 
799
            last_revision_id = br_from.last_revision()
 
800
            repository_to.fetch(br_from.repository,
 
801
                                revision_id=last_revision_id)
 
802
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
 
803
            note('Created new branch.')
 
804
            if br_from.get_push_location() is None or remember:
 
805
                br_from.set_push_location(br_to.base)
 
806
        else: # We have a valid to branch
 
807
            # We were able to connect to the remote location, so remember it
 
808
            # we don't need to successfully push because of possible divergence.
 
809
            if br_from.get_push_location() is None or remember:
 
810
                br_from.set_push_location(br_to.base)
 
811
            old_rh = br_to.revision_history()
 
812
            try:
 
813
                try:
 
814
                    tree_to = dir_to.open_workingtree()
 
815
                except errors.NotLocalUrl:
 
816
                    warning('This transport does not update the working '
 
817
                            'tree of: %s' % (br_to.base,))
 
818
                    push_result = br_from.push(br_to, overwrite)
 
819
                except errors.NoWorkingTree:
 
820
                    push_result = br_from.push(br_to, overwrite)
 
821
                else:
 
822
                    tree_to.lock_write()
 
823
                    try:
 
824
                        push_result = br_from.push(tree_to.branch, overwrite)
 
825
                        tree_to.update()
 
826
                    finally:
 
827
                        tree_to.unlock()
 
828
            except errors.DivergedBranches:
 
829
                raise errors.BzrCommandError('These branches have diverged.'
 
830
                                        '  Try using "merge" and then "push".')
 
831
        if push_result is not None:
 
832
            push_result.report(self.outf)
 
833
        elif verbose:
 
834
            new_rh = br_to.revision_history()
 
835
            if old_rh != new_rh:
 
836
                # Something changed
 
837
                from bzrlib.log import show_changed_revisions
 
838
                show_changed_revisions(br_to, old_rh, new_rh,
 
839
                                       to_file=self.outf)
 
840
        else:
 
841
            # we probably did a clone rather than a push, so a message was
 
842
            # emitted above
 
843
            pass
816
844
 
817
845
 
818
846
class cmd_branch(Command):
820
848
 
821
849
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
822
850
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
823
 
    If the FROM_LOCATION has no / or path separator embedded, the TO_LOCATION
824
 
    is derived from the FROM_LOCATION by stripping a leading scheme or drive
825
 
    identifier, if any. For example, "branch lp:foo-bar" will attempt to
826
 
    create ./foo-bar.
827
851
 
828
852
    To retrieve the branch as of a particular revision, supply the --revision
829
853
    parameter, as in "branch foo/bar -r 5".
831
855
 
832
856
    _see_also = ['checkout']
833
857
    takes_args = ['from_location', 'to_location?']
834
 
    takes_options = ['revision', Option('hardlink',
835
 
        help='Hard-link working tree files where possible.'),
836
 
        Option('stacked',
837
 
            help='Create a stacked branch referring to the source branch. '
838
 
                'The new branch will depend on the availability of the source '
839
 
                'branch for all operations.'),
840
 
        ]
 
858
    takes_options = ['revision']
841
859
    aliases = ['get', 'clone']
842
860
 
843
 
    def run(self, from_location, to_location=None, revision=None,
844
 
            hardlink=False, stacked=False):
 
861
    def run(self, from_location, to_location=None, revision=None):
845
862
        from bzrlib.tag import _merge_tags_if_possible
846
863
        if revision is None:
847
864
            revision = [None]
849
866
            raise errors.BzrCommandError(
850
867
                'bzr branch --revision takes exactly 1 revision value')
851
868
 
852
 
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
853
 
            from_location)
 
869
        br_from = Branch.open(from_location)
854
870
        br_from.lock_read()
855
871
        try:
856
872
            if len(revision) == 1 and revision[0] is not None:
857
 
                revision_id = revision[0].as_revision_id(br_from)
 
873
                revision_id = revision[0].in_history(br_from)[1]
858
874
            else:
859
875
                # FIXME - wt.last_revision, fallback to branch, fall back to
860
876
                # None or perhaps NULL_REVISION to mean copy nothing
861
877
                # RBC 20060209
862
878
                revision_id = br_from.last_revision()
863
879
            if to_location is None:
864
 
                to_location = urlutils.derive_to_location(from_location)
 
880
                to_location = os.path.basename(from_location.rstrip("/\\"))
 
881
                name = None
 
882
            else:
 
883
                name = os.path.basename(to_location) + '\n'
 
884
 
865
885
            to_transport = transport.get_transport(to_location)
866
886
            try:
867
887
                to_transport.mkdir('.')
873
893
                                             % to_location)
874
894
            try:
875
895
                # preserve whatever source format we have.
876
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
877
 
                                            possible_transports=[to_transport],
878
 
                                            accelerator_tree=accelerator_tree,
879
 
                                            hardlink=hardlink, stacked=stacked)
 
896
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id)
880
897
                branch = dir.open_branch()
881
898
            except errors.NoSuchRevision:
882
899
                to_transport.delete_tree('.')
883
 
                msg = "The branch %s has no revision %s." % (from_location,
884
 
                    revision[0])
 
900
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
885
901
                raise errors.BzrCommandError(msg)
 
902
            if name:
 
903
                branch.control_files.put_utf8('branch-name', name)
886
904
            _merge_tags_if_possible(br_from, branch)
887
 
            # If the source branch is stacked, the new branch may
888
 
            # be stacked whether we asked for that explicitly or not.
889
 
            # We therefore need a try/except here and not just 'if stacked:'
890
 
            try:
891
 
                note('Created new stacked branch referring to %s.' %
892
 
                    branch.get_stacked_on_url())
893
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
894
 
                errors.UnstackableRepositoryFormat), e:
895
 
                note('Branched %d revision(s).' % branch.revno())
 
905
            note('Branched %d revision(s).' % branch.revno())
896
906
        finally:
897
907
            br_from.unlock()
898
908
 
907
917
    
908
918
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
909
919
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
910
 
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
911
 
    is derived from the BRANCH_LOCATION by stripping a leading scheme or drive
912
 
    identifier, if any. For example, "checkout lp:foo-bar" will attempt to
913
 
    create ./foo-bar.
914
920
 
915
921
    To retrieve the branch as of a particular revision, supply the --revision
916
922
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
922
928
    takes_args = ['branch_location?', 'to_location?']
923
929
    takes_options = ['revision',
924
930
                     Option('lightweight',
925
 
                            help="Perform a lightweight checkout.  Lightweight "
 
931
                            help="perform a lightweight checkout. Lightweight "
926
932
                                 "checkouts depend on access to the branch for "
927
 
                                 "every operation.  Normal checkouts can perform "
 
933
                                 "every operation. Normal checkouts can perform "
928
934
                                 "common operations like diff and status without "
929
935
                                 "such access, and also support local commits."
930
936
                            ),
931
 
                     Option('files-from', type=str,
932
 
                            help="Get file contents from this tree."),
933
 
                     Option('hardlink',
934
 
                            help='Hard-link working tree files where possible.'
935
 
                            ),
936
937
                     ]
937
938
    aliases = ['co']
938
939
 
939
940
    def run(self, branch_location=None, to_location=None, revision=None,
940
 
            lightweight=False, files_from=None, hardlink=False):
 
941
            lightweight=False):
941
942
        if revision is None:
942
943
            revision = [None]
943
944
        elif len(revision) > 1:
946
947
        if branch_location is None:
947
948
            branch_location = osutils.getcwd()
948
949
            to_location = branch_location
949
 
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
950
 
            branch_location)
951
 
        if files_from is not None:
952
 
            accelerator_tree = WorkingTree.open(files_from)
 
950
        source = Branch.open(branch_location)
953
951
        if len(revision) == 1 and revision[0] is not None:
954
 
            revision_id = revision[0].as_revision_id(source)
 
952
            revision_id = revision[0].in_history(source)[1]
955
953
        else:
956
954
            revision_id = None
957
955
        if to_location is None:
958
 
            to_location = urlutils.derive_to_location(branch_location)
 
956
            to_location = os.path.basename(branch_location.rstrip("/\\"))
959
957
        # if the source and to_location are the same, 
960
958
        # and there is no working tree,
961
959
        # then reconstitute a branch
964
962
            try:
965
963
                source.bzrdir.open_workingtree()
966
964
            except errors.NoWorkingTree:
967
 
                source.bzrdir.create_workingtree(revision_id)
 
965
                source.bzrdir.create_workingtree()
968
966
                return
969
 
        source.create_checkout(to_location, revision_id, lightweight,
970
 
                               accelerator_tree, hardlink)
 
967
        try:
 
968
            os.mkdir(to_location)
 
969
        except OSError, e:
 
970
            if e.errno == errno.EEXIST:
 
971
                raise errors.BzrCommandError('Target directory "%s" already'
 
972
                                             ' exists.' % to_location)
 
973
            if e.errno == errno.ENOENT:
 
974
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
975
                                             % to_location)
 
976
            else:
 
977
                raise
 
978
        source.create_checkout(to_location, revision_id, lightweight)
971
979
 
972
980
 
973
981
class cmd_renames(Command):
1010
1018
    'bzr revert' instead of 'bzr commit' after the update.
1011
1019
    """
1012
1020
 
1013
 
    _see_also = ['pull', 'working-trees', 'status-flags']
 
1021
    _see_also = ['pull']
1014
1022
    takes_args = ['dir?']
1015
1023
    aliases = ['up']
1016
1024
 
1017
1025
    def run(self, dir='.'):
1018
1026
        tree = WorkingTree.open_containing(dir)[0]
1019
 
        possible_transports = []
1020
 
        master = tree.branch.get_master_branch(
1021
 
            possible_transports=possible_transports)
 
1027
        master = tree.branch.get_master_branch()
1022
1028
        if master is not None:
1023
1029
            tree.lock_write()
1024
1030
        else:
1025
1031
            tree.lock_tree_write()
1026
1032
        try:
1027
1033
            existing_pending_merges = tree.get_parent_ids()[1:]
1028
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1029
 
            if last_rev == _mod_revision.ensure_null(
1030
 
                tree.branch.last_revision()):
 
1034
            last_rev = tree.last_revision()
 
1035
            if last_rev == tree.branch.last_revision():
1031
1036
                # may be up to date, check master too.
1032
 
                if master is None or last_rev == _mod_revision.ensure_null(
1033
 
                    master.last_revision()):
 
1037
                master = tree.branch.get_master_branch()
 
1038
                if master is None or last_rev == master.last_revision():
1034
1039
                    revno = tree.branch.revision_id_to_revno(last_rev)
1035
1040
                    note("Tree is up to date at revision %d." % (revno,))
1036
1041
                    return 0
1037
 
            conflicts = tree.update(
1038
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored),
1039
 
                possible_transports=possible_transports)
1040
 
            revno = tree.branch.revision_id_to_revno(
1041
 
                _mod_revision.ensure_null(tree.last_revision()))
 
1042
            conflicts = tree.update()
 
1043
            revno = tree.branch.revision_id_to_revno(tree.last_revision())
1042
1044
            note('Updated to revision %d.' % (revno,))
1043
1045
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1044
1046
                note('Your local commits will now show as pending merges with '
1060
1062
 
1061
1063
    Branches and working trees will also report any missing revisions.
1062
1064
    """
1063
 
    _see_also = ['revno', 'working-trees', 'repositories']
 
1065
    _see_also = ['revno']
1064
1066
    takes_args = ['location?']
1065
1067
    takes_options = ['verbose']
1066
 
    encoding_type = 'replace'
1067
1068
 
1068
1069
    @display_command
1069
1070
    def run(self, location=None, verbose=False):
1070
 
        if verbose:
1071
 
            noise_level = 2
1072
 
        else:
1073
 
            noise_level = 0
1074
1071
        from bzrlib.info import show_bzrdir_info
1075
1072
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1076
 
                         verbose=noise_level, outfile=self.outf)
 
1073
                         verbose=verbose)
1077
1074
 
1078
1075
 
1079
1076
class cmd_remove(Command):
1080
1077
    """Remove files or directories.
1081
1078
 
1082
 
    This makes bzr stop tracking changes to the specified files. bzr will delete
1083
 
    them if they can easily be recovered using revert. If no options or
1084
 
    parameters are given bzr will scan for files that are being tracked by bzr
1085
 
    but missing in your tree and stop tracking them for you.
 
1079
    This makes bzr stop tracking changes to the specified files and
 
1080
    delete them if they can easily be recovered using revert.
 
1081
 
 
1082
    You can specify one or more files, and/or --new.  If you specify --new,
 
1083
    only 'added' files will be removed.  If you specify both, then new files
 
1084
    in the specified directories will be removed.  If the directories are
 
1085
    also new, they will also be removed.
1086
1086
    """
1087
1087
    takes_args = ['file*']
1088
1088
    takes_options = ['verbose',
1089
 
        Option('new', help='Only remove files that have never been committed.'),
 
1089
        Option('new', help='remove newly-added files'),
1090
1090
        RegistryOption.from_kwargs('file-deletion-strategy',
1091
 
            'The file deletion mode to be used.',
 
1091
            'The file deletion mode to be used',
1092
1092
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1093
1093
            safe='Only delete files if they can be'
1094
1094
                 ' safely recovered (default).',
1095
1095
            keep="Don't delete any files.",
1096
1096
            force='Delete all the specified files, even if they can not be '
1097
1097
                'recovered and even if they are non-empty directories.')]
1098
 
    aliases = ['rm', 'del']
 
1098
    aliases = ['rm']
1099
1099
    encoding_type = 'replace'
1100
1100
 
1101
1101
    def run(self, file_list, verbose=False, new=False,
1103
1103
        tree, file_list = tree_files(file_list)
1104
1104
 
1105
1105
        if file_list is not None:
1106
 
            file_list = [f for f in file_list]
 
1106
            file_list = [f for f in file_list if f != '']
 
1107
        elif not new:
 
1108
            raise errors.BzrCommandError('Specify one or more files to'
 
1109
            ' remove, or use --new.')
1107
1110
 
1108
 
        tree.lock_write()
1109
 
        try:
1110
 
            # Heuristics should probably all move into tree.remove_smart or
1111
 
            # some such?
1112
 
            if new:
1113
 
                added = tree.changes_from(tree.basis_tree(),
1114
 
                    specific_files=file_list).added
1115
 
                file_list = sorted([f[0] for f in added], reverse=True)
1116
 
                if len(file_list) == 0:
1117
 
                    raise errors.BzrCommandError('No matching files.')
1118
 
            elif file_list is None:
1119
 
                # missing files show up in iter_changes(basis) as
1120
 
                # versioned-with-no-kind.
1121
 
                missing = []
1122
 
                for change in tree.iter_changes(tree.basis_tree()):
1123
 
                    # Find paths in the working tree that have no kind:
1124
 
                    if change[1][1] is not None and change[6][1] is None:
1125
 
                        missing.append(change[1][1])
1126
 
                file_list = sorted(missing, reverse=True)
1127
 
                file_deletion_strategy = 'keep'
1128
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1129
 
                keep_files=file_deletion_strategy=='keep',
1130
 
                force=file_deletion_strategy=='force')
1131
 
        finally:
1132
 
            tree.unlock()
 
1111
        if new:
 
1112
            added = tree.changes_from(tree.basis_tree(),
 
1113
                specific_files=file_list).added
 
1114
            file_list = sorted([f[0] for f in added], reverse=True)
 
1115
            if len(file_list) == 0:
 
1116
                raise errors.BzrCommandError('No matching files.')
 
1117
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1118
            keep_files=file_deletion_strategy=='keep',
 
1119
            force=file_deletion_strategy=='force')
1133
1120
 
1134
1121
 
1135
1122
class cmd_file_id(Command):
1240
1227
            last_revision = wt.last_revision()
1241
1228
 
1242
1229
        revision_ids = b.repository.get_ancestry(last_revision)
 
1230
        assert revision_ids[0] is None
1243
1231
        revision_ids.pop(0)
1244
1232
        for revision_id in revision_ids:
1245
1233
            self.outf.write(revision_id + '\n')
1259
1247
    If there is already a branch at the location but it has no working tree,
1260
1248
    the tree can be populated with 'bzr checkout'.
1261
1249
 
1262
 
    Recipe for importing a tree of files::
1263
 
 
 
1250
    Recipe for importing a tree of files:
1264
1251
        cd ~/project
1265
1252
        bzr init
1266
1253
        bzr add .
1267
1254
        bzr status
1268
 
        bzr commit -m "imported project"
 
1255
        bzr commit -m 'imported project'
1269
1256
    """
1270
1257
 
1271
 
    _see_also = ['init-repository', 'branch', 'checkout']
 
1258
    _see_also = ['init-repo', 'branch', 'checkout']
1272
1259
    takes_args = ['location?']
1273
1260
    takes_options = [
1274
 
        Option('create-prefix',
1275
 
               help='Create the path leading up to the branch '
1276
 
                    'if it does not already exist.'),
1277
1261
         RegistryOption('format',
1278
1262
                help='Specify a format for this branch. '
1279
1263
                'See "help formats".',
1286
1270
                help='Never change revnos or the existing log.'
1287
1271
                '  Append revisions to it only.')
1288
1272
         ]
1289
 
    def run(self, location=None, format=None, append_revisions_only=False,
1290
 
            create_prefix=False):
 
1273
    def run(self, location=None, format=None, append_revisions_only=False):
1291
1274
        if format is None:
1292
1275
            format = bzrdir.format_registry.make_bzrdir('default')
1293
1276
        if location is None:
1300
1283
        # Just using os.mkdir, since I don't
1301
1284
        # believe that we want to create a bunch of
1302
1285
        # locations if the user supplies an extended path
1303
 
        try:
1304
 
            to_transport.ensure_base()
1305
 
        except errors.NoSuchFile:
1306
 
            if not create_prefix:
1307
 
                raise errors.BzrCommandError("Parent directory of %s"
1308
 
                    " does not exist."
1309
 
                    "\nYou may supply --create-prefix to create all"
1310
 
                    " leading parent directories."
1311
 
                    % location)
1312
 
            _create_prefix(to_transport)
1313
 
 
1314
 
        try:
1315
 
            existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
 
1286
        # TODO: create-prefix
 
1287
        try:
 
1288
            to_transport.mkdir('.')
 
1289
        except errors.FileExists:
 
1290
            pass
 
1291
                    
 
1292
        try:
 
1293
            existing_bzrdir = bzrdir.BzrDir.open(location)
1316
1294
        except errors.NotBranchError:
1317
1295
            # really a NotBzrDir error...
1318
 
            create_branch = bzrdir.BzrDir.create_branch_convenience
1319
 
            branch = create_branch(to_transport.base, format=format,
1320
 
                                   possible_transports=[to_transport])
 
1296
            branch = bzrdir.BzrDir.create_branch_convenience(to_transport.base,
 
1297
                                                             format=format)
1321
1298
        else:
1322
1299
            from bzrlib.transport.local import LocalTransport
1323
1300
            if existing_bzrdir.has_branch():
1334
1311
            except errors.UpgradeRequired:
1335
1312
                raise errors.BzrCommandError('This branch format cannot be set'
1336
1313
                    ' to append-revisions-only.  Try --experimental-branch6')
1337
 
        if not is_quiet():
1338
 
            from bzrlib.info import show_bzrdir_info
1339
 
            show_bzrdir_info(bzrdir.BzrDir.open_containing_from_transport(
1340
 
                to_transport)[0], verbose=0, outfile=self.outf)
1341
1314
 
1342
1315
 
1343
1316
class cmd_init_repository(Command):
1344
1317
    """Create a shared repository to hold branches.
1345
1318
 
1346
 
    New branches created under the repository directory will store their
1347
 
    revisions in the repository, not in the branch directory.
1348
 
 
1349
 
    If the --no-trees option is used then the branches in the repository
1350
 
    will not have working trees by default.
1351
 
 
1352
 
    :Examples:
1353
 
        Create a shared repositories holding just branches::
1354
 
 
1355
 
            bzr init-repo --no-trees repo
1356
 
            bzr init repo/trunk
1357
 
 
1358
 
        Make a lightweight checkout elsewhere::
1359
 
 
1360
 
            bzr checkout --lightweight repo/trunk trunk-checkout
1361
 
            cd trunk-checkout
1362
 
            (add files here)
 
1319
    New branches created under the repository directory will store their revisions
 
1320
    in the repository, not in the branch directory.
 
1321
 
 
1322
    example:
 
1323
        bzr init-repo --no-trees repo
 
1324
        bzr init repo/trunk
 
1325
        bzr checkout --lightweight repo/trunk trunk-checkout
 
1326
        cd trunk-checkout
 
1327
        (add files here)
1363
1328
    """
1364
1329
 
1365
 
    _see_also = ['init', 'branch', 'checkout', 'repositories']
 
1330
    _see_also = ['init', 'branch', 'checkout']
1366
1331
    takes_args = ["location"]
1367
1332
    takes_options = [RegistryOption('format',
1368
1333
                            help='Specify a format for this repository. See'
1369
 
                                 ' "bzr help formats" for details.',
 
1334
                                 ' "bzr help formats" for details',
1370
1335
                            registry=bzrdir.format_registry,
1371
1336
                            converter=bzrdir.format_registry.make_bzrdir,
1372
1337
                            value_switches=True, title='Repository format'),
1373
1338
                     Option('no-trees',
1374
1339
                             help='Branches in the repository will default to'
1375
 
                                  ' not having a working tree.'),
 
1340
                                  ' not having a working tree'),
1376
1341
                    ]
1377
1342
    aliases = ["init-repo"]
1378
1343
 
1384
1349
            location = '.'
1385
1350
 
1386
1351
        to_transport = transport.get_transport(location)
1387
 
        to_transport.ensure_base()
 
1352
        try:
 
1353
            to_transport.mkdir('.')
 
1354
        except errors.FileExists:
 
1355
            pass
1388
1356
 
1389
1357
        newdir = format.initialize_on_transport(to_transport)
1390
1358
        repo = newdir.create_repository(shared=True)
1391
1359
        repo.set_make_working_trees(not no_trees)
1392
 
        if not is_quiet():
1393
 
            from bzrlib.info import show_bzrdir_info
1394
 
            show_bzrdir_info(bzrdir.BzrDir.open_containing_from_transport(
1395
 
                to_transport)[0], verbose=0, outfile=self.outf)
1396
1360
 
1397
1361
 
1398
1362
class cmd_diff(Command):
1399
 
    """Show differences in the working tree, between revisions or branches.
 
1363
    """Show differences in the working tree or between revisions.
1400
1364
    
1401
 
    If no arguments are given, all changes for the current tree are listed.
1402
 
    If files are given, only the changes in those files are listed.
1403
 
    Remote and multiple branches can be compared by using the --old and
1404
 
    --new options. If not provided, the default for both is derived from
1405
 
    the first argument, if any, or the current tree if no arguments are
1406
 
    given.
 
1365
    If files are listed, only the changes in those files are listed.
 
1366
    Otherwise, all changes for the tree are listed.
1407
1367
 
1408
1368
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1409
1369
    produces patches suitable for "patch -p1".
1410
1370
 
1411
 
    :Exit values:
1412
 
        1 - changed
1413
 
        2 - unrepresentable changes
1414
 
        3 - error
1415
 
        0 - no change
1416
 
 
1417
 
    :Examples:
1418
 
        Shows the difference in the working tree versus the last commit::
1419
 
 
1420
 
            bzr diff
1421
 
 
1422
 
        Difference between the working tree and revision 1::
1423
 
 
1424
 
            bzr diff -r1
1425
 
 
1426
 
        Difference between revision 2 and revision 1::
1427
 
 
1428
 
            bzr diff -r1..2
1429
 
 
1430
 
        Difference between revision 2 and revision 1 for branch xxx::
1431
 
 
1432
 
            bzr diff -r1..2 xxx
1433
 
 
1434
 
        Show just the differences for file NEWS::
1435
 
 
1436
 
            bzr diff NEWS
1437
 
 
1438
 
        Show the differences in working tree xxx for file NEWS::
1439
 
 
1440
 
            bzr diff xxx/NEWS
1441
 
 
1442
 
        Show the differences from branch xxx to this working tree:
1443
 
 
1444
 
            bzr diff --old xxx
1445
 
 
1446
 
        Show the differences between two branches for file NEWS::
1447
 
 
1448
 
            bzr diff --old xxx --new yyy NEWS
1449
 
 
1450
 
        Same as 'bzr diff' but prefix paths with old/ and new/::
1451
 
 
1452
 
            bzr diff --prefix old/:new/
 
1371
    examples:
 
1372
        bzr diff
 
1373
            Shows the difference in the working tree versus the last commit
 
1374
        bzr diff -r1
 
1375
            Difference between the working tree and revision 1
 
1376
        bzr diff -r1..2
 
1377
            Difference between revision 2 and revision 1
 
1378
        bzr diff --prefix old/:new/
 
1379
            Same as 'bzr diff' but prefix paths with old/ and new/
 
1380
        bzr diff bzr.mine bzr.dev
 
1381
            Show the differences between the two working trees
 
1382
        bzr diff foo.c
 
1383
            Show just the differences for 'foo.c'
1453
1384
    """
 
1385
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
 
1386
    #       or a graphical diff.
 
1387
 
 
1388
    # TODO: Python difflib is not exactly the same as unidiff; should
 
1389
    #       either fix it up or prefer to use an external diff.
 
1390
 
 
1391
    # TODO: Selected-file diff is inefficient and doesn't show you
 
1392
    #       deleted files.
 
1393
 
 
1394
    # TODO: This probably handles non-Unix newlines poorly.
 
1395
 
1454
1396
    _see_also = ['status']
1455
1397
    takes_args = ['file*']
1456
 
    takes_options = [
1457
 
        Option('diff-options', type=str,
1458
 
               help='Pass these options to the external diff program.'),
 
1398
    takes_options = ['revision', 'diff-options',
1459
1399
        Option('prefix', type=str,
1460
1400
               short_name='p',
1461
 
               help='Set prefixes added to old and new filenames, as '
1462
 
                    'two values separated by a colon. (eg "old/:new/").'),
1463
 
        Option('old',
1464
 
            help='Branch/tree to compare from.',
1465
 
            type=unicode,
1466
 
            ),
1467
 
        Option('new',
1468
 
            help='Branch/tree to compare to.',
1469
 
            type=unicode,
1470
 
            ),
1471
 
        'revision',
1472
 
        'change',
1473
 
        Option('using',
1474
 
            help='Use this command to compare files.',
1475
 
            type=unicode,
1476
 
            ),
 
1401
               help='Set prefixes to added to old and new filenames, as '
 
1402
                    'two values separated by a colon. (eg "old/:new/")'),
1477
1403
        ]
1478
1404
    aliases = ['di', 'dif']
1479
1405
    encoding_type = 'exact'
1480
1406
 
1481
1407
    @display_command
1482
1408
    def run(self, revision=None, file_list=None, diff_options=None,
1483
 
            prefix=None, old=None, new=None, using=None):
1484
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1409
            prefix=None):
 
1410
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
1485
1411
 
1486
1412
        if (prefix is None) or (prefix == '0'):
1487
1413
            # diff -p0 format
1501
1427
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1502
1428
                                         ' one or two revision specifiers')
1503
1429
 
1504
 
        old_tree, new_tree, specific_files, extra_trees = \
1505
 
                _get_trees_to_diff(file_list, revision, old, new)
1506
 
        return show_diff_trees(old_tree, new_tree, sys.stdout, 
1507
 
                               specific_files=specific_files,
1508
 
                               external_diff_options=diff_options,
1509
 
                               old_label=old_label, new_label=new_label,
1510
 
                               extra_trees=extra_trees, using=using)
 
1430
        try:
 
1431
            tree1, file_list = internal_tree_files(file_list)
 
1432
            tree2 = None
 
1433
            b = None
 
1434
            b2 = None
 
1435
        except errors.FileInWrongBranch:
 
1436
            if len(file_list) != 2:
 
1437
                raise errors.BzrCommandError("Files are in different branches")
 
1438
 
 
1439
            tree1, file1 = WorkingTree.open_containing(file_list[0])
 
1440
            tree2, file2 = WorkingTree.open_containing(file_list[1])
 
1441
            if file1 != "" or file2 != "":
 
1442
                # FIXME diff those two files. rbc 20051123
 
1443
                raise errors.BzrCommandError("Files are in different branches")
 
1444
            file_list = None
 
1445
        except errors.NotBranchError:
 
1446
            if (revision is not None and len(revision) == 2
 
1447
                and not revision[0].needs_branch()
 
1448
                and not revision[1].needs_branch()):
 
1449
                # If both revision specs include a branch, we can
 
1450
                # diff them without needing a local working tree
 
1451
                tree1, tree2 = None, None
 
1452
            else:
 
1453
                raise
 
1454
 
 
1455
        if tree2 is not None:
 
1456
            if revision is not None:
 
1457
                # FIXME: but there should be a clean way to diff between
 
1458
                # non-default versions of two trees, it's not hard to do
 
1459
                # internally...
 
1460
                raise errors.BzrCommandError(
 
1461
                        "Sorry, diffing arbitrary revisions across branches "
 
1462
                        "is not implemented yet")
 
1463
            return show_diff_trees(tree1, tree2, sys.stdout, 
 
1464
                                   specific_files=file_list,
 
1465
                                   external_diff_options=diff_options,
 
1466
                                   old_label=old_label, new_label=new_label)
 
1467
 
 
1468
        return diff_cmd_helper(tree1, file_list, diff_options,
 
1469
                               revision_specs=revision,
 
1470
                               old_label=old_label, new_label=new_label)
1511
1471
 
1512
1472
 
1513
1473
class cmd_deleted(Command):
1549
1509
 
1550
1510
    hidden = True
1551
1511
    _see_also = ['status', 'ls']
1552
 
    takes_options = [
1553
 
            Option('null',
1554
 
                   help='Write an ascii NUL (\\0) separator '
1555
 
                   'between files rather than a newline.')
1556
 
            ]
1557
1512
 
1558
1513
    @display_command
1559
 
    def run(self, null=False):
 
1514
    def run(self):
1560
1515
        tree = WorkingTree.open_containing(u'.')[0]
1561
1516
        td = tree.changes_from(tree.basis_tree())
1562
1517
        for path, id, kind, text_modified, meta_modified in td.modified:
1563
 
            if null:
1564
 
                self.outf.write(path + '\0')
1565
 
            else:
1566
 
                self.outf.write(osutils.quotefn(path) + '\n')
 
1518
            self.outf.write(path + '\n')
1567
1519
 
1568
1520
 
1569
1521
class cmd_added(Command):
1572
1524
 
1573
1525
    hidden = True
1574
1526
    _see_also = ['status', 'ls']
1575
 
    takes_options = [
1576
 
            Option('null',
1577
 
                   help='Write an ascii NUL (\\0) separator '
1578
 
                   'between files rather than a newline.')
1579
 
            ]
1580
1527
 
1581
1528
    @display_command
1582
 
    def run(self, null=False):
 
1529
    def run(self):
1583
1530
        wt = WorkingTree.open_containing(u'.')[0]
1584
1531
        wt.lock_read()
1585
1532
        try:
1596
1543
                    path = inv.id2path(file_id)
1597
1544
                    if not os.access(osutils.abspath(path), os.F_OK):
1598
1545
                        continue
1599
 
                    if null:
1600
 
                        self.outf.write(path + '\0')
1601
 
                    else:
1602
 
                        self.outf.write(osutils.quotefn(path) + '\n')
 
1546
                    self.outf.write(path + '\n')
1603
1547
            finally:
1604
1548
                basis.unlock()
1605
1549
        finally:
1620
1564
        self.outf.write(tree.basedir + '\n')
1621
1565
 
1622
1566
 
1623
 
def _parse_limit(limitstring):
1624
 
    try:
1625
 
        return int(limitstring)
1626
 
    except ValueError:
1627
 
        msg = "The limit argument must be an integer."
1628
 
        raise errors.BzrCommandError(msg)
1629
 
 
1630
 
 
1631
1567
class cmd_log(Command):
1632
1568
    """Show log of a branch, file, or directory.
1633
1569
 
1637
1573
    -r revision requests a specific revision, -r ..end or -r begin.. are
1638
1574
    also valid.
1639
1575
 
1640
 
    :Examples:
1641
 
        Log the current branch::
1642
 
 
1643
 
            bzr log
1644
 
 
1645
 
        Log a file::
1646
 
 
1647
 
            bzr log foo.c
1648
 
 
1649
 
        Log the last 10 revisions of a branch::
1650
 
 
1651
 
            bzr log -r -10.. http://server/branch
 
1576
    examples:
 
1577
        bzr log
 
1578
        bzr log foo.c
 
1579
        bzr log -r -10.. http://server/branch
1652
1580
    """
1653
1581
 
1654
1582
    # TODO: Make --revision support uuid: and hash: [future tag:] notation.
1655
1583
 
1656
1584
    takes_args = ['location?']
1657
 
    takes_options = [
1658
 
            Option('forward',
1659
 
                   help='Show from oldest to newest.'),
1660
 
            Option('timezone',
1661
 
                   type=str,
1662
 
                   help='Display timezone as local, original, or utc.'),
1663
 
            custom_help('verbose',
1664
 
                   help='Show files changed in each revision.'),
1665
 
            'show-ids',
1666
 
            'revision',
1667
 
            'log-format',
1668
 
            Option('message',
1669
 
                   short_name='m',
1670
 
                   help='Show revisions whose message matches this '
1671
 
                        'regular expression.',
1672
 
                   type=str),
1673
 
            Option('limit',
1674
 
                   short_name='l',
1675
 
                   help='Limit the output to the first N revisions.',
1676
 
                   argname='N',
1677
 
                   type=_parse_limit),
1678
 
            ]
 
1585
    takes_options = [Option('forward', 
 
1586
                            help='show from oldest to newest'),
 
1587
                     'timezone', 
 
1588
                     Option('verbose', 
 
1589
                             short_name='v',
 
1590
                             help='show files changed in each revision'),
 
1591
                     'show-ids', 'revision',
 
1592
                     'log-format',
 
1593
                     Option('message',
 
1594
                            short_name='m',
 
1595
                            help='show revisions whose message matches this regexp',
 
1596
                            type=str),
 
1597
                     ]
1679
1598
    encoding_type = 'replace'
1680
1599
 
1681
1600
    @display_command
1685
1604
            forward=False,
1686
1605
            revision=None,
1687
1606
            log_format=None,
1688
 
            message=None,
1689
 
            limit=None):
 
1607
            message=None):
1690
1608
        from bzrlib.log import show_log
 
1609
        assert message is None or isinstance(message, basestring), \
 
1610
            "invalid message argument %r" % message
1691
1611
        direction = (forward and 'forward') or 'reverse'
1692
1612
        
1693
1613
        # log everything
1722
1642
                rev1 = None
1723
1643
                rev2 = None
1724
1644
            elif len(revision) == 1:
1725
 
                rev1 = rev2 = revision[0].in_history(b)
 
1645
                rev1 = rev2 = revision[0].in_history(b).revno
1726
1646
            elif len(revision) == 2:
1727
1647
                if revision[1].get_branch() != revision[0].get_branch():
1728
1648
                    # b is taken from revision[0].get_branch(), and
1731
1651
                    raise errors.BzrCommandError(
1732
1652
                        "Log doesn't accept two revisions in different"
1733
1653
                        " branches.")
1734
 
                rev1 = revision[0].in_history(b)
1735
 
                rev2 = revision[1].in_history(b)
 
1654
                if revision[0].spec is None:
 
1655
                    # missing begin-range means first revision
 
1656
                    rev1 = 1
 
1657
                else:
 
1658
                    rev1 = revision[0].in_history(b).revno
 
1659
 
 
1660
                if revision[1].spec is None:
 
1661
                    # missing end-range means last known revision
 
1662
                    rev2 = b.revno()
 
1663
                else:
 
1664
                    rev2 = revision[1].in_history(b).revno
1736
1665
            else:
1737
1666
                raise errors.BzrCommandError(
1738
1667
                    'bzr log --revision takes one or two values.')
1739
1668
 
 
1669
            # By this point, the revision numbers are converted to the +ve
 
1670
            # form if they were supplied in the -ve form, so we can do
 
1671
            # this comparison in relative safety
 
1672
            if rev1 > rev2:
 
1673
                (rev2, rev1) = (rev1, rev2)
 
1674
 
1740
1675
            if log_format is None:
1741
1676
                log_format = log.log_formatter_registry.get_default(b)
1742
1677
 
1750
1685
                     direction=direction,
1751
1686
                     start_revision=rev1,
1752
1687
                     end_revision=rev2,
1753
 
                     search=message,
1754
 
                     limit=limit)
 
1688
                     search=message)
1755
1689
        finally:
1756
1690
            b.unlock()
1757
1691
 
1792
1726
    _see_also = ['status', 'cat']
1793
1727
    takes_args = ['path?']
1794
1728
    # TODO: Take a revision or remote path and list that tree instead.
1795
 
    takes_options = [
1796
 
            'verbose',
1797
 
            'revision',
1798
 
            Option('non-recursive',
1799
 
                   help='Don\'t recurse into subdirectories.'),
1800
 
            Option('from-root',
1801
 
                   help='Print paths relative to the root of the branch.'),
1802
 
            Option('unknown', help='Print unknown files.'),
1803
 
            Option('versioned', help='Print versioned files.',
1804
 
                   short_name='V'),
1805
 
            Option('ignored', help='Print ignored files.'),
1806
 
            Option('null',
1807
 
                   help='Write an ascii NUL (\\0) separator '
1808
 
                   'between files rather than a newline.'),
1809
 
            Option('kind',
1810
 
                   help='List entries of a particular kind: file, directory, symlink.',
1811
 
                   type=unicode),
1812
 
            'show-ids',
1813
 
            ]
 
1729
    takes_options = ['verbose', 'revision',
 
1730
                     Option('non-recursive',
 
1731
                            help='don\'t recurse into sub-directories'),
 
1732
                     Option('from-root',
 
1733
                            help='Print all paths from the root of the branch.'),
 
1734
                     Option('unknown', help='Print unknown files'),
 
1735
                     Option('versioned', help='Print versioned files'),
 
1736
                     Option('ignored', help='Print ignored files'),
 
1737
 
 
1738
                     Option('null', help='Null separate the files'),
 
1739
                     'kind', 'show-ids'
 
1740
                    ]
1814
1741
    @display_command
1815
 
    def run(self, revision=None, verbose=False,
 
1742
    def run(self, revision=None, verbose=False, 
1816
1743
            non_recursive=False, from_root=False,
1817
1744
            unknown=False, versioned=False, ignored=False,
1818
1745
            null=False, kind=None, show_ids=False, path=None):
1843
1770
            relpath += '/'
1844
1771
        if revision is not None:
1845
1772
            tree = branch.repository.revision_tree(
1846
 
                revision[0].as_revision_id(branch))
 
1773
                revision[0].in_history(branch).rev_id)
1847
1774
        elif tree is None:
1848
1775
            tree = branch.basis_tree()
1849
1776
 
1900
1827
class cmd_ignore(Command):
1901
1828
    """Ignore specified files or patterns.
1902
1829
 
1903
 
    See ``bzr help patterns`` for details on the syntax of patterns.
1904
 
 
1905
1830
    To remove patterns from the ignore list, edit the .bzrignore file.
1906
 
    After adding, editing or deleting that file either indirectly by
1907
 
    using this command or directly by using an editor, be sure to commit
1908
 
    it.
 
1831
 
 
1832
    Trailing slashes on patterns are ignored. 
 
1833
    If the pattern contains a slash or is a regular expression, it is compared 
 
1834
    to the whole path from the branch root.  Otherwise, it is compared to only
 
1835
    the last component of the path.  To match a file only in the root 
 
1836
    directory, prepend './'.
 
1837
 
 
1838
    Ignore patterns specifying absolute paths are not allowed.
 
1839
 
 
1840
    Ignore patterns may include globbing wildcards such as:
 
1841
      ? - Matches any single character except '/'
 
1842
      * - Matches 0 or more characters except '/'
 
1843
      /**/ - Matches 0 or more directories in a path
 
1844
      [a-z] - Matches a single character from within a group of characters
 
1845
 
 
1846
    Ignore patterns may also be Python regular expressions.  
 
1847
    Regular expression ignore patterns are identified by a 'RE:' prefix 
 
1848
    followed by the regular expression.  Regular expression ignore patterns
 
1849
    may not include named or numbered groups.
1909
1850
 
1910
1851
    Note: ignore patterns containing shell wildcards must be quoted from 
1911
1852
    the shell on Unix.
1912
1853
 
1913
 
    :Examples:
1914
 
        Ignore the top level Makefile::
1915
 
 
1916
 
            bzr ignore ./Makefile
1917
 
 
1918
 
        Ignore class files in all directories::
1919
 
 
1920
 
            bzr ignore "*.class"
1921
 
 
1922
 
        Ignore .o files under the lib directory::
1923
 
 
1924
 
            bzr ignore "lib/**/*.o"
1925
 
 
1926
 
        Ignore .o files under the lib directory::
1927
 
 
1928
 
            bzr ignore "RE:lib/.*\.o"
1929
 
 
1930
 
        Ignore everything but the "debian" toplevel directory::
1931
 
 
1932
 
            bzr ignore "RE:(?!debian/).*"
 
1854
    examples:
 
1855
        bzr ignore ./Makefile
 
1856
        bzr ignore '*.class'
 
1857
        bzr ignore 'lib/**/*.o'
 
1858
        bzr ignore 'RE:lib/.*\.o'
1933
1859
    """
1934
1860
 
1935
 
    _see_also = ['status', 'ignored', 'patterns']
 
1861
    _see_also = ['status', 'ignored']
1936
1862
    takes_args = ['name_pattern*']
1937
1863
    takes_options = [
1938
 
        Option('old-default-rules',
1939
 
               help='Write out the ignore rules bzr < 0.9 always used.')
1940
 
        ]
 
1864
                     Option('old-default-rules',
 
1865
                            help='Out the ignore rules bzr < 0.9 always used.')
 
1866
                     ]
1941
1867
    
1942
1868
    def run(self, name_pattern_list=None, old_default_rules=None):
1943
 
        from bzrlib import ignores
 
1869
        from bzrlib.atomicfile import AtomicFile
1944
1870
        if old_default_rules is not None:
1945
1871
            # dump the rules and exit
1946
1872
            for pattern in ignores.OLD_DEFAULTS:
1957
1883
                raise errors.BzrCommandError(
1958
1884
                    "NAME_PATTERN should not be an absolute path")
1959
1885
        tree, relpath = WorkingTree.open_containing(u'.')
1960
 
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
1961
 
        ignored = globbing.Globster(name_pattern_list)
1962
 
        matches = []
1963
 
        tree.lock_read()
1964
 
        for entry in tree.list_files():
1965
 
            id = entry[3]
1966
 
            if id is not None:
1967
 
                filename = entry[0]
1968
 
                if ignored.match(filename):
1969
 
                    matches.append(filename.encode('utf-8'))
1970
 
        tree.unlock()
1971
 
        if len(matches) > 0:
1972
 
            print "Warning: the following files are version controlled and" \
1973
 
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
 
1886
        ifn = tree.abspath('.bzrignore')
 
1887
        if os.path.exists(ifn):
 
1888
            f = open(ifn, 'rt')
 
1889
            try:
 
1890
                igns = f.read().decode('utf-8')
 
1891
            finally:
 
1892
                f.close()
 
1893
        else:
 
1894
            igns = ''
 
1895
 
 
1896
        # TODO: If the file already uses crlf-style termination, maybe
 
1897
        # we should use that for the newly added lines?
 
1898
 
 
1899
        if igns and igns[-1] != '\n':
 
1900
            igns += '\n'
 
1901
        for name_pattern in name_pattern_list:
 
1902
            igns += name_pattern + '\n'
 
1903
 
 
1904
        f = AtomicFile(ifn, 'wb')
 
1905
        try:
 
1906
            f.write(igns.encode('utf-8'))
 
1907
            f.commit()
 
1908
        finally:
 
1909
            f.close()
 
1910
 
 
1911
        if not tree.path2id('.bzrignore'):
 
1912
            tree.add(['.bzrignore'])
1974
1913
 
1975
1914
 
1976
1915
class cmd_ignored(Command):
1977
1916
    """List ignored files and the patterns that matched them.
1978
 
 
1979
 
    List all the ignored files and the ignore pattern that caused the file to
1980
 
    be ignored.
1981
 
 
1982
 
    Alternatively, to list just the files::
1983
 
 
1984
 
        bzr ls --ignored
1985
1917
    """
1986
1918
 
1987
 
    encoding_type = 'replace'
1988
 
    _see_also = ['ignore', 'ls']
1989
 
 
 
1919
    _see_also = ['ignore']
1990
1920
    @display_command
1991
1921
    def run(self):
1992
1922
        tree = WorkingTree.open_containing(u'.')[0]
1997
1927
                    continue
1998
1928
                ## XXX: Slightly inefficient since this was already calculated
1999
1929
                pat = tree.is_ignored(path)
2000
 
                self.outf.write('%-50s %s\n' % (path, pat))
 
1930
                print '%-50s %s' % (path, pat)
2001
1931
        finally:
2002
1932
            tree.unlock()
2003
1933
 
2005
1935
class cmd_lookup_revision(Command):
2006
1936
    """Lookup the revision-id from a revision-number
2007
1937
 
2008
 
    :Examples:
 
1938
    example:
2009
1939
        bzr lookup-revision 33
2010
1940
    """
2011
1941
    hidden = True
2039
1969
 
2040
1970
    Note: Export of tree with non-ASCII filenames to zip is not supported.
2041
1971
 
2042
 
      =================       =========================
2043
 
      Supported formats       Autodetected by extension
2044
 
      =================       =========================
2045
 
         dir                         (none)
 
1972
     Supported formats       Autodetected by extension
 
1973
     -----------------       -------------------------
 
1974
         dir                            -
2046
1975
         tar                          .tar
2047
1976
         tbz2                    .tar.bz2, .tbz2
2048
1977
         tgz                      .tar.gz, .tgz
2049
1978
         zip                          .zip
2050
 
      =================       =========================
2051
1979
    """
2052
 
    takes_args = ['dest', 'branch_or_subdir?']
2053
 
    takes_options = [
2054
 
        Option('format',
2055
 
               help="Type of file to export to.",
2056
 
               type=unicode),
2057
 
        'revision',
2058
 
        Option('root',
2059
 
               type=str,
2060
 
               help="Name of the root directory inside the exported file."),
2061
 
        ]
2062
 
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2063
 
        root=None):
 
1980
    takes_args = ['dest', 'branch?']
 
1981
    takes_options = ['revision', 'format', 'root']
 
1982
    def run(self, dest, branch=None, revision=None, format=None, root=None):
2064
1983
        from bzrlib.export import export
2065
1984
 
2066
 
        if branch_or_subdir is None:
 
1985
        if branch is None:
2067
1986
            tree = WorkingTree.open_containing(u'.')[0]
2068
1987
            b = tree.branch
2069
 
            subdir = None
2070
1988
        else:
2071
 
            b, subdir = Branch.open_containing(branch_or_subdir)
 
1989
            b = Branch.open(branch)
2072
1990
            
2073
1991
        if revision is None:
2074
1992
            # should be tree.last_revision  FIXME
2076
1994
        else:
2077
1995
            if len(revision) != 1:
2078
1996
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2079
 
            rev_id = revision[0].as_revision_id(b)
 
1997
            rev_id = revision[0].in_history(b).rev_id
2080
1998
        t = b.repository.revision_tree(rev_id)
2081
1999
        try:
2082
 
            export(t, dest, format, root, subdir)
 
2000
            export(t, dest, format, root)
2083
2001
        except errors.NoSuchExportFormat, e:
2084
2002
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2085
2003
 
2094
2012
    """
2095
2013
 
2096
2014
    _see_also = ['ls']
2097
 
    takes_options = [
2098
 
        Option('name-from-revision', help='The path name in the old tree.'),
2099
 
        'revision',
2100
 
        ]
 
2015
    takes_options = ['revision', 'name-from-revision']
2101
2016
    takes_args = ['filename']
2102
2017
    encoding_type = 'exact'
2103
2018
 
2105
2020
    def run(self, filename, revision=None, name_from_revision=False):
2106
2021
        if revision is not None and len(revision) != 1:
2107
2022
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2108
 
                                         " one revision specifier")
2109
 
        tree, branch, relpath = \
2110
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2111
 
        branch.lock_read()
 
2023
                                        " one number")
 
2024
 
 
2025
        tree = None
2112
2026
        try:
2113
 
            return self._run(tree, branch, relpath, filename, revision,
2114
 
                             name_from_revision)
2115
 
        finally:
2116
 
            branch.unlock()
 
2027
            tree, b, relpath = \
 
2028
                    bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
2029
        except errors.NotBranchError:
 
2030
            pass
2117
2031
 
2118
 
    def _run(self, tree, b, relpath, filename, revision, name_from_revision):
 
2032
        if revision is not None and revision[0].get_branch() is not None:
 
2033
            b = Branch.open(revision[0].get_branch())
2119
2034
        if tree is None:
2120
2035
            tree = b.basis_tree()
2121
2036
        if revision is None:
2122
2037
            revision_id = b.last_revision()
2123
2038
        else:
2124
 
            revision_id = revision[0].as_revision_id(b)
 
2039
            revision_id = revision[0].in_history(b).rev_id
2125
2040
 
2126
2041
        cur_file_id = tree.path2id(relpath)
2127
2042
        rev_tree = b.repository.revision_tree(revision_id)
2132
2047
                raise errors.BzrCommandError("%r is not present in revision %s"
2133
2048
                                                % (filename, revision_id))
2134
2049
            else:
2135
 
                content = rev_tree.get_file_text(old_file_id)
 
2050
                rev_tree.print_file(old_file_id)
2136
2051
        elif cur_file_id is not None:
2137
 
            content = rev_tree.get_file_text(cur_file_id)
 
2052
            rev_tree.print_file(cur_file_id)
2138
2053
        elif old_file_id is not None:
2139
 
            content = rev_tree.get_file_text(old_file_id)
 
2054
            rev_tree.print_file(old_file_id)
2140
2055
        else:
2141
2056
            raise errors.BzrCommandError("%r is not present in revision %s" %
2142
2057
                                         (filename, revision_id))
2143
 
        self.outf.write(content)
2144
2058
 
2145
2059
 
2146
2060
class cmd_local_time_offset(Command):
2161
2075
    committed.  If a directory is specified then the directory and everything 
2162
2076
    within it is committed.
2163
2077
 
2164
 
    When excludes are given, they take precedence over selected files.
2165
 
    For example, too commit only changes within foo, but not changes within
2166
 
    foo/bar::
2167
 
 
2168
 
      bzr commit foo -x foo/bar
2169
 
 
2170
 
    If author of the change is not the same person as the committer, you can
2171
 
    specify the author's name using the --author option. The name should be
2172
 
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2173
 
 
2174
2078
    A selected-file commit may fail in some cases where the committed
2175
2079
    tree would be invalid. Consider::
2176
2080
 
2201
2105
 
2202
2106
    _see_also = ['bugs', 'uncommit']
2203
2107
    takes_args = ['selected*']
2204
 
    takes_options = [
2205
 
            ListOption('exclude', type=str, short_name='x',
2206
 
                help="Do not consider changes made to a given path."),
2207
 
            Option('message', type=unicode,
2208
 
                   short_name='m',
2209
 
                   help="Description of the new revision."),
2210
 
            'verbose',
2211
 
             Option('unchanged',
2212
 
                    help='Commit even if nothing has changed.'),
2213
 
             Option('file', type=str,
2214
 
                    short_name='F',
2215
 
                    argname='msgfile',
2216
 
                    help='Take commit message from this file.'),
2217
 
             Option('strict',
2218
 
                    help="Refuse to commit if there are unknown "
2219
 
                    "files in the working tree."),
2220
 
             ListOption('fixes', type=str,
2221
 
                    help="Mark a bug as being fixed by this revision."),
2222
 
             Option('author', type=unicode,
2223
 
                    help="Set the author's name, if it's different "
2224
 
                         "from the committer."),
2225
 
             Option('local',
2226
 
                    help="Perform a local commit in a bound "
2227
 
                         "branch.  Local commits are not pushed to "
2228
 
                         "the master branch until a normal commit "
2229
 
                         "is performed."
2230
 
                    ),
2231
 
              Option('show-diff',
2232
 
                     help='When no message is supplied, show the diff along'
2233
 
                     ' with the status summary in the message editor.'),
2234
 
             ]
 
2108
    takes_options = ['message', 'verbose', 
 
2109
                     Option('unchanged',
 
2110
                            help='commit even if nothing has changed'),
 
2111
                     Option('file', type=str, 
 
2112
                            short_name='F',
 
2113
                            argname='msgfile',
 
2114
                            help='file containing commit message'),
 
2115
                     Option('strict',
 
2116
                            help="refuse to commit if there are unknown "
 
2117
                            "files in the working tree."),
 
2118
                     ListOption('fixes', type=str,
 
2119
                                help="mark a bug as being fixed by this "
 
2120
                                     "revision."),
 
2121
                     Option('local',
 
2122
                            help="perform a local only commit in a bound "
 
2123
                                 "branch. Such commits are not pushed to "
 
2124
                                 "the master branch until a normal commit "
 
2125
                                 "is performed."
 
2126
                            ),
 
2127
                     ]
2235
2128
    aliases = ['ci', 'checkin']
2236
2129
 
2237
2130
    def _get_bug_fix_properties(self, fixes, branch):
2256
2149
            properties.append('%s fixed' % bug_url)
2257
2150
        return '\n'.join(properties)
2258
2151
 
2259
 
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2260
 
            unchanged=False, strict=False, local=False, fixes=None,
2261
 
            author=None, show_diff=False, exclude=None):
2262
 
        from bzrlib.errors import (
2263
 
            PointlessCommit,
2264
 
            ConflictsInTree,
2265
 
            StrictCommitFailed
2266
 
        )
2267
 
        from bzrlib.msgeditor import (
2268
 
            edit_commit_message_encoded,
2269
 
            make_commit_message_template_encoded
2270
 
        )
 
2152
    def run(self, message=None, file=None, verbose=True, selected_list=None,
 
2153
            unchanged=False, strict=False, local=False, fixes=None):
 
2154
        from bzrlib.commit import (NullCommitReporter, ReportCommitToLog)
 
2155
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
 
2156
                StrictCommitFailed)
 
2157
        from bzrlib.msgeditor import edit_commit_message, \
 
2158
                make_commit_message_template
2271
2159
 
2272
2160
        # TODO: Need a blackbox test for invoking the external editor; may be
2273
2161
        # slightly problematic to run this cross-platform.
2284
2172
            # selected-file merge commit is not done yet
2285
2173
            selected_list = []
2286
2174
 
2287
 
        if fixes is None:
2288
 
            fixes = []
2289
2175
        bug_property = self._get_bug_fix_properties(fixes, tree.branch)
2290
2176
        if bug_property:
2291
2177
            properties['bugs'] = bug_property
2297
2183
            """Callback to get commit message"""
2298
2184
            my_message = message
2299
2185
            if my_message is None and not file:
2300
 
                t = make_commit_message_template_encoded(tree,
2301
 
                        selected_list, diff=show_diff,
2302
 
                        output_encoding=bzrlib.user_encoding)
2303
 
                my_message = edit_commit_message_encoded(t)
 
2186
                template = make_commit_message_template(tree, selected_list)
 
2187
                my_message = edit_commit_message(template)
2304
2188
                if my_message is None:
2305
2189
                    raise errors.BzrCommandError("please specify a commit"
2306
2190
                        " message with either --message or --file")
2308
2192
                raise errors.BzrCommandError(
2309
2193
                    "please specify either --message or --file")
2310
2194
            if file:
2311
 
                my_message = codecs.open(file, 'rt',
 
2195
                my_message = codecs.open(file, 'rt', 
2312
2196
                                         bzrlib.user_encoding).read()
2313
2197
            if my_message == "":
2314
2198
                raise errors.BzrCommandError("empty commit message specified")
2315
2199
            return my_message
2316
2200
 
 
2201
        if verbose:
 
2202
            reporter = ReportCommitToLog()
 
2203
        else:
 
2204
            reporter = NullCommitReporter()
 
2205
 
2317
2206
        try:
2318
2207
            tree.commit(message_callback=get_message,
2319
2208
                        specific_files=selected_list,
2320
2209
                        allow_pointless=unchanged, strict=strict, local=local,
2321
 
                        reporter=None, verbose=verbose, revprops=properties,
2322
 
                        author=author,
2323
 
                        exclude=safe_relpath_files(tree, exclude))
 
2210
                        reporter=reporter, revprops=properties)
2324
2211
        except PointlessCommit:
2325
2212
            # FIXME: This should really happen before the file is read in;
2326
2213
            # perhaps prepare the commit; get the message; then actually commit
2341
2228
 
2342
2229
 
2343
2230
class cmd_check(Command):
2344
 
    """Validate working tree structure, branch consistency and repository history.
2345
 
 
2346
 
    This command checks various invariants about branch and repository storage
2347
 
    to detect data corruption or bzr bugs.
2348
 
 
2349
 
    The working tree and branch checks will only give output if a problem is
2350
 
    detected. The output fields of the repository check are:
2351
 
 
2352
 
        revisions: This is just the number of revisions checked.  It doesn't
2353
 
            indicate a problem.
2354
 
        versionedfiles: This is just the number of versionedfiles checked.  It
2355
 
            doesn't indicate a problem.
2356
 
        unreferenced ancestors: Texts that are ancestors of other texts, but
2357
 
            are not properly referenced by the revision ancestry.  This is a
2358
 
            subtle problem that Bazaar can work around.
2359
 
        unique file texts: This is the total number of unique file contents
2360
 
            seen in the checked revisions.  It does not indicate a problem.
2361
 
        repeated file texts: This is the total number of repeated texts seen
2362
 
            in the checked revisions.  Texts can be repeated when their file
2363
 
            entries are modified, but the file contents are not.  It does not
2364
 
            indicate a problem.
2365
 
 
2366
 
    If no restrictions are specified, all Bazaar data that is found at the given
2367
 
    location will be checked.
2368
 
 
2369
 
    :Examples:
2370
 
 
2371
 
        Check the tree and branch at 'foo'::
2372
 
 
2373
 
            bzr check --tree --branch foo
2374
 
 
2375
 
        Check only the repository at 'bar'::
2376
 
 
2377
 
            bzr check --repo bar
2378
 
 
2379
 
        Check everything at 'baz'::
2380
 
 
2381
 
            bzr check baz
 
2231
    """Validate consistency of branch history.
 
2232
 
 
2233
    This command checks various invariants about the branch storage to
 
2234
    detect data corruption or bzr bugs.
2382
2235
    """
2383
2236
 
2384
2237
    _see_also = ['reconcile']
2385
 
    takes_args = ['path?']
2386
 
    takes_options = ['verbose',
2387
 
                     Option('branch', help="Check the branch related to the"
2388
 
                                           " current directory."),
2389
 
                     Option('repo', help="Check the repository related to the"
2390
 
                                         " current directory."),
2391
 
                     Option('tree', help="Check the working tree related to"
2392
 
                                         " the current directory.")]
 
2238
    takes_args = ['branch?']
 
2239
    takes_options = ['verbose']
2393
2240
 
2394
 
    def run(self, path=None, verbose=False, branch=False, repo=False,
2395
 
            tree=False):
2396
 
        from bzrlib.check import check_dwim
2397
 
        if path is None:
2398
 
            path = '.'
2399
 
        if not branch and not repo and not tree:
2400
 
            branch = repo = tree = True
2401
 
        check_dwim(path, verbose, do_branch=branch, do_repo=repo, do_tree=tree)
 
2241
    def run(self, branch=None, verbose=False):
 
2242
        from bzrlib.check import check
 
2243
        if branch is None:
 
2244
            tree = WorkingTree.open_containing()[0]
 
2245
            branch = tree.branch
 
2246
        else:
 
2247
            branch = Branch.open(branch)
 
2248
        check(branch, verbose)
2402
2249
 
2403
2250
 
2404
2251
class cmd_upgrade(Command):
2414
2261
    takes_options = [
2415
2262
                    RegistryOption('format',
2416
2263
                        help='Upgrade to a specific format.  See "bzr help'
2417
 
                             ' formats" for details.',
 
2264
                             ' formats" for details',
2418
2265
                        registry=bzrdir.format_registry,
2419
2266
                        converter=bzrdir.format_registry.make_bzrdir,
2420
2267
                        value_switches=True, title='Branch format'),
2430
2277
class cmd_whoami(Command):
2431
2278
    """Show or set bzr user id.
2432
2279
    
2433
 
    :Examples:
2434
 
        Show the email of the current user::
2435
 
 
2436
 
            bzr whoami --email
2437
 
 
2438
 
        Set the current user::
2439
 
 
2440
 
            bzr whoami "Frank Chu <fchu@example.com>"
 
2280
    examples:
 
2281
        bzr whoami --email
 
2282
        bzr whoami 'Frank Chu <fchu@example.com>'
2441
2283
    """
2442
2284
    takes_options = [ Option('email',
2443
 
                             help='Display email address only.'),
 
2285
                             help='display email address only'),
2444
2286
                      Option('branch',
2445
 
                             help='Set identity for the current branch instead of '
2446
 
                                  'globally.'),
 
2287
                             help='set identity for the current branch instead of '
 
2288
                                  'globally'),
2447
2289
                    ]
2448
2290
    takes_args = ['name?']
2449
2291
    encoding_type = 'replace'
2498
2340
        print branch.nick
2499
2341
 
2500
2342
 
2501
 
class cmd_alias(Command):
2502
 
    """Set/unset and display aliases.
2503
 
 
2504
 
    :Examples:
2505
 
        Show the current aliases::
2506
 
 
2507
 
            bzr alias
2508
 
 
2509
 
        Show the alias specified for 'll'::
2510
 
 
2511
 
            bzr alias ll
2512
 
 
2513
 
        Set an alias for 'll'::
2514
 
 
2515
 
            bzr alias ll="log --line -r-10..-1"
2516
 
 
2517
 
        To remove an alias for 'll'::
2518
 
 
2519
 
            bzr alias --remove ll
2520
 
 
2521
 
    """
2522
 
    takes_args = ['name?']
2523
 
    takes_options = [
2524
 
        Option('remove', help='Remove the alias.'),
2525
 
        ]
2526
 
 
2527
 
    def run(self, name=None, remove=False):
2528
 
        if remove:
2529
 
            self.remove_alias(name)
2530
 
        elif name is None:
2531
 
            self.print_aliases()
2532
 
        else:
2533
 
            equal_pos = name.find('=')
2534
 
            if equal_pos == -1:
2535
 
                self.print_alias(name)
2536
 
            else:
2537
 
                self.set_alias(name[:equal_pos], name[equal_pos+1:])
2538
 
 
2539
 
    def remove_alias(self, alias_name):
2540
 
        if alias_name is None:
2541
 
            raise errors.BzrCommandError(
2542
 
                'bzr alias --remove expects an alias to remove.')
2543
 
        # If alias is not found, print something like:
2544
 
        # unalias: foo: not found
2545
 
        c = config.GlobalConfig()
2546
 
        c.unset_alias(alias_name)
2547
 
 
2548
 
    @display_command
2549
 
    def print_aliases(self):
2550
 
        """Print out the defined aliases in a similar format to bash."""
2551
 
        aliases = config.GlobalConfig().get_aliases()
2552
 
        for key, value in sorted(aliases.iteritems()):
2553
 
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
2554
 
 
2555
 
    @display_command
2556
 
    def print_alias(self, alias_name):
2557
 
        from bzrlib.commands import get_alias
2558
 
        alias = get_alias(alias_name)
2559
 
        if alias is None:
2560
 
            self.outf.write("bzr alias: %s: not found\n" % alias_name)
2561
 
        else:
2562
 
            self.outf.write(
2563
 
                'bzr alias %s="%s"\n' % (alias_name, ' '.join(alias)))
2564
 
 
2565
 
    def set_alias(self, alias_name, alias_command):
2566
 
        """Save the alias in the global config."""
2567
 
        c = config.GlobalConfig()
2568
 
        c.set_alias(alias_name, alias_command)
2569
 
 
2570
 
 
2571
2343
class cmd_selftest(Command):
2572
2344
    """Run internal test suite.
2573
2345
    
 
2346
    This creates temporary test directories in the working directory, but no
 
2347
    existing data is affected.  These directories are deleted if the tests
 
2348
    pass, or left behind to help in debugging if they fail and --keep-output
 
2349
    is specified.
 
2350
    
2574
2351
    If arguments are given, they are regular expressions that say which tests
2575
2352
    should run.  Tests matching any expression are run, and other tests are
2576
2353
    not run.
2599
2376
    modified by plugins will not be tested, and tests provided by plugins will
2600
2377
    not be run.
2601
2378
 
2602
 
    Tests that need working space on disk use a common temporary directory, 
2603
 
    typically inside $TMPDIR or /tmp.
2604
 
 
2605
 
    :Examples:
2606
 
        Run only tests relating to 'ignore'::
2607
 
 
2608
 
            bzr selftest ignore
2609
 
 
2610
 
        Disable plugins and list tests as they're run::
2611
 
 
2612
 
            bzr --no-plugins selftest -v
 
2379
    examples::
 
2380
        bzr selftest ignore
 
2381
            run only tests relating to 'ignore'
 
2382
        bzr --no-plugins selftest -v
 
2383
            disable plugins and list tests as they're run
 
2384
 
 
2385
    For each test, that needs actual disk access, bzr create their own
 
2386
    subdirectory in the temporary testing directory (testXXXX.tmp).
 
2387
    By default the name of such subdirectory is based on the name of the test.
 
2388
    If option '--numbered-dirs' is given, bzr will use sequent numbers
 
2389
    of running tests to create such subdirectories. This is default behavior
 
2390
    on Windows because of path length limitation.
2613
2391
    """
2614
2392
    # NB: this is used from the class without creating an instance, which is
2615
2393
    # why it does not have a self parameter.
2632
2410
    takes_args = ['testspecs*']
2633
2411
    takes_options = ['verbose',
2634
2412
                     Option('one',
2635
 
                             help='Stop when one test fails.',
 
2413
                             help='stop when one test fails',
2636
2414
                             short_name='1',
2637
2415
                             ),
 
2416
                     Option('keep-output',
 
2417
                            help='keep output directories when tests fail'),
2638
2418
                     Option('transport',
2639
2419
                            help='Use a different transport by default '
2640
2420
                                 'throughout the test suite.',
2641
2421
                            type=get_transport_type),
2642
 
                     Option('benchmark',
2643
 
                            help='Run the benchmarks rather than selftests.'),
 
2422
                     Option('benchmark', help='run the bzr benchmarks.'),
2644
2423
                     Option('lsprof-timed',
2645
 
                            help='Generate lsprof output for benchmarked'
 
2424
                            help='generate lsprof output for benchmarked'
2646
2425
                                 ' sections of code.'),
2647
2426
                     Option('cache-dir', type=str,
2648
 
                            help='Cache intermediate benchmark output in this '
2649
 
                                 'directory.'),
 
2427
                            help='a directory to cache intermediate'
 
2428
                                 ' benchmark steps'),
 
2429
                     Option('clean-output',
 
2430
                            help='clean temporary tests directories'
 
2431
                                 ' without running tests'),
2650
2432
                     Option('first',
2651
 
                            help='Run all tests, but run specified tests first.',
 
2433
                            help='run all tests, but run specified tests first',
2652
2434
                            short_name='f',
2653
2435
                            ),
 
2436
                     Option('numbered-dirs',
 
2437
                            help='use numbered dirs for TestCaseInTempDir'),
2654
2438
                     Option('list-only',
2655
 
                            help='List the tests instead of running them.'),
 
2439
                            help='list the tests instead of running them'),
2656
2440
                     Option('randomize', type=str, argname="SEED",
2657
 
                            help='Randomize the order of tests using the given'
2658
 
                                 ' seed or "now" for the current time.'),
 
2441
                            help='randomize the order of tests using the given'
 
2442
                                 ' seed or "now" for the current time'),
2659
2443
                     Option('exclude', type=str, argname="PATTERN",
2660
2444
                            short_name='x',
2661
 
                            help='Exclude tests that match this regular'
2662
 
                                 ' expression.'),
2663
 
                     Option('strict', help='Fail on missing dependencies or '
2664
 
                            'known failures.'),
2665
 
                     Option('load-list', type=str, argname='TESTLISTFILE',
2666
 
                            help='Load a test id list from a text file.'),
2667
 
                     ListOption('debugflag', type=str, short_name='E',
2668
 
                                help='Turn on a selftest debug flag.'),
2669
 
                     ListOption('starting-with', type=str, argname='TESTID',
2670
 
                                param_name='starting_with', short_name='s',
2671
 
                                help=
2672
 
                                'Load only the tests starting with TESTID.'),
 
2445
                            help='exclude tests that match this regular'
 
2446
                                 ' expression'),
2673
2447
                     ]
2674
2448
    encoding_type = 'replace'
2675
2449
 
2676
 
    def run(self, testspecs_list=None, verbose=False, one=False,
2677
 
            transport=None, benchmark=None,
2678
 
            lsprof_timed=None, cache_dir=None,
2679
 
            first=False, list_only=False,
2680
 
            randomize=None, exclude=None, strict=False,
2681
 
            load_list=None, debugflag=None, starting_with=None):
 
2450
    def run(self, testspecs_list=None, verbose=None, one=False,
 
2451
            keep_output=False, transport=None, benchmark=None,
 
2452
            lsprof_timed=None, cache_dir=None, clean_output=False,
 
2453
            first=False, numbered_dirs=None, list_only=False,
 
2454
            randomize=None, exclude=None):
2682
2455
        import bzrlib.ui
2683
2456
        from bzrlib.tests import selftest
2684
2457
        import bzrlib.benchmarks as benchmarks
2685
2458
        from bzrlib.benchmarks import tree_creator
2686
2459
 
2687
 
        # Make deprecation warnings visible, unless -Werror is set
2688
 
        symbol_versioning.activate_deprecation_warnings(override=False)
 
2460
        if clean_output:
 
2461
            from bzrlib.tests import clean_selftest_output
 
2462
            clean_selftest_output()
 
2463
            return 0
 
2464
 
 
2465
        if numbered_dirs is None and sys.platform == 'win32':
 
2466
            numbered_dirs = True
2689
2467
 
2690
2468
        if cache_dir is not None:
2691
2469
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2692
 
        if not list_only:
2693
 
            print 'testing: %s' % (osutils.realpath(sys.argv[0]),)
2694
 
            print '   %s (%s python%s)' % (
2695
 
                    bzrlib.__path__[0],
2696
 
                    bzrlib.version_string,
2697
 
                    bzrlib._format_version_tuple(sys.version_info),
2698
 
                    )
 
2470
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
 
2471
        print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
2699
2472
        print
2700
2473
        if testspecs_list is not None:
2701
2474
            pattern = '|'.join(testspecs_list)
2703
2476
            pattern = ".*"
2704
2477
        if benchmark:
2705
2478
            test_suite_factory = benchmarks.test_suite
2706
 
            # Unless user explicitly asks for quiet, be verbose in benchmarks
2707
 
            verbose = not is_quiet()
 
2479
            if verbose is None:
 
2480
                verbose = True
2708
2481
            # TODO: should possibly lock the history file...
2709
2482
            benchfile = open(".perf_history", "at", buffering=1)
2710
2483
        else:
2711
2484
            test_suite_factory = None
 
2485
            if verbose is None:
 
2486
                verbose = False
2712
2487
            benchfile = None
2713
2488
        try:
2714
 
            result = selftest(verbose=verbose,
 
2489
            result = selftest(verbose=verbose, 
2715
2490
                              pattern=pattern,
2716
 
                              stop_on_failure=one,
 
2491
                              stop_on_failure=one, 
 
2492
                              keep_output=keep_output,
2717
2493
                              transport=transport,
2718
2494
                              test_suite_factory=test_suite_factory,
2719
2495
                              lsprof_timed=lsprof_timed,
2720
2496
                              bench_history=benchfile,
2721
2497
                              matching_tests_first=first,
 
2498
                              numbered_dirs=numbered_dirs,
2722
2499
                              list_only=list_only,
2723
2500
                              random_seed=randomize,
2724
 
                              exclude_pattern=exclude,
2725
 
                              strict=strict,
2726
 
                              load_list=load_list,
2727
 
                              debug_flags=debugflag,
2728
 
                              starting_with=starting_with,
 
2501
                              exclude_pattern=exclude
2729
2502
                              )
2730
2503
        finally:
2731
2504
            if benchfile is not None:
2732
2505
                benchfile.close()
2733
2506
        if result:
2734
 
            note('tests passed')
 
2507
            info('tests passed')
2735
2508
        else:
2736
 
            note('tests failed')
 
2509
            info('tests failed')
2737
2510
        return int(not result)
2738
2511
 
2739
2512
 
2740
2513
class cmd_version(Command):
2741
2514
    """Show version of bzr."""
2742
2515
 
2743
 
    encoding_type = 'replace'
2744
 
    takes_options = [
2745
 
        Option("short", help="Print just the version number."),
2746
 
        ]
2747
 
 
2748
2516
    @display_command
2749
 
    def run(self, short=False):
 
2517
    def run(self):
2750
2518
        from bzrlib.version import show_version
2751
 
        if short:
2752
 
            self.outf.write(bzrlib.version_string + '\n')
2753
 
        else:
2754
 
            show_version(to_file=self.outf)
 
2519
        show_version()
2755
2520
 
2756
2521
 
2757
2522
class cmd_rocks(Command):
2773
2538
    
2774
2539
    @display_command
2775
2540
    def run(self, branch, other):
2776
 
        from bzrlib.revision import ensure_null
 
2541
        from bzrlib.revision import MultipleRevisionSources
2777
2542
        
2778
2543
        branch1 = Branch.open_containing(branch)[0]
2779
2544
        branch2 = Branch.open_containing(other)[0]
2780
 
        branch1.lock_read()
2781
 
        try:
2782
 
            branch2.lock_read()
2783
 
            try:
2784
 
                last1 = ensure_null(branch1.last_revision())
2785
 
                last2 = ensure_null(branch2.last_revision())
2786
 
 
2787
 
                graph = branch1.repository.get_graph(branch2.repository)
2788
 
                base_rev_id = graph.find_unique_lca(last1, last2)
2789
 
 
2790
 
                print 'merge base is revision %s' % base_rev_id
2791
 
            finally:
2792
 
                branch2.unlock()
2793
 
        finally:
2794
 
            branch1.unlock()
 
2545
 
 
2546
        last1 = branch1.last_revision()
 
2547
        last2 = branch2.last_revision()
 
2548
 
 
2549
        source = MultipleRevisionSources(branch1.repository, 
 
2550
                                         branch2.repository)
 
2551
        
 
2552
        base_rev_id = common_ancestor(last1, last2, source)
 
2553
 
 
2554
        print 'merge base is revision %s' % base_rev_id
2795
2555
 
2796
2556
 
2797
2557
class cmd_merge(Command):
2798
2558
    """Perform a three-way merge.
2799
2559
    
2800
 
    The source of the merge can be specified either in the form of a branch,
2801
 
    or in the form of a path to a file containing a merge directive generated
2802
 
    with bzr send. If neither is specified, the default is the upstream branch
2803
 
    or the branch most recently merged using --remember.
2804
 
 
2805
 
    When merging a branch, by default the tip will be merged. To pick a different
2806
 
    revision, pass --revision. If you specify two values, the first will be used as
2807
 
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
2808
 
    available revisions, like this is commonly referred to as "cherrypicking".
2809
 
 
2810
 
    Revision numbers are always relative to the branch being merged.
 
2560
    The branch is the branch you will merge from.  By default, it will merge
 
2561
    the latest revision.  If you specify a revision, that revision will be
 
2562
    merged.  If you specify two revisions, the first will be used as a BASE,
 
2563
    and the second one as OTHER.  Revision numbers are always relative to the
 
2564
    specified branch.
2811
2565
 
2812
2566
    By default, bzr will try to merge in all new work from the other
2813
2567
    branch, automatically determining an appropriate base.  If this
2828
2582
    The results of the merge are placed into the destination working
2829
2583
    directory, where they can be reviewed (with bzr diff), tested, and then
2830
2584
    committed to record the result of the merge.
 
2585
 
 
2586
    Examples:
 
2587
 
 
2588
    To merge the latest revision from bzr.dev:
 
2589
        bzr merge ../bzr.dev
 
2590
 
 
2591
    To merge changes up to and including revision 82 from bzr.dev:
 
2592
        bzr merge -r 82 ../bzr.dev
 
2593
 
 
2594
    To merge the changes introduced by 82, without previous changes:
 
2595
        bzr merge -r 81..82 ../bzr.dev
2831
2596
    
2832
2597
    merge refuses to run if there are any uncommitted changes, unless
2833
2598
    --force is given.
2834
 
 
2835
 
    :Examples:
2836
 
        To merge the latest revision from bzr.dev::
2837
 
 
2838
 
            bzr merge ../bzr.dev
2839
 
 
2840
 
        To merge changes up to and including revision 82 from bzr.dev::
2841
 
 
2842
 
            bzr merge -r 82 ../bzr.dev
2843
 
 
2844
 
        To merge the changes introduced by 82, without previous changes::
2845
 
 
2846
 
            bzr merge -r 81..82 ../bzr.dev
2847
 
 
2848
 
        To apply a merge directive contained in in /tmp/merge:
2849
 
 
2850
 
            bzr merge /tmp/merge
2851
2599
    """
2852
2600
 
2853
 
    encoding_type = 'exact'
2854
 
    _see_also = ['update', 'remerge', 'status-flags']
2855
 
    takes_args = ['location?']
2856
 
    takes_options = [
2857
 
        'change',
2858
 
        'revision',
2859
 
        Option('force',
2860
 
               help='Merge even if the destination tree has uncommitted changes.'),
2861
 
        'merge-type',
2862
 
        'reprocess',
2863
 
        'remember',
 
2601
    _see_also = ['update', 'remerge']
 
2602
    takes_args = ['branch?']
 
2603
    takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2864
2604
        Option('show-base', help="Show base revision text in "
2865
 
               "conflicts."),
 
2605
               "conflicts"),
2866
2606
        Option('uncommitted', help='Apply uncommitted changes'
2867
 
               ' from a working copy, instead of branch changes.'),
 
2607
               ' from a working copy, instead of branch changes'),
2868
2608
        Option('pull', help='If the destination is already'
2869
2609
                ' completely merged into the source, pull from the'
2870
 
                ' source rather than merging.  When this happens,'
 
2610
                ' source rather than merging. When this happens,'
2871
2611
                ' you do not need to commit the result.'),
2872
2612
        Option('directory',
2873
 
               help='Branch to merge into, '
2874
 
                    'rather than the one containing the working directory.',
2875
 
               short_name='d',
2876
 
               type=unicode,
2877
 
               ),
2878
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
 
2613
            help='Branch to merge into, '
 
2614
                 'rather than the one containing the working directory',
 
2615
            short_name='d',
 
2616
            type=unicode,
 
2617
            ),
2879
2618
    ]
2880
2619
 
2881
 
    def run(self, location=None, revision=None, force=False,
2882
 
            merge_type=None, show_base=False, reprocess=False, remember=False,
 
2620
    def run(self, branch=None, revision=None, force=False, merge_type=None,
 
2621
            show_base=False, reprocess=False, remember=False,
2883
2622
            uncommitted=False, pull=False,
2884
2623
            directory=None,
2885
 
            preview=False,
2886
2624
            ):
 
2625
        from bzrlib.tag import _merge_tags_if_possible
 
2626
        other_revision_id = None
2887
2627
        if merge_type is None:
2888
2628
            merge_type = _mod_merge.Merge3Merger
2889
2629
 
2890
2630
        if directory is None: directory = u'.'
2891
 
        possible_transports = []
2892
 
        merger = None
2893
 
        allow_pending = True
2894
 
        verified = 'inapplicable'
 
2631
        # XXX: jam 20070225 WorkingTree should be locked before you extract its
 
2632
        #      inventory. Because merge is a mutating operation, it really
 
2633
        #      should be a lock_write() for the whole cmd_merge operation.
 
2634
        #      However, cmd_merge open's its own tree in _merge_helper, which
 
2635
        #      means if we lock here, the later lock_write() will always block.
 
2636
        #      Either the merge helper code should be updated to take a tree,
 
2637
        #      (What about tree.merge_from_branch?)
2895
2638
        tree = WorkingTree.open_containing(directory)[0]
2896
2639
        change_reporter = delta._ChangeReporter(
2897
2640
            unversioned_filter=tree.is_ignored)
2898
 
        cleanups = []
2899
 
        try:
2900
 
            pb = ui.ui_factory.nested_progress_bar()
2901
 
            cleanups.append(pb.finished)
2902
 
            tree.lock_write()
2903
 
            cleanups.append(tree.unlock)
2904
 
            if location is not None:
2905
 
                try:
2906
 
                    mergeable = bundle.read_mergeable_from_url(location,
2907
 
                        possible_transports=possible_transports)
2908
 
                except errors.NotABundle:
2909
 
                    mergeable = None
 
2641
 
 
2642
        if branch is not None:
 
2643
            try:
 
2644
                mergeable = bundle.read_mergeable_from_url(
 
2645
                    branch)
 
2646
            except errors.NotABundle:
 
2647
                pass # Continue on considering this url a Branch
 
2648
            else:
 
2649
                if revision is not None:
 
2650
                    raise errors.BzrCommandError(
 
2651
                        'Cannot use -r with merge directives or bundles')
 
2652
                other_revision_id = mergeable.install_revisions(
 
2653
                    tree.branch.repository)
 
2654
                revision = [RevisionSpec.from_string(
 
2655
                    'revid:' + other_revision_id)]
 
2656
 
 
2657
        if revision is None \
 
2658
                or len(revision) < 1 or revision[0].needs_branch():
 
2659
            branch = self._get_remembered_parent(tree, branch, 'Merging from')
 
2660
 
 
2661
        if revision is None or len(revision) < 1:
 
2662
            if uncommitted:
 
2663
                base = [branch, -1]
 
2664
                other = [branch, None]
 
2665
            else:
 
2666
                base = [None, None]
 
2667
                other = [branch, -1]
 
2668
            other_branch, path = Branch.open_containing(branch)
 
2669
        else:
 
2670
            if uncommitted:
 
2671
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
2672
                                             ' --revision at the same time.')
 
2673
            branch = revision[0].get_branch() or branch
 
2674
            if len(revision) == 1:
 
2675
                base = [None, None]
 
2676
                if other_revision_id is not None:
 
2677
                    other_branch = None
 
2678
                    path = ""
 
2679
                    other = None
2910
2680
                else:
2911
 
                    if uncommitted:
2912
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
2913
 
                            ' with bundles or merge directives.')
2914
 
 
2915
 
                    if revision is not None:
2916
 
                        raise errors.BzrCommandError(
2917
 
                            'Cannot use -r with merge directives or bundles')
2918
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
2919
 
                       mergeable, pb)
2920
 
 
2921
 
            if merger is None and uncommitted:
2922
 
                if revision is not None and len(revision) > 0:
2923
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
2924
 
                        ' --revision at the same time.')
2925
 
                location = self._select_branch_location(tree, location)[0]
2926
 
                other_tree, other_path = WorkingTree.open_containing(location)
2927
 
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
2928
 
                    pb)
2929
 
                allow_pending = False
2930
 
                if other_path != '':
2931
 
                    merger.interesting_files = [other_path]
2932
 
 
2933
 
            if merger is None:
2934
 
                merger, allow_pending = self._get_merger_from_branch(tree,
2935
 
                    location, revision, remember, possible_transports, pb)
2936
 
 
2937
 
            merger.merge_type = merge_type
2938
 
            merger.reprocess = reprocess
2939
 
            merger.show_base = show_base
2940
 
            self.sanity_check_merger(merger)
2941
 
            if (merger.base_rev_id == merger.other_rev_id and
2942
 
                merger.other_rev_id is not None):
2943
 
                note('Nothing to do.')
 
2681
                    other_branch, path = Branch.open_containing(branch)
 
2682
                    revno = revision[0].in_history(other_branch).revno
 
2683
                    other = [branch, revno]
 
2684
            else:
 
2685
                assert len(revision) == 2
 
2686
                if None in revision:
 
2687
                    raise errors.BzrCommandError(
 
2688
                        "Merge doesn't permit empty revision specifier.")
 
2689
                base_branch, path = Branch.open_containing(branch)
 
2690
                branch1 = revision[1].get_branch() or branch
 
2691
                other_branch, path1 = Branch.open_containing(branch1)
 
2692
                if revision[0].get_branch() is not None:
 
2693
                    # then path was obtained from it, and is None.
 
2694
                    path = path1
 
2695
 
 
2696
                base = [branch, revision[0].in_history(base_branch).revno]
 
2697
                other = [branch1, revision[1].in_history(other_branch).revno]
 
2698
 
 
2699
        if ((tree.branch.get_parent() is None or remember) and
 
2700
            other_branch is not None):
 
2701
            tree.branch.set_parent(other_branch.base)
 
2702
 
 
2703
        # pull tags now... it's a bit inconsistent to do it ahead of copying
 
2704
        # the history but that's done inside the merge code
 
2705
        if other_branch is not None:
 
2706
            _merge_tags_if_possible(other_branch, tree.branch)
 
2707
 
 
2708
        if path != "":
 
2709
            interesting_files = [path]
 
2710
        else:
 
2711
            interesting_files = None
 
2712
        pb = ui.ui_factory.nested_progress_bar()
 
2713
        try:
 
2714
            try:
 
2715
                conflict_count = _merge_helper(
 
2716
                    other, base, other_rev_id=other_revision_id,
 
2717
                    check_clean=(not force),
 
2718
                    merge_type=merge_type,
 
2719
                    reprocess=reprocess,
 
2720
                    show_base=show_base,
 
2721
                    pull=pull,
 
2722
                    this_dir=directory,
 
2723
                    pb=pb, file_list=interesting_files,
 
2724
                    change_reporter=change_reporter)
 
2725
            finally:
 
2726
                pb.finished()
 
2727
            if conflict_count != 0:
 
2728
                return 1
 
2729
            else:
2944
2730
                return 0
2945
 
            if pull:
2946
 
                if merger.interesting_files is not None:
2947
 
                    raise errors.BzrCommandError('Cannot pull individual files')
2948
 
                if (merger.base_rev_id == tree.last_revision()):
2949
 
                    result = tree.pull(merger.other_branch, False,
2950
 
                                       merger.other_rev_id)
2951
 
                    result.report(self.outf)
2952
 
                    return 0
2953
 
            merger.check_basis(not force)
2954
 
            if preview:
2955
 
                return self._do_preview(merger)
2956
 
            else:
2957
 
                return self._do_merge(merger, change_reporter, allow_pending,
2958
 
                                      verified)
2959
 
        finally:
2960
 
            for cleanup in reversed(cleanups):
2961
 
                cleanup()
2962
 
 
2963
 
    def _do_preview(self, merger):
2964
 
        from bzrlib.diff import show_diff_trees
2965
 
        tree_merger = merger.make_merger()
2966
 
        tt = tree_merger.make_preview_transform()
2967
 
        try:
2968
 
            result_tree = tt.get_preview_tree()
2969
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
2970
 
                            old_label='', new_label='')
2971
 
        finally:
2972
 
            tt.finalize()
2973
 
 
2974
 
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
2975
 
        merger.change_reporter = change_reporter
2976
 
        conflict_count = merger.do_merge()
2977
 
        if allow_pending:
2978
 
            merger.set_pending()
2979
 
        if verified == 'failed':
2980
 
            warning('Preview patch does not match changes')
2981
 
        if conflict_count != 0:
2982
 
            return 1
2983
 
        else:
2984
 
            return 0
2985
 
 
2986
 
    def sanity_check_merger(self, merger):
2987
 
        if (merger.show_base and
2988
 
            not merger.merge_type is _mod_merge.Merge3Merger):
2989
 
            raise errors.BzrCommandError("Show-base is not supported for this"
2990
 
                                         " merge type. %s" % merger.merge_type)
2991
 
        if merger.reprocess and not merger.merge_type.supports_reprocess:
2992
 
            raise errors.BzrCommandError("Conflict reduction is not supported"
2993
 
                                         " for merge type %s." %
2994
 
                                         merger.merge_type)
2995
 
        if merger.reprocess and merger.show_base:
2996
 
            raise errors.BzrCommandError("Cannot do conflict reduction and"
2997
 
                                         " show base.")
2998
 
 
2999
 
    def _get_merger_from_branch(self, tree, location, revision, remember,
3000
 
                                possible_transports, pb):
3001
 
        """Produce a merger from a location, assuming it refers to a branch."""
3002
 
        from bzrlib.tag import _merge_tags_if_possible
3003
 
        # find the branch locations
3004
 
        other_loc, user_location = self._select_branch_location(tree, location,
3005
 
            revision, -1)
3006
 
        if revision is not None and len(revision) == 2:
3007
 
            base_loc, _unused = self._select_branch_location(tree,
3008
 
                location, revision, 0)
3009
 
        else:
3010
 
            base_loc = other_loc
3011
 
        # Open the branches
3012
 
        other_branch, other_path = Branch.open_containing(other_loc,
3013
 
            possible_transports)
3014
 
        if base_loc == other_loc:
3015
 
            base_branch = other_branch
3016
 
        else:
3017
 
            base_branch, base_path = Branch.open_containing(base_loc,
3018
 
                possible_transports)
3019
 
        # Find the revision ids
3020
 
        if revision is None or len(revision) < 1 or revision[-1] is None:
3021
 
            other_revision_id = _mod_revision.ensure_null(
3022
 
                other_branch.last_revision())
3023
 
        else:
3024
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
3025
 
        if (revision is not None and len(revision) == 2
3026
 
            and revision[0] is not None):
3027
 
            base_revision_id = revision[0].as_revision_id(base_branch)
3028
 
        else:
3029
 
            base_revision_id = None
3030
 
        # Remember where we merge from
3031
 
        if ((remember or tree.branch.get_submit_branch() is None) and
3032
 
             user_location is not None):
3033
 
            tree.branch.set_submit_branch(other_branch.base)
3034
 
        _merge_tags_if_possible(other_branch, tree.branch)
3035
 
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3036
 
            other_revision_id, base_revision_id, other_branch, base_branch)
3037
 
        if other_path != '':
3038
 
            allow_pending = False
3039
 
            merger.interesting_files = [other_path]
3040
 
        else:
3041
 
            allow_pending = True
3042
 
        return merger, allow_pending
3043
 
 
3044
 
    def _select_branch_location(self, tree, user_location, revision=None,
3045
 
                                index=None):
3046
 
        """Select a branch location, according to possible inputs.
3047
 
 
3048
 
        If provided, branches from ``revision`` are preferred.  (Both
3049
 
        ``revision`` and ``index`` must be supplied.)
3050
 
 
3051
 
        Otherwise, the ``location`` parameter is used.  If it is None, then the
3052
 
        ``submit`` or ``parent`` location is used, and a note is printed.
3053
 
 
3054
 
        :param tree: The working tree to select a branch for merging into
3055
 
        :param location: The location entered by the user
3056
 
        :param revision: The revision parameter to the command
3057
 
        :param index: The index to use for the revision parameter.  Negative
3058
 
            indices are permitted.
3059
 
        :return: (selected_location, user_location).  The default location
3060
 
            will be the user-entered location.
3061
 
        """
3062
 
        if (revision is not None and index is not None
3063
 
            and revision[index] is not None):
3064
 
            branch = revision[index].get_branch()
3065
 
            if branch is not None:
3066
 
                return branch, branch
3067
 
        if user_location is None:
3068
 
            location = self._get_remembered(tree, 'Merging from')
3069
 
        else:
3070
 
            location = user_location
3071
 
        return location, user_location
3072
 
 
3073
 
    def _get_remembered(self, tree, verb_string):
 
2731
        except errors.AmbiguousBase, e:
 
2732
            m = ("sorry, bzr can't determine the right merge base yet\n"
 
2733
                 "candidates are:\n  "
 
2734
                 + "\n  ".join(e.bases)
 
2735
                 + "\n"
 
2736
                 "please specify an explicit base with -r,\n"
 
2737
                 "and (if you want) report this to the bzr developers\n")
 
2738
            log_error(m)
 
2739
 
 
2740
    # TODO: move up to common parent; this isn't merge-specific anymore. 
 
2741
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
3074
2742
        """Use tree.branch's parent if none was supplied.
3075
2743
 
3076
2744
        Report if the remembered location was used.
3077
2745
        """
3078
 
        stored_location = tree.branch.get_submit_branch()
3079
 
        stored_location_type = "submit"
3080
 
        if stored_location is None:
3081
 
            stored_location = tree.branch.get_parent()
3082
 
            stored_location_type = "parent"
 
2746
        if supplied_location is not None:
 
2747
            return supplied_location
 
2748
        stored_location = tree.branch.get_parent()
3083
2749
        mutter("%s", stored_location)
3084
2750
        if stored_location is None:
3085
2751
            raise errors.BzrCommandError("No location specified or remembered")
3086
 
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
3087
 
        note(u"%s remembered %s location %s", verb_string,
3088
 
                stored_location_type, display_url)
 
2752
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
 
2753
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
3089
2754
        return stored_location
3090
2755
 
3091
2756
 
3100
2765
    merge.  The difference is that remerge can (only) be run when there is a
3101
2766
    pending merge, and it lets you specify particular files.
3102
2767
 
3103
 
    :Examples:
 
2768
    Examples:
 
2769
 
 
2770
    $ bzr remerge --show-base
3104
2771
        Re-do the merge of all conflicted files, and show the base text in
3105
 
        conflict regions, in addition to the usual THIS and OTHER texts::
3106
 
      
3107
 
            bzr remerge --show-base
 
2772
        conflict regions, in addition to the usual THIS and OTHER texts.
3108
2773
 
 
2774
    $ bzr remerge --merge-type weave --reprocess foobar
3109
2775
        Re-do the merge of "foobar", using the weave merge algorithm, with
3110
 
        additional processing to reduce the size of conflict regions::
3111
 
      
3112
 
            bzr remerge --merge-type weave --reprocess foobar
 
2776
        additional processing to reduce the size of conflict regions.
3113
2777
    """
3114
2778
    takes_args = ['file*']
3115
 
    takes_options = [
3116
 
            'merge-type',
3117
 
            'reprocess',
3118
 
            Option('show-base',
3119
 
                   help="Show base revision text in conflicts."),
3120
 
            ]
 
2779
    takes_options = ['merge-type', 'reprocess',
 
2780
                     Option('show-base', help="Show base revision text in "
 
2781
                            "conflicts")]
3121
2782
 
3122
2783
    def run(self, file_list=None, merge_type=None, show_base=False,
3123
2784
            reprocess=False):
3132
2793
                                             " merges.  Not cherrypicking or"
3133
2794
                                             " multi-merges.")
3134
2795
            repository = tree.branch.repository
 
2796
            base_revision = common_ancestor(parents[0],
 
2797
                                            parents[1], repository)
 
2798
            base_tree = repository.revision_tree(base_revision)
 
2799
            other_tree = repository.revision_tree(parents[1])
3135
2800
            interesting_ids = None
3136
2801
            new_conflicts = []
3137
2802
            conflicts = tree.conflicts()
3162
2827
                    restore(tree.abspath(filename))
3163
2828
                except errors.NotConflicted:
3164
2829
                    pass
3165
 
            # Disable pending merges, because the file texts we are remerging
3166
 
            # have not had those merges performed.  If we use the wrong parents
3167
 
            # list, we imply that the working tree text has seen and rejected
3168
 
            # all the changes from the other tree, when in fact those changes
3169
 
            # have not yet been seen.
3170
 
            pb = ui.ui_factory.nested_progress_bar()
3171
 
            tree.set_parent_ids(parents[:1])
3172
 
            try:
3173
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
3174
 
                                                             tree, parents[1])
3175
 
                merger.interesting_ids = interesting_ids
3176
 
                merger.merge_type = merge_type
3177
 
                merger.show_base = show_base
3178
 
                merger.reprocess = reprocess
3179
 
                conflicts = merger.do_merge()
3180
 
            finally:
3181
 
                tree.set_parent_ids(parents)
3182
 
                pb.finished()
 
2830
            conflicts = _mod_merge.merge_inner(
 
2831
                                      tree.branch, other_tree, base_tree,
 
2832
                                      this_tree=tree,
 
2833
                                      interesting_ids=interesting_ids,
 
2834
                                      other_rev_id=parents[1],
 
2835
                                      merge_type=merge_type,
 
2836
                                      show_base=show_base,
 
2837
                                      reprocess=reprocess)
3183
2838
        finally:
3184
2839
            tree.unlock()
3185
2840
        if conflicts > 0:
3196
2851
    last committed revision is used.
3197
2852
 
3198
2853
    To remove only some changes, without reverting to a prior version, use
3199
 
    merge instead.  For example, "merge . --revision -2..-3" will remove the
3200
 
    changes introduced by -2, without affecting the changes introduced by -1.
3201
 
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
2854
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
 
2855
    introduced by -2, without affecting the changes introduced by -1.  Or
 
2856
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
3202
2857
    
3203
2858
    By default, any files that have been manually changed will be backed up
3204
2859
    first.  (Files changed only by merge are not backed up.)  Backup files have
3208
2863
    from the target revision.  So you can use revert to "undelete" a file by
3209
2864
    name.  If you name a directory, all the contents of that directory will be
3210
2865
    reverted.
3211
 
 
3212
 
    Any files that have been newly added since that revision will be deleted,
3213
 
    with a backup kept if appropriate.  Directories containing unknown files
3214
 
    will not be deleted.
3215
 
 
3216
 
    The working tree contains a list of pending merged revisions, which will
3217
 
    be included as parents in the next commit.  Normally, revert clears that
3218
 
    list as well as reverting the files.  If any files are specified, revert
3219
 
    leaves the pending merge list alone and reverts only the files.  Use "bzr
3220
 
    revert ." in the tree root to revert all files but keep the merge record,
3221
 
    and "bzr revert --forget-merges" to clear the pending merge list without
3222
 
    reverting any files.
3223
2866
    """
3224
2867
 
3225
2868
    _see_also = ['cat', 'export']
3226
 
    takes_options = [
3227
 
        'revision',
3228
 
        Option('no-backup', "Do not save backups of reverted files."),
3229
 
        Option('forget-merges',
3230
 
               'Remove pending merge marker, without changing any files.'),
3231
 
        ]
 
2869
    takes_options = ['revision', 'no-backup']
3232
2870
    takes_args = ['file*']
3233
2871
 
3234
 
    def run(self, revision=None, no_backup=False, file_list=None,
3235
 
            forget_merges=None):
 
2872
    def run(self, revision=None, no_backup=False, file_list=None):
 
2873
        if file_list is not None:
 
2874
            if len(file_list) == 0:
 
2875
                raise errors.BzrCommandError("No files specified")
 
2876
        else:
 
2877
            file_list = []
 
2878
        
3236
2879
        tree, file_list = tree_files(file_list)
3237
 
        if forget_merges:
3238
 
            tree.set_parent_ids(tree.get_parent_ids()[:1])
3239
 
        else:
3240
 
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3241
 
 
3242
 
    @staticmethod
3243
 
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
3244
2880
        if revision is None:
 
2881
            # FIXME should be tree.last_revision
3245
2882
            rev_id = tree.last_revision()
3246
2883
        elif len(revision) != 1:
3247
2884
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3248
2885
        else:
3249
 
            rev_id = revision[0].as_revision_id(tree.branch)
 
2886
            rev_id = revision[0].in_history(tree.branch).rev_id
3250
2887
        pb = ui.ui_factory.nested_progress_bar()
3251
2888
        try:
3252
 
            tree.revert(file_list,
 
2889
            tree.revert(file_list, 
3253
2890
                        tree.branch.repository.revision_tree(rev_id),
3254
2891
                        not no_backup, pb, report_changes=True)
3255
2892
        finally:
3271
2908
    """
3272
2909
 
3273
2910
    _see_also = ['topics']
3274
 
    takes_options = [
3275
 
            Option('long', 'Show help on all commands.'),
3276
 
            ]
 
2911
    takes_options = [Option('long', 'show help on all commands')]
3277
2912
    takes_args = ['topic?']
3278
2913
    aliases = ['?', '--help', '-?', '-h']
3279
2914
    
3300
2935
        shellcomplete.shellcomplete(context)
3301
2936
 
3302
2937
 
 
2938
class cmd_fetch(Command):
 
2939
    """Copy in history from another branch but don't merge it.
 
2940
 
 
2941
    This is an internal method used for pull and merge.
 
2942
    """
 
2943
    hidden = True
 
2944
    takes_args = ['from_branch', 'to_branch']
 
2945
    def run(self, from_branch, to_branch):
 
2946
        from bzrlib.fetch import Fetcher
 
2947
        from_b = Branch.open(from_branch)
 
2948
        to_b = Branch.open(to_branch)
 
2949
        Fetcher(to_b, from_b)
 
2950
 
 
2951
 
3303
2952
class cmd_missing(Command):
3304
2953
    """Show unmerged/unpulled revisions between two branches.
3305
 
    
 
2954
 
3306
2955
    OTHER_BRANCH may be local or remote.
3307
2956
    """
3308
2957
 
3309
2958
    _see_also = ['merge', 'pull']
3310
2959
    takes_args = ['other_branch?']
3311
 
    takes_options = [
3312
 
            Option('reverse', 'Reverse the order of revisions.'),
3313
 
            Option('mine-only',
3314
 
                   'Display changes in the local branch only.'),
3315
 
            Option('this' , 'Same as --mine-only.'),
3316
 
            Option('theirs-only',
3317
 
                   'Display changes in the remote branch only.'),
3318
 
            Option('other', 'Same as --theirs-only.'),
3319
 
            'log-format',
3320
 
            'show-ids',
3321
 
            'verbose'
3322
 
            ]
 
2960
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
 
2961
                     Option('mine-only', 
 
2962
                            'Display changes in the local branch only'),
 
2963
                     Option('theirs-only', 
 
2964
                            'Display changes in the remote branch only'), 
 
2965
                     'log-format',
 
2966
                     'show-ids',
 
2967
                     'verbose'
 
2968
                     ]
3323
2969
    encoding_type = 'replace'
3324
2970
 
3325
2971
    @display_command
3326
2972
    def run(self, other_branch=None, reverse=False, mine_only=False,
3327
2973
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
3328
 
            show_ids=False, verbose=False, this=False, other=False):
3329
 
        from bzrlib.missing import find_unmerged, iter_log_revisions
3330
 
 
3331
 
        if this:
3332
 
            mine_only = this
3333
 
        if other:
3334
 
            theirs_only = other
3335
 
        # TODO: We should probably check that we don't have mine-only and
3336
 
        #       theirs-only set, but it gets complicated because we also have
3337
 
        #       this and other which could be used.
3338
 
        restrict = 'all'
3339
 
        if mine_only:
3340
 
            restrict = 'local'
3341
 
        elif theirs_only:
3342
 
            restrict = 'remote'
3343
 
 
 
2974
            show_ids=False, verbose=False):
 
2975
        from bzrlib.missing import find_unmerged, iter_log_data
 
2976
        from bzrlib.log import log_formatter
3344
2977
        local_branch = Branch.open_containing(u".")[0]
3345
2978
        parent = local_branch.get_parent()
3346
2979
        if other_branch is None:
3347
2980
            other_branch = parent
3348
2981
            if other_branch is None:
3349
 
                raise errors.BzrCommandError("No peer location known"
3350
 
                                             " or specified.")
 
2982
                raise errors.BzrCommandError("No peer location known or specified.")
3351
2983
            display_url = urlutils.unescape_for_display(parent,
3352
2984
                                                        self.outf.encoding)
3353
 
            self.outf.write("Using saved parent location: "
3354
 
                    + display_url + "\n")
 
2985
            print "Using last location: " + display_url
3355
2986
 
3356
2987
        remote_branch = Branch.open(other_branch)
3357
2988
        if remote_branch.base == local_branch.base:
3360
2991
        try:
3361
2992
            remote_branch.lock_read()
3362
2993
            try:
3363
 
                local_extra, remote_extra = find_unmerged(
3364
 
                    local_branch, remote_branch, restrict)
3365
 
 
3366
 
                if log_format is None:
3367
 
                    registry = log.log_formatter_registry
3368
 
                    log_format = registry.get_default(local_branch)
 
2994
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
 
2995
                if (log_format is None):
 
2996
                    log_format = log.log_formatter_registry.get_default(
 
2997
                        local_branch)
3369
2998
                lf = log_format(to_file=self.outf,
3370
2999
                                show_ids=show_ids,
3371
3000
                                show_timezone='original')
3372
3001
                if reverse is False:
3373
 
                    if local_extra is not None:
3374
 
                        local_extra.reverse()
3375
 
                    if remote_extra is not None:
3376
 
                        remote_extra.reverse()
3377
 
 
3378
 
                status_code = 0
 
3002
                    local_extra.reverse()
 
3003
                    remote_extra.reverse()
3379
3004
                if local_extra and not theirs_only:
3380
 
                    self.outf.write("You have %d extra revision(s):\n" %
3381
 
                                    len(local_extra))
3382
 
                    for revision in iter_log_revisions(local_extra,
3383
 
                                        local_branch.repository,
3384
 
                                        verbose):
3385
 
                        lf.log_revision(revision)
 
3005
                    print "You have %d extra revision(s):" % len(local_extra)
 
3006
                    for data in iter_log_data(local_extra, local_branch.repository,
 
3007
                                              verbose):
 
3008
                        lf.show(*data)
3386
3009
                    printed_local = True
3387
 
                    status_code = 1
3388
3010
                else:
3389
3011
                    printed_local = False
3390
 
 
3391
3012
                if remote_extra and not mine_only:
3392
3013
                    if printed_local is True:
3393
 
                        self.outf.write("\n\n\n")
3394
 
                    self.outf.write("You are missing %d revision(s):\n" %
3395
 
                                    len(remote_extra))
3396
 
                    for revision in iter_log_revisions(remote_extra,
3397
 
                                        remote_branch.repository,
3398
 
                                        verbose):
3399
 
                        lf.log_revision(revision)
 
3014
                        print "\n\n"
 
3015
                    print "You are missing %d revision(s):" % len(remote_extra)
 
3016
                    for data in iter_log_data(remote_extra, remote_branch.repository, 
 
3017
                                              verbose):
 
3018
                        lf.show(*data)
 
3019
                if not remote_extra and not local_extra:
 
3020
                    status_code = 0
 
3021
                    print "Branches are up to date."
 
3022
                else:
3400
3023
                    status_code = 1
3401
 
 
3402
 
                if mine_only and not local_extra:
3403
 
                    # We checked local, and found nothing extra
3404
 
                    self.outf.write('This branch is up to date.\n')
3405
 
                elif theirs_only and not remote_extra:
3406
 
                    # We checked remote, and found nothing extra
3407
 
                    self.outf.write('Other branch is up to date.\n')
3408
 
                elif not (mine_only or theirs_only or local_extra or
3409
 
                          remote_extra):
3410
 
                    # We checked both branches, and neither one had extra
3411
 
                    # revisions
3412
 
                    self.outf.write("Branches are up to date.\n")
3413
3024
            finally:
3414
3025
                remote_branch.unlock()
3415
3026
        finally:
3425
3036
        return status_code
3426
3037
 
3427
3038
 
3428
 
class cmd_pack(Command):
3429
 
    """Compress the data within a repository."""
3430
 
 
3431
 
    _see_also = ['repositories']
3432
 
    takes_args = ['branch_or_repo?']
3433
 
 
3434
 
    def run(self, branch_or_repo='.'):
3435
 
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
3436
 
        try:
3437
 
            branch = dir.open_branch()
3438
 
            repository = branch.repository
3439
 
        except errors.NotBranchError:
3440
 
            repository = dir.open_repository()
3441
 
        repository.pack()
3442
 
 
3443
 
 
3444
3039
class cmd_plugins(Command):
3445
 
    """List the installed plugins.
3446
 
    
3447
 
    This command displays the list of installed plugins including
3448
 
    version of plugin and a short description of each.
3449
 
 
3450
 
    --verbose shows the path where each plugin is located.
3451
 
 
3452
 
    A plugin is an external component for Bazaar that extends the
3453
 
    revision control system, by adding or replacing code in Bazaar.
3454
 
    Plugins can do a variety of things, including overriding commands,
3455
 
    adding new commands, providing additional network transports and
3456
 
    customizing log output.
3457
 
 
3458
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
3459
 
    information on plugins including where to find them and how to
3460
 
    install them. Instructions are also provided there on how to
3461
 
    write new plugins using the Python programming language.
3462
 
    """
3463
 
    takes_options = ['verbose']
3464
 
 
 
3040
    """List plugins"""
 
3041
    hidden = True
3465
3042
    @display_command
3466
 
    def run(self, verbose=False):
 
3043
    def run(self):
3467
3044
        import bzrlib.plugin
3468
3045
        from inspect import getdoc
3469
 
        result = []
3470
 
        for name, plugin in bzrlib.plugin.plugins().items():
3471
 
            version = plugin.__version__
3472
 
            if version == 'unknown':
3473
 
                version = ''
3474
 
            name_ver = '%s %s' % (name, version)
3475
 
            d = getdoc(plugin.module)
 
3046
        for name, plugin in bzrlib.plugin.all_plugins().items():
 
3047
            if getattr(plugin, '__path__', None) is not None:
 
3048
                print plugin.__path__[0]
 
3049
            elif getattr(plugin, '__file__', None) is not None:
 
3050
                print plugin.__file__
 
3051
            else:
 
3052
                print repr(plugin)
 
3053
                
 
3054
            d = getdoc(plugin)
3476
3055
            if d:
3477
 
                doc = d.split('\n')[0]
3478
 
            else:
3479
 
                doc = '(no description)'
3480
 
            result.append((name_ver, doc, plugin.path()))
3481
 
        for name_ver, doc, path in sorted(result):
3482
 
            print name_ver
3483
 
            print '   ', doc
3484
 
            if verbose:
3485
 
                print '   ', path
3486
 
            print
 
3056
                print '\t', d.split('\n')[0]
3487
3057
 
3488
3058
 
3489
3059
class cmd_testament(Command):
3490
3060
    """Show testament (signing-form) of a revision."""
3491
 
    takes_options = [
3492
 
            'revision',
3493
 
            Option('long', help='Produce long-format testament.'),
3494
 
            Option('strict',
3495
 
                   help='Produce a strict-format testament.')]
 
3061
    takes_options = ['revision',
 
3062
                     Option('long', help='Produce long-format testament'), 
 
3063
                     Option('strict', help='Produce a strict-format'
 
3064
                            ' testament')]
3496
3065
    takes_args = ['branch?']
3497
3066
    @display_command
3498
3067
    def run(self, branch=u'.', revision=None, long=False, strict=False):
3501
3070
            testament_class = StrictTestament
3502
3071
        else:
3503
3072
            testament_class = Testament
3504
 
        if branch == '.':
3505
 
            b = Branch.open_containing(branch)[0]
3506
 
        else:
3507
 
            b = Branch.open(branch)
 
3073
        b = WorkingTree.open_containing(branch)[0].branch
3508
3074
        b.lock_read()
3509
3075
        try:
3510
3076
            if revision is None:
3511
3077
                rev_id = b.last_revision()
3512
3078
            else:
3513
 
                rev_id = revision[0].as_revision_id(b)
 
3079
                rev_id = revision[0].in_history(b).rev_id
3514
3080
            t = testament_class.from_revision(b.repository, rev_id)
3515
3081
            if long:
3516
3082
                sys.stdout.writelines(t.as_text_lines())
3534
3100
    #       with new uncommitted lines marked
3535
3101
    aliases = ['ann', 'blame', 'praise']
3536
3102
    takes_args = ['filename']
3537
 
    takes_options = [Option('all', help='Show annotations on all lines.'),
3538
 
                     Option('long', help='Show commit date in annotations.'),
 
3103
    takes_options = [Option('all', help='show annotations on all lines'),
 
3104
                     Option('long', help='show date in annotations'),
3539
3105
                     'revision',
3540
3106
                     'show-ids',
3541
3107
                     ]
3542
 
    encoding_type = 'exact'
3543
3108
 
3544
3109
    @display_command
3545
3110
    def run(self, filename, all=False, long=False, revision=None,
3546
3111
            show_ids=False):
3547
3112
        from bzrlib.annotate import annotate_file
3548
 
        wt, branch, relpath = \
3549
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
3550
 
        if wt is not None:
3551
 
            wt.lock_read()
3552
 
        else:
3553
 
            branch.lock_read()
 
3113
        tree, relpath = WorkingTree.open_containing(filename)
 
3114
        branch = tree.branch
 
3115
        branch.lock_read()
3554
3116
        try:
3555
3117
            if revision is None:
3556
3118
                revision_id = branch.last_revision()
3557
3119
            elif len(revision) != 1:
3558
3120
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3559
3121
            else:
3560
 
                revision_id = revision[0].as_revision_id(branch)
 
3122
                revision_id = revision[0].in_history(branch).rev_id
 
3123
            file_id = tree.path2id(relpath)
3561
3124
            tree = branch.repository.revision_tree(revision_id)
3562
 
            if wt is not None:
3563
 
                file_id = wt.path2id(relpath)
3564
 
            else:
3565
 
                file_id = tree.path2id(relpath)
3566
 
            if file_id is None:
3567
 
                raise errors.NotVersionedError(filename)
3568
3125
            file_version = tree.inventory[file_id].revision
3569
 
            annotate_file(branch, file_version, file_id, long, all, self.outf,
 
3126
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
3570
3127
                          show_ids=show_ids)
3571
3128
        finally:
3572
 
            if wt is not None:
3573
 
                wt.unlock()
3574
 
            else:
3575
 
                branch.unlock()
 
3129
            branch.unlock()
3576
3130
 
3577
3131
 
3578
3132
class cmd_re_sign(Command):
3584
3138
    takes_options = ['revision']
3585
3139
    
3586
3140
    def run(self, revision_id_list=None, revision=None):
 
3141
        import bzrlib.gpg as gpg
3587
3142
        if revision_id_list is not None and revision is not None:
3588
3143
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3589
3144
        if revision_id_list is None and revision is None:
3590
3145
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3591
3146
        b = WorkingTree.open_containing(u'.')[0].branch
3592
 
        b.lock_write()
3593
 
        try:
3594
 
            return self._run(b, revision_id_list, revision)
3595
 
        finally:
3596
 
            b.unlock()
3597
 
 
3598
 
    def _run(self, b, revision_id_list, revision):
3599
 
        import bzrlib.gpg as gpg
3600
3147
        gpg_strategy = gpg.GPGStrategy(b.get_config())
3601
3148
        if revision_id_list is not None:
3602
 
            b.repository.start_write_group()
3603
 
            try:
3604
 
                for revision_id in revision_id_list:
3605
 
                    b.repository.sign_revision(revision_id, gpg_strategy)
3606
 
            except:
3607
 
                b.repository.abort_write_group()
3608
 
                raise
3609
 
            else:
3610
 
                b.repository.commit_write_group()
 
3149
            for revision_id in revision_id_list:
 
3150
                b.repository.sign_revision(revision_id, gpg_strategy)
3611
3151
        elif revision is not None:
3612
3152
            if len(revision) == 1:
3613
3153
                revno, rev_id = revision[0].in_history(b)
3614
 
                b.repository.start_write_group()
3615
 
                try:
3616
 
                    b.repository.sign_revision(rev_id, gpg_strategy)
3617
 
                except:
3618
 
                    b.repository.abort_write_group()
3619
 
                    raise
3620
 
                else:
3621
 
                    b.repository.commit_write_group()
 
3154
                b.repository.sign_revision(rev_id, gpg_strategy)
3622
3155
            elif len(revision) == 2:
3623
3156
                # are they both on rh- if so we can walk between them
3624
3157
                # might be nice to have a range helper for arbitrary
3629
3162
                    to_revno = b.revno()
3630
3163
                if from_revno is None or to_revno is None:
3631
3164
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
3632
 
                b.repository.start_write_group()
3633
 
                try:
3634
 
                    for revno in range(from_revno, to_revno + 1):
3635
 
                        b.repository.sign_revision(b.get_rev_id(revno),
3636
 
                                                   gpg_strategy)
3637
 
                except:
3638
 
                    b.repository.abort_write_group()
3639
 
                    raise
3640
 
                else:
3641
 
                    b.repository.commit_write_group()
 
3165
                for revno in range(from_revno, to_revno + 1):
 
3166
                    b.repository.sign_revision(b.get_rev_id(revno), 
 
3167
                                               gpg_strategy)
3642
3168
            else:
3643
3169
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
3644
3170
 
3697
3223
    --verbose will print out what is being removed.
3698
3224
    --dry-run will go through all the motions, but not actually
3699
3225
    remove anything.
3700
 
 
3701
 
    If --revision is specified, uncommit revisions to leave the branch at the
3702
 
    specified revision.  For example, "bzr uncommit -r 15" will leave the
3703
 
    branch at revision 15.
3704
 
 
3705
 
    Uncommit leaves the working tree ready for a new commit.  The only change
3706
 
    it may make is to restore any pending merges that were present before
3707
 
    the commit.
 
3226
    
 
3227
    In the future, uncommit will create a revision bundle, which can then
 
3228
    be re-applied.
3708
3229
    """
3709
3230
 
3710
3231
    # TODO: jam 20060108 Add an option to allow uncommit to remove
3713
3234
    # information in shared branches as well.
3714
3235
    _see_also = ['commit']
3715
3236
    takes_options = ['verbose', 'revision',
3716
 
                    Option('dry-run', help='Don\'t actually make changes.'),
3717
 
                    Option('force', help='Say yes to all questions.'),
3718
 
                    Option('local',
3719
 
                           help="Only remove the commits from the local branch"
3720
 
                                " when in a checkout."
3721
 
                           ),
3722
 
                    ]
 
3237
                    Option('dry-run', help='Don\'t actually make changes'),
 
3238
                    Option('force', help='Say yes to all questions.')]
3723
3239
    takes_args = ['location?']
3724
3240
    aliases = []
3725
 
    encoding_type = 'replace'
3726
3241
 
3727
3242
    def run(self, location=None,
3728
3243
            dry_run=False, verbose=False,
3729
 
            revision=None, force=False, local=False):
 
3244
            revision=None, force=False):
 
3245
        from bzrlib.log import log_formatter, show_log
 
3246
        import sys
 
3247
        from bzrlib.uncommit import uncommit
 
3248
 
3730
3249
        if location is None:
3731
3250
            location = u'.'
3732
3251
        control, relpath = bzrdir.BzrDir.open_containing(location)
3737
3256
            tree = None
3738
3257
            b = control.open_branch()
3739
3258
 
3740
 
        if tree is not None:
3741
 
            tree.lock_write()
3742
 
        else:
3743
 
            b.lock_write()
3744
 
        try:
3745
 
            return self._run(b, tree, dry_run, verbose, revision, force,
3746
 
                             local=local)
3747
 
        finally:
3748
 
            if tree is not None:
3749
 
                tree.unlock()
3750
 
            else:
3751
 
                b.unlock()
3752
 
 
3753
 
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
3754
 
        from bzrlib.log import log_formatter, show_log
3755
 
        from bzrlib.uncommit import uncommit
3756
 
 
3757
 
        last_revno, last_rev_id = b.last_revision_info()
3758
 
 
3759
3259
        rev_id = None
3760
3260
        if revision is None:
3761
 
            revno = last_revno
3762
 
            rev_id = last_rev_id
 
3261
            revno = b.revno()
3763
3262
        else:
3764
3263
            # 'bzr uncommit -r 10' actually means uncommit
3765
3264
            # so that the final tree is at revno 10.
3766
3265
            # but bzrlib.uncommit.uncommit() actually uncommits
3767
3266
            # the revisions that are supplied.
3768
3267
            # So we need to offset it by one
3769
 
            revno = revision[0].in_history(b).revno + 1
3770
 
            if revno <= last_revno:
3771
 
                rev_id = b.get_rev_id(revno)
 
3268
            revno = revision[0].in_history(b).revno+1
3772
3269
 
3773
 
        if rev_id is None or _mod_revision.is_null(rev_id):
 
3270
        if revno <= b.revno():
 
3271
            rev_id = b.get_rev_id(revno)
 
3272
        if rev_id is None:
3774
3273
            self.outf.write('No revisions to uncommit.\n')
3775
3274
            return 1
3776
3275
 
3783
3282
                 verbose=False,
3784
3283
                 direction='forward',
3785
3284
                 start_revision=revno,
3786
 
                 end_revision=last_revno)
 
3285
                 end_revision=b.revno())
3787
3286
 
3788
3287
        if dry_run:
3789
3288
            print 'Dry-run, pretending to remove the above revisions.'
3797
3296
                    print 'Canceled'
3798
3297
                    return 0
3799
3298
 
3800
 
        mutter('Uncommitting from {%s} to {%s}',
3801
 
               last_rev_id, rev_id)
3802
3299
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3803
 
                 revno=revno, local=local)
3804
 
        note('You can restore the old tip by running:\n'
3805
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
3300
                revno=revno)
3806
3301
 
3807
3302
 
3808
3303
class cmd_break_lock(Command):
3813
3308
 
3814
3309
    You can get information on what locks are open via the 'bzr info' command.
3815
3310
    
3816
 
    :Examples:
 
3311
    example:
3817
3312
        bzr break-lock
3818
3313
    """
3819
3314
    takes_args = ['location?']
3849
3344
 
3850
3345
    takes_options = [
3851
3346
        Option('inet',
3852
 
               help='Serve on stdin/out for use from inetd or sshd.'),
 
3347
               help='serve on stdin/out for use from inetd or sshd'),
3853
3348
        Option('port',
3854
 
               help='Listen for connections on nominated port of the form '
3855
 
                    '[hostname:]portnumber.  Passing 0 as the port number will '
3856
 
                    'result in a dynamically allocated port.  The default port is '
 
3349
               help='listen for connections on nominated port of the form '
 
3350
                    '[hostname:]portnumber. Passing 0 as the port number will '
 
3351
                    'result in a dynamically allocated port. Default port is '
3857
3352
                    '4155.',
3858
3353
               type=str),
3859
3354
        Option('directory',
3860
 
               help='Serve contents of this directory.',
 
3355
               help='serve contents of directory',
3861
3356
               type=unicode),
3862
3357
        Option('allow-writes',
3863
 
               help='By default the server is a readonly server.  Supplying '
 
3358
               help='By default the server is a readonly server. Supplying '
3864
3359
                    '--allow-writes enables write access to the contents of '
3865
 
                    'the served directory and below.'
 
3360
                    'the served directory and below. '
3866
3361
                ),
3867
3362
        ]
3868
3363
 
3869
3364
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
3870
 
        from bzrlib import lockdir
3871
3365
        from bzrlib.smart import medium, server
3872
3366
        from bzrlib.transport import get_transport
3873
3367
        from bzrlib.transport.chroot import ChrootServer
 
3368
        from bzrlib.transport.remote import BZR_DEFAULT_PORT, BZR_DEFAULT_INTERFACE
3874
3369
        if directory is None:
3875
3370
            directory = os.getcwd()
3876
3371
        url = urlutils.local_path_to_url(directory)
3883
3378
            smart_server = medium.SmartServerPipeStreamMedium(
3884
3379
                sys.stdin, sys.stdout, t)
3885
3380
        else:
3886
 
            host = medium.BZR_DEFAULT_INTERFACE
 
3381
            host = BZR_DEFAULT_INTERFACE
3887
3382
            if port is None:
3888
 
                port = medium.BZR_DEFAULT_PORT
 
3383
                port = BZR_DEFAULT_PORT
3889
3384
            else:
3890
3385
                if ':' in port:
3891
3386
                    host, port = port.split(':')
3898
3393
        # be changed with care though, as we dont want to use bandwidth sending
3899
3394
        # progress over stderr to smart server clients!
3900
3395
        old_factory = ui.ui_factory
3901
 
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
3902
3396
        try:
3903
3397
            ui.ui_factory = ui.SilentUIFactory()
3904
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
3905
3398
            smart_server.serve()
3906
3399
        finally:
3907
3400
            ui.ui_factory = old_factory
3908
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
3909
3401
 
3910
3402
 
3911
3403
class cmd_join(Command):
3931
3423
 
3932
3424
    _see_also = ['split']
3933
3425
    takes_args = ['tree']
3934
 
    takes_options = [
3935
 
            Option('reference', help='Join by reference.'),
3936
 
            ]
 
3426
    takes_options = [Option('reference', 'join by reference')]
3937
3427
    hidden = True
3938
3428
 
3939
3429
    def run(self, tree, reference=False):
3963
3453
 
3964
3454
 
3965
3455
class cmd_split(Command):
3966
 
    """Split a subdirectory of a tree into a separate tree.
 
3456
    """Split a tree into two trees.
3967
3457
 
3968
 
    This command will produce a target tree in a format that supports
3969
 
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
3970
 
    converted into earlier formats like 'dirstate-tags'.
 
3458
    This command is for experimental use only.  It requires the target tree
 
3459
    to be in dirstate-with-subtree format, which cannot be converted into
 
3460
    earlier formats.
3971
3461
 
3972
3462
    The TREE argument should be a subdirectory of a working tree.  That
3973
3463
    subdirectory will be converted into an independent tree, with its own
3974
3464
    branch.  Commits in the top-level tree will not apply to the new subtree.
 
3465
    If you want that behavior, do "bzr join --reference TREE".
3975
3466
    """
3976
3467
 
3977
 
    # join is not un-hidden yet
3978
 
    #_see_also = ['join']
 
3468
    _see_also = ['join']
3979
3469
    takes_args = ['tree']
3980
3470
 
 
3471
    hidden = True
 
3472
 
3981
3473
    def run(self, tree):
3982
3474
        containing_tree, subdir = WorkingTree.open_containing(tree)
3983
3475
        sub_id = containing_tree.path2id(subdir)
3989
3481
            raise errors.UpgradeRequired(containing_tree.branch.base)
3990
3482
 
3991
3483
 
 
3484
 
3992
3485
class cmd_merge_directive(Command):
3993
3486
    """Generate a merge directive for auto-merge tools.
3994
3487
 
4008
3501
 
4009
3502
    takes_args = ['submit_branch?', 'public_branch?']
4010
3503
 
4011
 
    hidden = True
4012
 
 
4013
 
    _see_also = ['send']
4014
 
 
4015
3504
    takes_options = [
4016
3505
        RegistryOption.from_kwargs('patch-type',
4017
 
            'The type of patch to include in the directive.',
4018
 
            title='Patch type',
4019
 
            value_switches=True,
4020
 
            enum_switch=False,
4021
 
            bundle='Bazaar revision bundle (default).',
4022
 
            diff='Normal unified diff.',
4023
 
            plain='No patch, just directive.'),
4024
 
        Option('sign', help='GPG-sign the directive.'), 'revision',
 
3506
            'The type of patch to include in the directive',
 
3507
            title='Patch type', value_switches=True, enum_switch=False,
 
3508
            bundle='Bazaar revision bundle (default)',
 
3509
            diff='Normal unified diff',
 
3510
            plain='No patch, just directive'),
 
3511
        Option('sign', help='GPG-sign the directive'), 'revision',
4025
3512
        Option('mail-to', type=str,
4026
 
            help='Instead of printing the directive, email to this address.'),
 
3513
            help='Instead of printing the directive, email to this address'),
4027
3514
        Option('message', type=str, short_name='m',
4028
 
            help='Message to use when committing this merge.')
 
3515
            help='Message to use when committing this merge')
4029
3516
        ]
4030
3517
 
4031
 
    encoding_type = 'exact'
4032
 
 
4033
3518
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
4034
3519
            sign=False, revision=None, mail_to=None, message=None):
4035
 
        from bzrlib.revision import ensure_null, NULL_REVISION
4036
 
        include_patch, include_bundle = {
4037
 
            'plain': (False, False),
4038
 
            'diff': (True, False),
4039
 
            'bundle': (True, True),
4040
 
            }[patch_type]
 
3520
        if patch_type == 'plain':
 
3521
            patch_type = None
4041
3522
        branch = Branch.open('.')
4042
3523
        stored_submit_branch = branch.get_submit_branch()
4043
3524
        if submit_branch is None:
4055
3536
            public_branch = stored_public_branch
4056
3537
        elif stored_public_branch is None:
4057
3538
            branch.set_public_branch(public_branch)
4058
 
        if not include_bundle and public_branch is None:
 
3539
        if patch_type != "bundle" and public_branch is None:
4059
3540
            raise errors.BzrCommandError('No public branch specified or'
4060
3541
                                         ' known')
4061
 
        base_revision_id = None
4062
3542
        if revision is not None:
4063
 
            if len(revision) > 2:
 
3543
            if len(revision) != 1:
4064
3544
                raise errors.BzrCommandError('bzr merge-directive takes '
4065
 
                    'at most two one revision identifiers')
4066
 
            revision_id = revision[-1].as_revision_id(branch)
4067
 
            if len(revision) == 2:
4068
 
                base_revision_id = revision[0].as_revision_id(branch)
 
3545
                    'exactly one revision identifier')
 
3546
            else:
 
3547
                revision_id = revision[0].in_history(branch).rev_id
4069
3548
        else:
4070
3549
            revision_id = branch.last_revision()
4071
 
        revision_id = ensure_null(revision_id)
4072
 
        if revision_id == NULL_REVISION:
4073
 
            raise errors.BzrCommandError('No revisions to bundle.')
4074
 
        directive = merge_directive.MergeDirective2.from_objects(
 
3550
        directive = merge_directive.MergeDirective.from_objects(
4075
3551
            branch.repository, revision_id, time.time(),
4076
3552
            osutils.local_time_offset(), submit_branch,
4077
 
            public_branch=public_branch, include_patch=include_patch,
4078
 
            include_bundle=include_bundle, message=message,
4079
 
            base_revision_id=base_revision_id)
 
3553
            public_branch=public_branch, patch_type=patch_type,
 
3554
            message=message)
4080
3555
        if mail_to is None:
4081
3556
            if sign:
4082
3557
                self.outf.write(directive.to_signed(branch))
4084
3559
                self.outf.writelines(directive.to_lines())
4085
3560
        else:
4086
3561
            message = directive.to_email(mail_to, branch, sign)
4087
 
            s = SMTPConnection(branch.get_config())
4088
 
            s.send_email(message)
4089
 
 
4090
 
 
4091
 
class cmd_send(Command):
4092
 
    """Mail or create a merge-directive for submiting changes.
4093
 
 
4094
 
    A merge directive provides many things needed for requesting merges:
4095
 
 
4096
 
    * A machine-readable description of the merge to perform
4097
 
 
4098
 
    * An optional patch that is a preview of the changes requested
4099
 
 
4100
 
    * An optional bundle of revision data, so that the changes can be applied
4101
 
      directly from the merge directive, without retrieving data from a
4102
 
      branch.
4103
 
 
4104
 
    If --no-bundle is specified, then public_branch is needed (and must be
4105
 
    up-to-date), so that the receiver can perform the merge using the
4106
 
    public_branch.  The public_branch is always included if known, so that
4107
 
    people can check it later.
4108
 
 
4109
 
    The submit branch defaults to the parent, but can be overridden.  Both
4110
 
    submit branch and public branch will be remembered if supplied.
4111
 
 
4112
 
    If a public_branch is known for the submit_branch, that public submit
4113
 
    branch is used in the merge instructions.  This means that a local mirror
4114
 
    can be used as your actual submit branch, once you have set public_branch
4115
 
    for that mirror.
4116
 
 
4117
 
    Mail is sent using your preferred mail program.  This should be transparent
4118
 
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
4119
 
    If the preferred client can't be found (or used), your editor will be used.
4120
 
    
4121
 
    To use a specific mail program, set the mail_client configuration option.
4122
 
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4123
 
    specific clients are "evolution", "kmail", "mutt", and "thunderbird";
4124
 
    generic options are "default", "editor", "emacsclient", "mapi", and
4125
 
    "xdg-email".  Plugins may also add supported clients.
4126
 
 
4127
 
    If mail is being sent, a to address is required.  This can be supplied
4128
 
    either on the commandline, by setting the submit_to configuration
4129
 
    option in the branch itself or the child_submit_to configuration option 
4130
 
    in the submit branch.
4131
 
 
4132
 
    Two formats are currently supported: "4" uses revision bundle format 4 and
4133
 
    merge directive format 2.  It is significantly faster and smaller than
4134
 
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4135
 
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4136
 
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
4137
 
    
4138
 
    Merge directives are applied using the merge command or the pull command.
4139
 
    """
4140
 
 
4141
 
    encoding_type = 'exact'
4142
 
 
4143
 
    _see_also = ['merge', 'pull']
4144
 
 
4145
 
    takes_args = ['submit_branch?', 'public_branch?']
4146
 
 
4147
 
    takes_options = [
4148
 
        Option('no-bundle',
4149
 
               help='Do not include a bundle in the merge directive.'),
4150
 
        Option('no-patch', help='Do not include a preview patch in the merge'
4151
 
               ' directive.'),
4152
 
        Option('remember',
4153
 
               help='Remember submit and public branch.'),
4154
 
        Option('from',
4155
 
               help='Branch to generate the submission from, '
4156
 
               'rather than the one containing the working directory.',
4157
 
               short_name='f',
4158
 
               type=unicode),
4159
 
        Option('output', short_name='o',
4160
 
               help='Write merge directive to this file; '
4161
 
                    'use - for stdout.',
4162
 
               type=unicode),
4163
 
        Option('mail-to', help='Mail the request to this address.',
4164
 
               type=unicode),
4165
 
        'revision',
4166
 
        'message',
4167
 
        RegistryOption.from_kwargs('format',
4168
 
        'Use the specified output format.',
4169
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4170
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
4171
 
        ]
4172
 
 
4173
 
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4174
 
            no_patch=False, revision=None, remember=False, output=None,
4175
 
            format='4', mail_to=None, message=None, **kwargs):
4176
 
        return self._run(submit_branch, revision, public_branch, remember,
4177
 
                         format, no_bundle, no_patch, output,
4178
 
                         kwargs.get('from', '.'), mail_to, message)
4179
 
 
4180
 
    def _run(self, submit_branch, revision, public_branch, remember, format,
4181
 
             no_bundle, no_patch, output, from_, mail_to, message):
4182
 
        from bzrlib.revision import NULL_REVISION
4183
 
        branch = Branch.open_containing(from_)[0]
4184
 
        if output is None:
4185
 
            outfile = StringIO()
4186
 
        elif output == '-':
4187
 
            outfile = self.outf
4188
 
        else:
4189
 
            outfile = open(output, 'wb')
4190
 
        # we may need to write data into branch's repository to calculate
4191
 
        # the data to send.
4192
 
        branch.lock_write()
4193
 
        try:
4194
 
            if output is None:
4195
 
                config = branch.get_config()
4196
 
                if mail_to is None:
4197
 
                    mail_to = config.get_user_option('submit_to')
4198
 
                mail_client = config.get_mail_client()
4199
 
            if remember and submit_branch is None:
4200
 
                raise errors.BzrCommandError(
4201
 
                    '--remember requires a branch to be specified.')
4202
 
            stored_submit_branch = branch.get_submit_branch()
4203
 
            remembered_submit_branch = None
4204
 
            if submit_branch is None:
4205
 
                submit_branch = stored_submit_branch
4206
 
                remembered_submit_branch = "submit"
4207
 
            else:
4208
 
                if stored_submit_branch is None or remember:
4209
 
                    branch.set_submit_branch(submit_branch)
4210
 
            if submit_branch is None:
4211
 
                submit_branch = branch.get_parent()
4212
 
                remembered_submit_branch = "parent"
4213
 
            if submit_branch is None:
4214
 
                raise errors.BzrCommandError('No submit branch known or'
4215
 
                                             ' specified')
4216
 
            if remembered_submit_branch is not None:
4217
 
                note('Using saved %s location "%s" to determine what '
4218
 
                        'changes to submit.', remembered_submit_branch,
4219
 
                        submit_branch)
4220
 
 
4221
 
            if mail_to is None:
4222
 
                submit_config = Branch.open(submit_branch).get_config()
4223
 
                mail_to = submit_config.get_user_option("child_submit_to")
4224
 
 
4225
 
            stored_public_branch = branch.get_public_branch()
4226
 
            if public_branch is None:
4227
 
                public_branch = stored_public_branch
4228
 
            elif stored_public_branch is None or remember:
4229
 
                branch.set_public_branch(public_branch)
4230
 
            if no_bundle and public_branch is None:
4231
 
                raise errors.BzrCommandError('No public branch specified or'
4232
 
                                             ' known')
4233
 
            base_revision_id = None
4234
 
            revision_id = None
4235
 
            if revision is not None:
4236
 
                if len(revision) > 2:
4237
 
                    raise errors.BzrCommandError('bzr send takes '
4238
 
                        'at most two one revision identifiers')
4239
 
                revision_id = revision[-1].as_revision_id(branch)
4240
 
                if len(revision) == 2:
4241
 
                    base_revision_id = revision[0].as_revision_id(branch)
4242
 
            if revision_id is None:
4243
 
                revision_id = branch.last_revision()
4244
 
            if revision_id == NULL_REVISION:
4245
 
                raise errors.BzrCommandError('No revisions to submit.')
4246
 
            if format == '4':
4247
 
                directive = merge_directive.MergeDirective2.from_objects(
4248
 
                    branch.repository, revision_id, time.time(),
4249
 
                    osutils.local_time_offset(), submit_branch,
4250
 
                    public_branch=public_branch, include_patch=not no_patch,
4251
 
                    include_bundle=not no_bundle, message=message,
4252
 
                    base_revision_id=base_revision_id)
4253
 
            elif format == '0.9':
4254
 
                if not no_bundle:
4255
 
                    if not no_patch:
4256
 
                        patch_type = 'bundle'
4257
 
                    else:
4258
 
                        raise errors.BzrCommandError('Format 0.9 does not'
4259
 
                            ' permit bundle with no patch')
4260
 
                else:
4261
 
                    if not no_patch:
4262
 
                        patch_type = 'diff'
4263
 
                    else:
4264
 
                        patch_type = None
4265
 
                directive = merge_directive.MergeDirective.from_objects(
4266
 
                    branch.repository, revision_id, time.time(),
4267
 
                    osutils.local_time_offset(), submit_branch,
4268
 
                    public_branch=public_branch, patch_type=patch_type,
4269
 
                    message=message)
4270
 
 
4271
 
            outfile.writelines(directive.to_lines())
4272
 
            if output is None:
4273
 
                subject = '[MERGE] '
4274
 
                if message is not None:
4275
 
                    subject += message
4276
 
                else:
4277
 
                    revision = branch.repository.get_revision(revision_id)
4278
 
                    subject += revision.get_summary()
4279
 
                basename = directive.get_disk_name(branch)
4280
 
                mail_client.compose_merge_request(mail_to, subject,
4281
 
                                                  outfile.getvalue(), basename)
4282
 
        finally:
4283
 
            if output != '-':
4284
 
                outfile.close()
4285
 
            branch.unlock()
4286
 
 
4287
 
 
4288
 
class cmd_bundle_revisions(cmd_send):
4289
 
 
4290
 
    """Create a merge-directive for submiting changes.
4291
 
 
4292
 
    A merge directive provides many things needed for requesting merges:
4293
 
 
4294
 
    * A machine-readable description of the merge to perform
4295
 
 
4296
 
    * An optional patch that is a preview of the changes requested
4297
 
 
4298
 
    * An optional bundle of revision data, so that the changes can be applied
4299
 
      directly from the merge directive, without retrieving data from a
4300
 
      branch.
4301
 
 
4302
 
    If --no-bundle is specified, then public_branch is needed (and must be
4303
 
    up-to-date), so that the receiver can perform the merge using the
4304
 
    public_branch.  The public_branch is always included if known, so that
4305
 
    people can check it later.
4306
 
 
4307
 
    The submit branch defaults to the parent, but can be overridden.  Both
4308
 
    submit branch and public branch will be remembered if supplied.
4309
 
 
4310
 
    If a public_branch is known for the submit_branch, that public submit
4311
 
    branch is used in the merge instructions.  This means that a local mirror
4312
 
    can be used as your actual submit branch, once you have set public_branch
4313
 
    for that mirror.
4314
 
 
4315
 
    Two formats are currently supported: "4" uses revision bundle format 4 and
4316
 
    merge directive format 2.  It is significantly faster and smaller than
4317
 
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4318
 
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4319
 
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
4320
 
    """
4321
 
 
4322
 
    takes_options = [
4323
 
        Option('no-bundle',
4324
 
               help='Do not include a bundle in the merge directive.'),
4325
 
        Option('no-patch', help='Do not include a preview patch in the merge'
4326
 
               ' directive.'),
4327
 
        Option('remember',
4328
 
               help='Remember submit and public branch.'),
4329
 
        Option('from',
4330
 
               help='Branch to generate the submission from, '
4331
 
               'rather than the one containing the working directory.',
4332
 
               short_name='f',
4333
 
               type=unicode),
4334
 
        Option('output', short_name='o', help='Write directive to this file.',
4335
 
               type=unicode),
4336
 
        'revision',
4337
 
        RegistryOption.from_kwargs('format',
4338
 
        'Use the specified output format.',
4339
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4340
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
4341
 
        ]
4342
 
    aliases = ['bundle']
4343
 
 
4344
 
    _see_also = ['send', 'merge']
4345
 
 
4346
 
    hidden = True
4347
 
 
4348
 
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4349
 
            no_patch=False, revision=None, remember=False, output=None,
4350
 
            format='4', **kwargs):
4351
 
        if output is None:
4352
 
            output = '-'
4353
 
        return self._run(submit_branch, revision, public_branch, remember,
4354
 
                         format, no_bundle, no_patch, output,
4355
 
                         kwargs.get('from', '.'), None, None)
 
3562
            s = smtplib.SMTP()
 
3563
            server = branch.get_config().get_user_option('smtp_server')
 
3564
            if not server:
 
3565
                server = 'localhost'
 
3566
            s.connect(server)
 
3567
            s.sendmail(message['From'], message['To'], message.as_string())
4356
3568
 
4357
3569
 
4358
3570
class cmd_tag(Command):
4359
 
    """Create, remove or modify a tag naming a revision.
 
3571
    """Create a tag naming a revision.
4360
3572
    
4361
3573
    Tags give human-meaningful names to revisions.  Commands that take a -r
4362
3574
    (--revision) option can be given -rtag:X, where X is any previously
4367
3579
 
4368
3580
    It is an error to give a tag name that already exists unless you pass 
4369
3581
    --force, in which case the tag is moved to point to the new revision.
4370
 
 
4371
 
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
4372
 
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
4373
3582
    """
4374
3583
 
4375
3584
    _see_also = ['commit', 'tags']
4384
3593
            type=unicode,
4385
3594
            ),
4386
3595
        Option('force',
4387
 
            help='Replace existing tags.',
 
3596
            help='Replace existing tags',
4388
3597
            ),
4389
3598
        'revision',
4390
3599
        ]
4407
3616
                        raise errors.BzrCommandError(
4408
3617
                            "Tags can only be placed on a single revision, "
4409
3618
                            "not on a range")
4410
 
                    revision_id = revision[0].as_revision_id(branch)
 
3619
                    revision_id = revision[0].in_history(branch).rev_id
4411
3620
                else:
4412
3621
                    revision_id = branch.last_revision()
4413
3622
                if (not force) and branch.tags.has_tag(tag_name):
4421
3630
class cmd_tags(Command):
4422
3631
    """List tags.
4423
3632
 
4424
 
    This command shows a table of tag names and the revisions they reference.
 
3633
    This tag shows a table of tag names and the revisions they reference.
4425
3634
    """
4426
3635
 
4427
3636
    _see_also = ['tag']
4428
3637
    takes_options = [
4429
3638
        Option('directory',
4430
 
            help='Branch whose tags should be displayed.',
 
3639
            help='Branch whose tags should be displayed',
4431
3640
            short_name='d',
4432
3641
            type=unicode,
4433
3642
            ),
4434
 
        RegistryOption.from_kwargs('sort',
4435
 
            'Sort tags by different criteria.', title='Sorting',
4436
 
            alpha='Sort tags lexicographically (default).',
4437
 
            time='Sort tags chronologically.',
4438
 
            ),
4439
 
        'show-ids',
4440
3643
    ]
4441
3644
 
4442
3645
    @display_command
4443
3646
    def run(self,
4444
3647
            directory='.',
4445
 
            sort='alpha',
4446
 
            show_ids=False,
4447
3648
            ):
4448
3649
        branch, relpath = Branch.open_containing(directory)
4449
 
        tags = branch.tags.get_tag_dict().items()
4450
 
        if not tags:
4451
 
            return
4452
 
        if sort == 'alpha':
4453
 
            tags.sort()
4454
 
        elif sort == 'time':
4455
 
            timestamps = {}
4456
 
            for tag, revid in tags:
4457
 
                try:
4458
 
                    revobj = branch.repository.get_revision(revid)
4459
 
                except errors.NoSuchRevision:
4460
 
                    timestamp = sys.maxint # place them at the end
 
3650
        for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
 
3651
            self.outf.write('%-20s %s\n' % (tag_name, target))
 
3652
 
 
3653
 
 
3654
# command-line interpretation helper for merge-related commands
 
3655
def _merge_helper(other_revision, base_revision,
 
3656
                  check_clean=True, ignore_zero=False,
 
3657
                  this_dir=None, backup_files=False,
 
3658
                  merge_type=None,
 
3659
                  file_list=None, show_base=False, reprocess=False,
 
3660
                  pull=False,
 
3661
                  pb=DummyProgress(),
 
3662
                  change_reporter=None,
 
3663
                  other_rev_id=None):
 
3664
    """Merge changes into a tree.
 
3665
 
 
3666
    base_revision
 
3667
        list(path, revno) Base for three-way merge.  
 
3668
        If [None, None] then a base will be automatically determined.
 
3669
    other_revision
 
3670
        list(path, revno) Other revision for three-way merge.
 
3671
    this_dir
 
3672
        Directory to merge changes into; '.' by default.
 
3673
    check_clean
 
3674
        If true, this_dir must have no uncommitted changes before the
 
3675
        merge begins.
 
3676
    ignore_zero - If true, suppress the "zero conflicts" message when 
 
3677
        there are no conflicts; should be set when doing something we expect
 
3678
        to complete perfectly.
 
3679
    file_list - If supplied, merge only changes to selected files.
 
3680
 
 
3681
    All available ancestors of other_revision and base_revision are
 
3682
    automatically pulled into the branch.
 
3683
 
 
3684
    The revno may be -1 to indicate the last revision on the branch, which is
 
3685
    the typical case.
 
3686
 
 
3687
    This function is intended for use from the command line; programmatic
 
3688
    clients might prefer to call merge.merge_inner(), which has less magic 
 
3689
    behavior.
 
3690
    """
 
3691
    # Loading it late, so that we don't always have to import bzrlib.merge
 
3692
    if merge_type is None:
 
3693
        merge_type = _mod_merge.Merge3Merger
 
3694
    if this_dir is None:
 
3695
        this_dir = u'.'
 
3696
    this_tree = WorkingTree.open_containing(this_dir)[0]
 
3697
    if show_base and not merge_type is _mod_merge.Merge3Merger:
 
3698
        raise errors.BzrCommandError("Show-base is not supported for this merge"
 
3699
                                     " type. %s" % merge_type)
 
3700
    if reprocess and not merge_type.supports_reprocess:
 
3701
        raise errors.BzrCommandError("Conflict reduction is not supported for merge"
 
3702
                                     " type %s." % merge_type)
 
3703
    if reprocess and show_base:
 
3704
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
 
3705
    # TODO: jam 20070226 We should really lock these trees earlier. However, we
 
3706
    #       only want to take out a lock_tree_write() if we don't have to pull
 
3707
    #       any ancestry. But merge might fetch ancestry in the middle, in
 
3708
    #       which case we would need a lock_write().
 
3709
    #       Because we cannot upgrade locks, for now we live with the fact that
 
3710
    #       the tree will be locked multiple times during a merge. (Maybe
 
3711
    #       read-only some of the time, but it means things will get read
 
3712
    #       multiple times.)
 
3713
    try:
 
3714
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
 
3715
                                   pb=pb, change_reporter=change_reporter)
 
3716
        merger.pp = ProgressPhase("Merge phase", 5, pb)
 
3717
        merger.pp.next_phase()
 
3718
        merger.check_basis(check_clean)
 
3719
        if other_rev_id is not None:
 
3720
            merger.set_other_revision(other_rev_id, this_tree.branch)
 
3721
        else:
 
3722
            merger.set_other(other_revision)
 
3723
        merger.pp.next_phase()
 
3724
        merger.set_base(base_revision)
 
3725
        if merger.base_rev_id == merger.other_rev_id:
 
3726
            note('Nothing to do.')
 
3727
            return 0
 
3728
        if file_list is None:
 
3729
            if pull and merger.base_rev_id == merger.this_rev_id:
 
3730
                # FIXME: deduplicate with pull
 
3731
                result = merger.this_tree.pull(merger.this_branch,
 
3732
                        False, merger.other_rev_id)
 
3733
                if result.old_revid == result.new_revid:
 
3734
                    note('No revisions to pull.')
4461
3735
                else:
4462
 
                    timestamp = revobj.timestamp
4463
 
                timestamps[revid] = timestamp
4464
 
            tags.sort(key=lambda x: timestamps[x[1]])
4465
 
        if not show_ids:
4466
 
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
4467
 
            revno_map = branch.get_revision_id_to_revno_map()
4468
 
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
4469
 
                        for tag, revid in tags ]
4470
 
        for tag, revspec in tags:
4471
 
            self.outf.write('%-20s %s\n' % (tag, revspec))
4472
 
 
4473
 
 
4474
 
class cmd_reconfigure(Command):
4475
 
    """Reconfigure the type of a bzr directory.
4476
 
 
4477
 
    A target configuration must be specified.
4478
 
 
4479
 
    For checkouts, the bind-to location will be auto-detected if not specified.
4480
 
    The order of preference is
4481
 
    1. For a lightweight checkout, the current bound location.
4482
 
    2. For branches that used to be checkouts, the previously-bound location.
4483
 
    3. The push location.
4484
 
    4. The parent location.
4485
 
    If none of these is available, --bind-to must be specified.
4486
 
    """
4487
 
 
4488
 
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
4489
 
    takes_args = ['location?']
4490
 
    takes_options = [RegistryOption.from_kwargs('target_type',
4491
 
                     title='Target type',
4492
 
                     help='The type to reconfigure the directory to.',
4493
 
                     value_switches=True, enum_switch=False,
4494
 
                     branch='Reconfigure to be an unbound branch '
4495
 
                        'with no working tree.',
4496
 
                     tree='Reconfigure to be an unbound branch '
4497
 
                        'with a working tree.',
4498
 
                     checkout='Reconfigure to be a bound branch '
4499
 
                        'with a working tree.',
4500
 
                     lightweight_checkout='Reconfigure to be a lightweight'
4501
 
                     ' checkout (with no local history).',
4502
 
                     standalone='Reconfigure to be a standalone branch '
4503
 
                        '(i.e. stop using shared repository).',
4504
 
                     use_shared='Reconfigure to use a shared repository.'),
4505
 
                     Option('bind-to', help='Branch to bind checkout to.',
4506
 
                            type=str),
4507
 
                     Option('force',
4508
 
                        help='Perform reconfiguration even if local changes'
4509
 
                        ' will be lost.')
4510
 
                     ]
4511
 
 
4512
 
    def run(self, location=None, target_type=None, bind_to=None, force=False):
4513
 
        directory = bzrdir.BzrDir.open(location)
4514
 
        if target_type is None:
4515
 
            raise errors.BzrCommandError('No target configuration specified')
4516
 
        elif target_type == 'branch':
4517
 
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
4518
 
        elif target_type == 'tree':
4519
 
            reconfiguration = reconfigure.Reconfigure.to_tree(directory)
4520
 
        elif target_type == 'checkout':
4521
 
            reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4522
 
                                                                  bind_to)
4523
 
        elif target_type == 'lightweight-checkout':
4524
 
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
4525
 
                directory, bind_to)
4526
 
        elif target_type == 'use-shared':
4527
 
            reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
4528
 
        elif target_type == 'standalone':
4529
 
            reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
4530
 
        reconfiguration.apply(force)
4531
 
 
4532
 
 
4533
 
class cmd_switch(Command):
4534
 
    """Set the branch of a checkout and update.
4535
 
    
4536
 
    For lightweight checkouts, this changes the branch being referenced.
4537
 
    For heavyweight checkouts, this checks that there are no local commits
4538
 
    versus the current bound branch, then it makes the local branch a mirror
4539
 
    of the new location and binds to it.
4540
 
    
4541
 
    In both cases, the working tree is updated and uncommitted changes
4542
 
    are merged. The user can commit or revert these as they desire.
4543
 
 
4544
 
    Pending merges need to be committed or reverted before using switch.
4545
 
 
4546
 
    The path to the branch to switch to can be specified relative to the parent
4547
 
    directory of the current branch. For example, if you are currently in a
4548
 
    checkout of /path/to/branch, specifying 'newbranch' will find a branch at
4549
 
    /path/to/newbranch.
4550
 
    """
4551
 
 
4552
 
    takes_args = ['to_location']
4553
 
    takes_options = [Option('force',
4554
 
                        help='Switch even if local commits will be lost.')
4555
 
                     ]
4556
 
 
4557
 
    def run(self, to_location, force=False):
4558
 
        from bzrlib import switch
4559
 
        tree_location = '.'
4560
 
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4561
 
        try:
4562
 
            to_branch = Branch.open(to_location)
4563
 
        except errors.NotBranchError:
4564
 
            to_branch = Branch.open(
4565
 
                control_dir.open_branch().base + '../' + to_location)
4566
 
        switch.switch(control_dir, to_branch, force)
4567
 
        note('Switched to branch: %s',
4568
 
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4569
 
 
4570
 
 
4571
 
class cmd_hooks(Command):
4572
 
    """Show a branch's currently registered hooks.
4573
 
    """
4574
 
 
4575
 
    hidden = True
4576
 
    takes_args = ['path?']
4577
 
 
4578
 
    def run(self, path=None):
4579
 
        if path is None:
4580
 
            path = '.'
4581
 
        branch_hooks = Branch.open(path).hooks
4582
 
        for hook_type in branch_hooks:
4583
 
            hooks = branch_hooks[hook_type]
4584
 
            self.outf.write("%s:\n" % (hook_type,))
4585
 
            if hooks:
4586
 
                for hook in hooks:
4587
 
                    self.outf.write("  %s\n" %
4588
 
                                    (branch_hooks.get_hook_name(hook),))
4589
 
            else:
4590
 
                self.outf.write("  <no hooks installed>\n")
4591
 
 
4592
 
 
4593
 
def _create_prefix(cur_transport):
4594
 
    needed = [cur_transport]
4595
 
    # Recurse upwards until we can create a directory successfully
4596
 
    while True:
4597
 
        new_transport = cur_transport.clone('..')
4598
 
        if new_transport.base == cur_transport.base:
4599
 
            raise errors.BzrCommandError(
4600
 
                "Failed to create path prefix for %s."
4601
 
                % cur_transport.base)
4602
 
        try:
4603
 
            new_transport.mkdir('.')
4604
 
        except errors.NoSuchFile:
4605
 
            needed.append(new_transport)
4606
 
            cur_transport = new_transport
4607
 
        else:
4608
 
            break
4609
 
    # Now we only need to create child directories
4610
 
    while needed:
4611
 
        cur_transport = needed.pop()
4612
 
        cur_transport.ensure_base()
 
3736
                    note('Now on revision %d.' % result.new_revno)
 
3737
                return 0
 
3738
        merger.backup_files = backup_files
 
3739
        merger.merge_type = merge_type 
 
3740
        merger.set_interesting_files(file_list)
 
3741
        merger.show_base = show_base 
 
3742
        merger.reprocess = reprocess
 
3743
        conflicts = merger.do_merge()
 
3744
        if file_list is None:
 
3745
            merger.set_pending()
 
3746
    finally:
 
3747
        pb.clear()
 
3748
    return conflicts
 
3749
 
 
3750
 
 
3751
# Compatibility
 
3752
merge = _merge_helper
4613
3753
 
4614
3754
 
4615
3755
# these get imported and then picked up by the scan for cmd_*
4619
3759
# details were needed.
4620
3760
from bzrlib.cmd_version_info import cmd_version_info
4621
3761
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
4622
 
from bzrlib.bundle.commands import (
4623
 
    cmd_bundle_info,
4624
 
    )
 
3762
from bzrlib.bundle.commands import cmd_bundle_revisions
4625
3763
from bzrlib.sign_my_commits import cmd_sign_my_commits
4626
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
 
3764
from bzrlib.weave_commands import cmd_weave_list, cmd_weave_join, \
4627
3765
        cmd_weave_plan_merge, cmd_weave_merge_text