~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Vincent Ladeuil
  • Date: 2007-11-04 15:29:17 UTC
  • mfrom: (2961 +trunk)
  • mto: (2961.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 2962.
  • Revision ID: v.ladeuil+lp@free.fr-20071104152917-nrsumxpk3dikso2c
Merge bzr.dev

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
87
87
    if file_list is None or len(file_list) == 0:
88
88
        return WorkingTree.open_containing(default_branch)[0], file_list
89
89
    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
90
    new_list = []
105
91
    for filename in file_list:
106
92
        try:
107
93
            new_list.append(tree.relpath(osutils.dereference_path(filename)))
108
94
        except errors.PathNotChild:
109
95
            raise errors.FileInWrongBranch(tree.branch, filename)
110
 
    return new_list
 
96
    return tree, new_list
 
97
 
 
98
 
 
99
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
 
100
def get_format_type(typestring):
 
101
    """Parse and return a format specifier."""
 
102
    # Have to use BzrDirMetaFormat1 directly, so that
 
103
    # RepositoryFormat.set_default_format works
 
104
    if typestring == "default":
 
105
        return bzrdir.BzrDirMetaFormat1()
 
106
    try:
 
107
        return bzrdir.format_registry.make_bzrdir(typestring)
 
108
    except KeyError:
 
109
        msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
 
110
        raise errors.BzrCommandError(msg)
111
111
 
112
112
 
113
113
# TODO: Make sure no commands unconditionally use the working directory as a
148
148
    
149
149
    Note that --short or -S gives status flags for each item, similar
150
150
    to Subversion's status command. To get output similar to svn -q,
151
 
    use bzr status -SV.
 
151
    use bzr -SV.
152
152
 
153
153
    If no arguments are specified, the status of the entire working
154
154
    directory is shown.  Otherwise, only the status of the specified
166
166
                     Option('short', help='Use short status indicators.',
167
167
                            short_name='S'),
168
168
                     Option('versioned', help='Only show versioned files.',
169
 
                            short_name='V'),
170
 
                     Option('no-pending', help='Don\'t show pending merges.',
171
 
                           ),
 
169
                            short_name='V')
172
170
                     ]
173
171
    aliases = ['st', 'stat']
174
172
 
177
175
    
178
176
    @display_command
179
177
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
180
 
            versioned=False, no_pending=False):
 
178
            versioned=False):
181
179
        from bzrlib.status import show_tree_status
182
180
 
183
181
        if revision and len(revision) > 2:
184
182
            raise errors.BzrCommandError('bzr status --revision takes exactly'
185
183
                                         ' one or two revision specifiers')
186
184
 
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
 
185
        tree, file_list = tree_files(file_list)
 
186
            
197
187
        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))
 
188
                         specific_files=file_list, revision=revision,
 
189
                         to_file=self.outf, short=short, versioned=versioned)
201
190
 
202
191
 
203
192
class cmd_cat_revision(Command):
226
215
        # TODO: jam 20060112 should cat-revision always output utf-8?
227
216
        if revision_id is not None:
228
217
            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)
 
218
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
235
219
        elif revision is not None:
236
220
            for rev in revision:
237
221
                if rev is None:
238
222
                    raise errors.BzrCommandError('You cannot specify a NULL'
239
223
                                                 ' revision.')
240
 
                rev_id = rev.as_revision_id(b)
 
224
                revno, rev_id = rev.in_history(b)
241
225
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
242
226
    
243
227
 
311
295
            revs.append(RevisionSpec.from_string('-1'))
312
296
 
313
297
        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:
 
298
            revinfo = rev.in_history(b)
 
299
            if revinfo.revno is None:
318
300
                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)
 
301
                revno = '.'.join(str(i) for i in dotted_map[revinfo.rev_id])
 
302
                print '%s %s' % (revno, revinfo.rev_id)
 
303
            else:
 
304
                print '%4d %s' % (revinfo.revno, revinfo.rev_id)
321
305
 
322
306
    
323
307
class cmd_add(Command):
482
466
                    raise errors.BzrCommandError(
483
467
                        'bzr inventory --revision takes exactly one revision'
484
468
                        ' identifier')
485
 
                revision_id = revision[0].as_revision_id(work_tree.branch)
 
469
                revision_id = revision[0].in_history(work_tree.branch).rev_id
486
470
                tree = work_tree.branch.repository.revision_tree(revision_id)
487
471
 
488
472
                extra_trees = [work_tree]
550
534
        if len(names_list) < 2:
551
535
            raise errors.BzrCommandError("missing file argument")
552
536
        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:
 
537
        
 
538
        if os.path.isdir(names_list[-1]):
578
539
            # move into existing directory
579
540
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
580
541
                self.outf.write("%s => %s\n" % pair)
585
546
                                             ' directory')
586
547
            tree.rename_one(rel_names[0], rel_names[1], after=after)
587
548
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
588
 
 
589
 
 
 
549
            
 
550
    
590
551
class cmd_pull(Command):
591
552
    """Turn this branch into a mirror of another branch.
592
553
 
605
566
    that, you can omit the location to use the default.  To change the
606
567
    default, use --remember. The value will only be saved if the remote
607
568
    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
569
    """
613
570
 
614
571
    _see_also = ['push', 'update', 'status-flags']
642
599
 
643
600
        possible_transports = []
644
601
        if location is not None:
645
 
            try:
646
 
                mergeable = bundle.read_mergeable_from_url(location,
647
 
                    possible_transports=possible_transports)
648
 
            except errors.NotABundle:
649
 
                mergeable = None
 
602
            mergeable, location_transport = _get_mergeable_helper(location)
 
603
            possible_transports.append(location_transport)
650
604
 
651
605
        stored_loc = branch_to.get_parent()
652
606
        if location is None:
656
610
            else:
657
611
                display_url = urlutils.unescape_for_display(stored_loc,
658
612
                        self.outf.encoding)
659
 
                if not is_quiet():
660
 
                    self.outf.write("Using saved parent location: %s\n" % display_url)
 
613
                self.outf.write("Using saved location: %s\n" % display_url)
661
614
                location = stored_loc
 
615
                location_transport = transport.get_transport(
 
616
                    location, possible_transports=possible_transports)
662
617
 
663
618
        if mergeable is not None:
664
619
            if revision is not None:
669
624
                mergeable.get_merge_request(branch_to.repository)
670
625
            branch_from = branch_to
671
626
        else:
672
 
            branch_from = Branch.open(location,
673
 
                possible_transports=possible_transports)
 
627
            branch_from = Branch.open_from_transport(location_transport)
674
628
 
675
629
            if branch_to.get_parent() is None or remember:
676
630
                branch_to.set_parent(branch_from.base)
677
631
 
678
632
        if revision is not None:
679
633
            if len(revision) == 1:
680
 
                revision_id = revision[0].as_revision_id(branch_from)
 
634
                revision_id = revision[0].in_history(branch_from).rev_id
681
635
            else:
682
636
                raise errors.BzrCommandError(
683
637
                    'bzr pull --revision takes one value.')
684
638
 
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)
 
639
        if verbose:
 
640
            old_rh = branch_to.revision_history()
 
641
        if tree_to is not None:
 
642
            change_reporter = delta._ChangeReporter(
 
643
                unversioned_filter=tree_to.is_ignored)
 
644
            result = tree_to.pull(branch_from, overwrite, revision_id,
 
645
                                  change_reporter,
 
646
                                  possible_transports=possible_transports)
 
647
        else:
 
648
            result = branch_to.pull(branch_from, overwrite, revision_id)
695
649
 
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()
 
650
        result.report(self.outf)
 
651
        if verbose:
 
652
            new_rh = branch_to.revision_history()
 
653
            log.show_changed_revisions(branch_to, old_rh, new_rh,
 
654
                                       to_file=self.outf)
707
655
 
708
656
 
709
657
class cmd_push(Command):
733
681
    """
734
682
 
735
683
    _see_also = ['pull', 'update', 'working-trees']
736
 
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
 
684
    takes_options = ['remember', 'overwrite', 'verbose',
737
685
        Option('create-prefix',
738
686
               help='Create the path leading up to the branch '
739
687
                    'if it does not already exist.'),
748
696
                    ' directory exists, but does not already'
749
697
                    ' have a control directory.  This flag will'
750
698
                    ' 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
699
        ]
760
700
    takes_args = ['location?']
761
701
    encoding_type = 'replace'
762
702
 
763
703
    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
 
704
            create_prefix=False, verbose=False,
 
705
            use_existing_dir=False,
 
706
            directory=None):
 
707
        # FIXME: Way too big!  Put this into a function called from the
 
708
        # command.
770
709
        if directory is None:
771
710
            directory = '.'
772
711
        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
 
712
        stored_loc = br_from.get_push_location()
801
713
        if location is None:
802
 
            stored_loc = br_from.get_push_location()
803
714
            if stored_loc is None:
804
 
                raise errors.BzrCommandError(
805
 
                    "No push location known or specified.")
 
715
                raise errors.BzrCommandError("No push location known or specified.")
806
716
            else:
807
717
                display_url = urlutils.unescape_for_display(stored_loc,
808
718
                        self.outf.encoding)
809
 
                self.outf.write("Using saved push location: %s\n" % display_url)
 
719
                self.outf.write("Using saved location: %s\n" % display_url)
810
720
                location = stored_loc
811
721
 
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)
 
722
        to_transport = transport.get_transport(location)
 
723
 
 
724
        br_to = repository_to = dir_to = None
 
725
        try:
 
726
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
 
727
        except errors.NotBranchError:
 
728
            pass # Didn't find anything
 
729
        else:
 
730
            # If we can open a branch, use its direct repository, otherwise see
 
731
            # if there is a repository without a branch.
 
732
            try:
 
733
                br_to = dir_to.open_branch()
 
734
            except errors.NotBranchError:
 
735
                # Didn't find a branch, can we find a repository?
 
736
                try:
 
737
                    repository_to = dir_to.find_repository()
 
738
                except errors.NoRepositoryPresent:
 
739
                    pass
 
740
            else:
 
741
                # Found a branch, so we must have found a repository
 
742
                repository_to = br_to.repository
 
743
        push_result = None
 
744
        if verbose:
 
745
            old_rh = []
 
746
        if dir_to is None:
 
747
            # The destination doesn't exist; create it.
 
748
            # XXX: Refactor the create_prefix/no_create_prefix code into a
 
749
            #      common helper function
 
750
            try:
 
751
                to_transport.mkdir('.')
 
752
            except errors.FileExists:
 
753
                if not use_existing_dir:
 
754
                    raise errors.BzrCommandError("Target directory %s"
 
755
                         " already exists, but does not have a valid .bzr"
 
756
                         " directory. Supply --use-existing-dir to push"
 
757
                         " there anyway." % location)
 
758
            except errors.NoSuchFile:
 
759
                if not create_prefix:
 
760
                    raise errors.BzrCommandError("Parent directory of %s"
 
761
                        " does not exist."
 
762
                        "\nYou may supply --create-prefix to create all"
 
763
                        " leading parent directories."
 
764
                        % location)
 
765
                _create_prefix(to_transport)
 
766
 
 
767
            # Now the target directory exists, but doesn't have a .bzr
 
768
            # directory. So we need to create it, along with any work to create
 
769
            # all of the dependent branches, etc.
 
770
            dir_to = br_from.bzrdir.clone_on_transport(to_transport,
 
771
                revision_id=br_from.last_revision())
 
772
            br_to = dir_to.open_branch()
 
773
            # TODO: Some more useful message about what was copied
 
774
            note('Created new branch.')
 
775
            # We successfully created the target, remember it
 
776
            if br_from.get_push_location() is None or remember:
 
777
                br_from.set_push_location(br_to.base)
 
778
        elif repository_to is None:
 
779
            # we have a bzrdir but no branch or repository
 
780
            # XXX: Figure out what to do other than complain.
 
781
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
 
782
                " directory, but not a branch or repository. This is an"
 
783
                " unsupported configuration. Please move the target directory"
 
784
                " out of the way and try again."
 
785
                % location)
 
786
        elif br_to is None:
 
787
            # We have a repository but no branch, copy the revisions, and then
 
788
            # create a branch.
 
789
            last_revision_id = br_from.last_revision()
 
790
            repository_to.fetch(br_from.repository,
 
791
                                revision_id=last_revision_id)
 
792
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
 
793
            note('Created new branch.')
 
794
            if br_from.get_push_location() is None or remember:
 
795
                br_from.set_push_location(br_to.base)
 
796
        else: # We have a valid to branch
 
797
            # We were able to connect to the remote location, so remember it
 
798
            # we don't need to successfully push because of possible divergence.
 
799
            if br_from.get_push_location() is None or remember:
 
800
                br_from.set_push_location(br_to.base)
 
801
            if verbose:
 
802
                old_rh = br_to.revision_history()
 
803
            try:
 
804
                try:
 
805
                    tree_to = dir_to.open_workingtree()
 
806
                except errors.NotLocalUrl:
 
807
                    warning("This transport does not update the working " 
 
808
                            "tree of: %s. See 'bzr help working-trees' for "
 
809
                            "more information." % br_to.base)
 
810
                    push_result = br_from.push(br_to, overwrite)
 
811
                except errors.NoWorkingTree:
 
812
                    push_result = br_from.push(br_to, overwrite)
 
813
                else:
 
814
                    tree_to.lock_write()
 
815
                    try:
 
816
                        push_result = br_from.push(tree_to.branch, overwrite)
 
817
                        tree_to.update()
 
818
                    finally:
 
819
                        tree_to.unlock()
 
820
            except errors.DivergedBranches:
 
821
                raise errors.BzrCommandError('These branches have diverged.'
 
822
                                        '  Try using "merge" and then "push".')
 
823
        if push_result is not None:
 
824
            push_result.report(self.outf)
 
825
        elif verbose:
 
826
            new_rh = br_to.revision_history()
 
827
            if old_rh != new_rh:
 
828
                # Something changed
 
829
                from bzrlib.log import show_changed_revisions
 
830
                show_changed_revisions(br_to, old_rh, new_rh,
 
831
                                       to_file=self.outf)
 
832
        else:
 
833
            # we probably did a clone rather than a push, so a message was
 
834
            # emitted above
 
835
            pass
816
836
 
817
837
 
818
838
class cmd_branch(Command):
831
851
 
832
852
    _see_also = ['checkout']
833
853
    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
 
        ]
 
854
    takes_options = ['revision']
841
855
    aliases = ['get', 'clone']
842
856
 
843
 
    def run(self, from_location, to_location=None, revision=None,
844
 
            hardlink=False, stacked=False):
 
857
    def run(self, from_location, to_location=None, revision=None):
845
858
        from bzrlib.tag import _merge_tags_if_possible
846
859
        if revision is None:
847
860
            revision = [None]
849
862
            raise errors.BzrCommandError(
850
863
                'bzr branch --revision takes exactly 1 revision value')
851
864
 
852
 
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
853
 
            from_location)
 
865
        br_from = Branch.open(from_location)
854
866
        br_from.lock_read()
855
867
        try:
856
868
            if len(revision) == 1 and revision[0] is not None:
857
 
                revision_id = revision[0].as_revision_id(br_from)
 
869
                revision_id = revision[0].in_history(br_from)[1]
858
870
            else:
859
871
                # FIXME - wt.last_revision, fallback to branch, fall back to
860
872
                # None or perhaps NULL_REVISION to mean copy nothing
862
874
                revision_id = br_from.last_revision()
863
875
            if to_location is None:
864
876
                to_location = urlutils.derive_to_location(from_location)
 
877
                name = None
 
878
            else:
 
879
                name = os.path.basename(to_location) + '\n'
 
880
 
865
881
            to_transport = transport.get_transport(to_location)
866
882
            try:
867
883
                to_transport.mkdir('.')
874
890
            try:
875
891
                # preserve whatever source format we have.
876
892
                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)
 
893
                                            possible_transports=[to_transport])
880
894
                branch = dir.open_branch()
881
895
            except errors.NoSuchRevision:
882
896
                to_transport.delete_tree('.')
883
 
                msg = "The branch %s has no revision %s." % (from_location,
884
 
                    revision[0])
 
897
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
885
898
                raise errors.BzrCommandError(msg)
 
899
            if name:
 
900
                branch.control_files.put_utf8('branch-name', name)
886
901
            _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())
 
902
            note('Branched %d revision(s).' % branch.revno())
896
903
        finally:
897
904
            br_from.unlock()
898
905
 
928
935
                                 "common operations like diff and status without "
929
936
                                 "such access, and also support local commits."
930
937
                            ),
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
938
                     ]
937
939
    aliases = ['co']
938
940
 
939
941
    def run(self, branch_location=None, to_location=None, revision=None,
940
 
            lightweight=False, files_from=None, hardlink=False):
 
942
            lightweight=False):
941
943
        if revision is None:
942
944
            revision = [None]
943
945
        elif len(revision) > 1:
946
948
        if branch_location is None:
947
949
            branch_location = osutils.getcwd()
948
950
            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)
 
951
        source = Branch.open(branch_location)
953
952
        if len(revision) == 1 and revision[0] is not None:
954
 
            revision_id = revision[0].as_revision_id(source)
 
953
            revision_id = _mod_revision.ensure_null(
 
954
                revision[0].in_history(source)[1])
955
955
        else:
956
956
            revision_id = None
957
957
        if to_location is None:
966
966
            except errors.NoWorkingTree:
967
967
                source.bzrdir.create_workingtree(revision_id)
968
968
                return
969
 
        source.create_checkout(to_location, revision_id, lightweight,
970
 
                               accelerator_tree, hardlink)
 
969
        source.create_checkout(to_location, revision_id, lightweight)
971
970
 
972
971
 
973
972
class cmd_renames(Command):
1063
1062
    _see_also = ['revno', 'working-trees', 'repositories']
1064
1063
    takes_args = ['location?']
1065
1064
    takes_options = ['verbose']
1066
 
    encoding_type = 'replace'
1067
1065
 
1068
1066
    @display_command
1069
1067
    def run(self, location=None, verbose=False):
1073
1071
            noise_level = 0
1074
1072
        from bzrlib.info import show_bzrdir_info
1075
1073
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1076
 
                         verbose=noise_level, outfile=self.outf)
 
1074
                         verbose=noise_level)
1077
1075
 
1078
1076
 
1079
1077
class cmd_remove(Command):
1080
1078
    """Remove files or directories.
1081
1079
 
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.
 
1080
    This makes bzr stop tracking changes to the specified files and
 
1081
    delete them if they can easily be recovered using revert.
 
1082
 
 
1083
    You can specify one or more files, and/or --new.  If you specify --new,
 
1084
    only 'added' files will be removed.  If you specify both, then new files
 
1085
    in the specified directories will be removed.  If the directories are
 
1086
    also new, they will also be removed.
1086
1087
    """
1087
1088
    takes_args = ['file*']
1088
1089
    takes_options = ['verbose',
1089
 
        Option('new', help='Only remove files that have never been committed.'),
 
1090
        Option('new', help='Remove newly-added files.'),
1090
1091
        RegistryOption.from_kwargs('file-deletion-strategy',
1091
1092
            'The file deletion mode to be used.',
1092
1093
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1095
1096
            keep="Don't delete any files.",
1096
1097
            force='Delete all the specified files, even if they can not be '
1097
1098
                'recovered and even if they are non-empty directories.')]
1098
 
    aliases = ['rm', 'del']
 
1099
    aliases = ['rm']
1099
1100
    encoding_type = 'replace'
1100
1101
 
1101
1102
    def run(self, file_list, verbose=False, new=False,
1104
1105
 
1105
1106
        if file_list is not None:
1106
1107
            file_list = [f for f in file_list]
 
1108
        elif not new:
 
1109
            raise errors.BzrCommandError('Specify one or more files to'
 
1110
            ' remove, or use --new.')
1107
1111
 
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()
 
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
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1119
            keep_files=file_deletion_strategy=='keep',
 
1120
            force=file_deletion_strategy=='force')
1133
1121
 
1134
1122
 
1135
1123
class cmd_file_id(Command):
1240
1228
            last_revision = wt.last_revision()
1241
1229
 
1242
1230
        revision_ids = b.repository.get_ancestry(last_revision)
 
1231
        assert revision_ids[0] is None
1243
1232
        revision_ids.pop(0)
1244
1233
        for revision_id in revision_ids:
1245
1234
            self.outf.write(revision_id + '\n')
1265
1254
        bzr init
1266
1255
        bzr add .
1267
1256
        bzr status
1268
 
        bzr commit -m "imported project"
 
1257
        bzr commit -m 'imported project'
1269
1258
    """
1270
1259
 
1271
1260
    _see_also = ['init-repository', 'branch', 'checkout']
1334
1323
            except errors.UpgradeRequired:
1335
1324
                raise errors.BzrCommandError('This branch format cannot be set'
1336
1325
                    ' 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
1326
 
1342
1327
 
1343
1328
class cmd_init_repository(Command):
1389
1374
        newdir = format.initialize_on_transport(to_transport)
1390
1375
        repo = newdir.create_repository(shared=True)
1391
1376
        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
1377
 
1397
1378
 
1398
1379
class cmd_diff(Command):
1399
 
    """Show differences in the working tree, between revisions or branches.
 
1380
    """Show differences in the working tree or between revisions.
1400
1381
    
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.
 
1382
    If files are listed, only the changes in those files are listed.
 
1383
    Otherwise, all changes for the tree are listed.
1407
1384
 
1408
1385
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1409
1386
    produces patches suitable for "patch -p1".
1410
1387
 
1411
 
    :Exit values:
1412
 
        1 - changed
1413
 
        2 - unrepresentable changes
1414
 
        3 - error
1415
 
        0 - no change
1416
 
 
1417
1388
    :Examples:
1418
1389
        Shows the difference in the working tree versus the last commit::
1419
1390
 
1427
1398
 
1428
1399
            bzr diff -r1..2
1429
1400
 
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
1401
        Same as 'bzr diff' but prefix paths with old/ and new/::
1451
1402
 
1452
1403
            bzr diff --prefix old/:new/
 
1404
 
 
1405
        Show the differences between the two working trees::
 
1406
 
 
1407
            bzr diff bzr.mine bzr.dev
 
1408
 
 
1409
        Show just the differences for 'foo.c'::
 
1410
 
 
1411
            bzr diff foo.c
1453
1412
    """
 
1413
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
 
1414
    #       or a graphical diff.
 
1415
 
 
1416
    # TODO: Python difflib is not exactly the same as unidiff; should
 
1417
    #       either fix it up or prefer to use an external diff.
 
1418
 
 
1419
    # TODO: Selected-file diff is inefficient and doesn't show you
 
1420
    #       deleted files.
 
1421
 
 
1422
    # TODO: This probably handles non-Unix newlines poorly.
 
1423
 
1454
1424
    _see_also = ['status']
1455
1425
    takes_args = ['file*']
1456
1426
    takes_options = [
1460
1430
               short_name='p',
1461
1431
               help='Set prefixes added to old and new filenames, as '
1462
1432
                    '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
1433
        'revision',
1472
1434
        'change',
1473
 
        Option('using',
1474
 
            help='Use this command to compare files.',
1475
 
            type=unicode,
1476
 
            ),
1477
1435
        ]
1478
1436
    aliases = ['di', 'dif']
1479
1437
    encoding_type = 'exact'
1480
1438
 
1481
1439
    @display_command
1482
1440
    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
 
1441
            prefix=None):
 
1442
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
1485
1443
 
1486
1444
        if (prefix is None) or (prefix == '0'):
1487
1445
            # diff -p0 format
1501
1459
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1502
1460
                                         ' one or two revision specifiers')
1503
1461
 
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)
 
1462
        try:
 
1463
            tree1, file_list = internal_tree_files(file_list)
 
1464
            tree2 = None
 
1465
            b = None
 
1466
            b2 = None
 
1467
        except errors.FileInWrongBranch:
 
1468
            if len(file_list) != 2:
 
1469
                raise errors.BzrCommandError("Files are in different branches")
 
1470
 
 
1471
            tree1, file1 = WorkingTree.open_containing(file_list[0])
 
1472
            tree2, file2 = WorkingTree.open_containing(file_list[1])
 
1473
            if file1 != "" or file2 != "":
 
1474
                # FIXME diff those two files. rbc 20051123
 
1475
                raise errors.BzrCommandError("Files are in different branches")
 
1476
            file_list = None
 
1477
        except errors.NotBranchError:
 
1478
            if (revision is not None and len(revision) == 2
 
1479
                and not revision[0].needs_branch()
 
1480
                and not revision[1].needs_branch()):
 
1481
                # If both revision specs include a branch, we can
 
1482
                # diff them without needing a local working tree
 
1483
                tree1, tree2 = None, None
 
1484
            else:
 
1485
                raise
 
1486
 
 
1487
        if tree2 is not None:
 
1488
            if revision is not None:
 
1489
                # FIXME: but there should be a clean way to diff between
 
1490
                # non-default versions of two trees, it's not hard to do
 
1491
                # internally...
 
1492
                raise errors.BzrCommandError(
 
1493
                        "Sorry, diffing arbitrary revisions across branches "
 
1494
                        "is not implemented yet")
 
1495
            return show_diff_trees(tree1, tree2, sys.stdout, 
 
1496
                                   specific_files=file_list,
 
1497
                                   external_diff_options=diff_options,
 
1498
                                   old_label=old_label, new_label=new_label)
 
1499
 
 
1500
        return diff_cmd_helper(tree1, file_list, diff_options,
 
1501
                               revision_specs=revision,
 
1502
                               old_label=old_label, new_label=new_label)
1511
1503
 
1512
1504
 
1513
1505
class cmd_deleted(Command):
1549
1541
 
1550
1542
    hidden = True
1551
1543
    _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
1544
 
1558
1545
    @display_command
1559
 
    def run(self, null=False):
 
1546
    def run(self):
1560
1547
        tree = WorkingTree.open_containing(u'.')[0]
1561
1548
        td = tree.changes_from(tree.basis_tree())
1562
1549
        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')
 
1550
            self.outf.write(path + '\n')
1567
1551
 
1568
1552
 
1569
1553
class cmd_added(Command):
1572
1556
 
1573
1557
    hidden = True
1574
1558
    _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
1559
 
1581
1560
    @display_command
1582
 
    def run(self, null=False):
 
1561
    def run(self):
1583
1562
        wt = WorkingTree.open_containing(u'.')[0]
1584
1563
        wt.lock_read()
1585
1564
        try:
1596
1575
                    path = inv.id2path(file_id)
1597
1576
                    if not os.access(osutils.abspath(path), os.F_OK):
1598
1577
                        continue
1599
 
                    if null:
1600
 
                        self.outf.write(path + '\0')
1601
 
                    else:
1602
 
                        self.outf.write(osutils.quotefn(path) + '\n')
 
1578
                    self.outf.write(path + '\n')
1603
1579
            finally:
1604
1580
                basis.unlock()
1605
1581
        finally:
1671
1647
                        'regular expression.',
1672
1648
                   type=str),
1673
1649
            Option('limit',
1674
 
                   short_name='l',
1675
1650
                   help='Limit the output to the first N revisions.',
1676
1651
                   argname='N',
1677
1652
                   type=_parse_limit),
1688
1663
            message=None,
1689
1664
            limit=None):
1690
1665
        from bzrlib.log import show_log
 
1666
        assert message is None or isinstance(message, basestring), \
 
1667
            "invalid message argument %r" % message
1691
1668
        direction = (forward and 'forward') or 'reverse'
1692
1669
        
1693
1670
        # log everything
1800
1777
            Option('from-root',
1801
1778
                   help='Print paths relative to the root of the branch.'),
1802
1779
            Option('unknown', help='Print unknown files.'),
1803
 
            Option('versioned', help='Print versioned files.',
1804
 
                   short_name='V'),
 
1780
            Option('versioned', help='Print versioned files.'),
1805
1781
            Option('ignored', help='Print ignored files.'),
1806
1782
            Option('null',
1807
1783
                   help='Write an ascii NUL (\\0) separator '
1843
1819
            relpath += '/'
1844
1820
        if revision is not None:
1845
1821
            tree = branch.repository.revision_tree(
1846
 
                revision[0].as_revision_id(branch))
 
1822
                revision[0].in_history(branch).rev_id)
1847
1823
        elif tree is None:
1848
1824
            tree = branch.basis_tree()
1849
1825
 
1900
1876
class cmd_ignore(Command):
1901
1877
    """Ignore specified files or patterns.
1902
1878
 
1903
 
    See ``bzr help patterns`` for details on the syntax of patterns.
1904
 
 
1905
1879
    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.
 
1880
 
 
1881
    Trailing slashes on patterns are ignored. 
 
1882
    If the pattern contains a slash or is a regular expression, it is compared 
 
1883
    to the whole path from the branch root.  Otherwise, it is compared to only
 
1884
    the last component of the path.  To match a file only in the root 
 
1885
    directory, prepend './'.
 
1886
 
 
1887
    Ignore patterns specifying absolute paths are not allowed.
 
1888
 
 
1889
    Ignore patterns may include globbing wildcards such as::
 
1890
 
 
1891
      ? - Matches any single character except '/'
 
1892
      * - Matches 0 or more characters except '/'
 
1893
      /**/ - Matches 0 or more directories in a path
 
1894
      [a-z] - Matches a single character from within a group of characters
 
1895
 
 
1896
    Ignore patterns may also be Python regular expressions.  
 
1897
    Regular expression ignore patterns are identified by a 'RE:' prefix 
 
1898
    followed by the regular expression.  Regular expression ignore patterns
 
1899
    may not include named or numbered groups.
1909
1900
 
1910
1901
    Note: ignore patterns containing shell wildcards must be quoted from 
1911
1902
    the shell on Unix.
1917
1908
 
1918
1909
        Ignore class files in all directories::
1919
1910
 
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/).*"
 
1911
            bzr ignore '*.class'
 
1912
 
 
1913
        Ignore .o files under the lib directory::
 
1914
 
 
1915
            bzr ignore 'lib/**/*.o'
 
1916
 
 
1917
        Ignore .o files under the lib directory::
 
1918
 
 
1919
            bzr ignore 'RE:lib/.*\.o'
1933
1920
    """
1934
1921
 
1935
 
    _see_also = ['status', 'ignored', 'patterns']
 
1922
    _see_also = ['status', 'ignored']
1936
1923
    takes_args = ['name_pattern*']
1937
1924
    takes_options = [
1938
1925
        Option('old-default-rules',
1940
1927
        ]
1941
1928
    
1942
1929
    def run(self, name_pattern_list=None, old_default_rules=None):
1943
 
        from bzrlib import ignores
 
1930
        from bzrlib.atomicfile import AtomicFile
1944
1931
        if old_default_rules is not None:
1945
1932
            # dump the rules and exit
1946
1933
            for pattern in ignores.OLD_DEFAULTS:
1957
1944
                raise errors.BzrCommandError(
1958
1945
                    "NAME_PATTERN should not be an absolute path")
1959
1946
        tree, relpath = WorkingTree.open_containing(u'.')
1960
 
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
 
1947
        ifn = tree.abspath('.bzrignore')
 
1948
        if os.path.exists(ifn):
 
1949
            f = open(ifn, 'rt')
 
1950
            try:
 
1951
                igns = f.read().decode('utf-8')
 
1952
            finally:
 
1953
                f.close()
 
1954
        else:
 
1955
            igns = ''
 
1956
 
 
1957
        # TODO: If the file already uses crlf-style termination, maybe
 
1958
        # we should use that for the newly added lines?
 
1959
 
 
1960
        if igns and igns[-1] != '\n':
 
1961
            igns += '\n'
 
1962
        for name_pattern in name_pattern_list:
 
1963
            igns += name_pattern + '\n'
 
1964
 
 
1965
        f = AtomicFile(ifn, 'wb')
 
1966
        try:
 
1967
            f.write(igns.encode('utf-8'))
 
1968
            f.commit()
 
1969
        finally:
 
1970
            f.close()
 
1971
 
 
1972
        if not tree.path2id('.bzrignore'):
 
1973
            tree.add(['.bzrignore'])
 
1974
 
1961
1975
        ignored = globbing.Globster(name_pattern_list)
1962
1976
        matches = []
1963
1977
        tree.lock_read()
1972
1986
            print "Warning: the following files are version controlled and" \
1973
1987
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
1974
1988
 
1975
 
 
1976
1989
class cmd_ignored(Command):
1977
1990
    """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
1991
    """
1986
1992
 
1987
 
    encoding_type = 'replace'
1988
 
    _see_also = ['ignore', 'ls']
1989
 
 
 
1993
    _see_also = ['ignore']
1990
1994
    @display_command
1991
1995
    def run(self):
1992
1996
        tree = WorkingTree.open_containing(u'.')[0]
1997
2001
                    continue
1998
2002
                ## XXX: Slightly inefficient since this was already calculated
1999
2003
                pat = tree.is_ignored(path)
2000
 
                self.outf.write('%-50s %s\n' % (path, pat))
 
2004
                print '%-50s %s' % (path, pat)
2001
2005
        finally:
2002
2006
            tree.unlock()
2003
2007
 
2049
2053
         zip                          .zip
2050
2054
      =================       =========================
2051
2055
    """
2052
 
    takes_args = ['dest', 'branch_or_subdir?']
 
2056
    takes_args = ['dest', 'branch?']
2053
2057
    takes_options = [
2054
2058
        Option('format',
2055
2059
               help="Type of file to export to.",
2059
2063
               type=str,
2060
2064
               help="Name of the root directory inside the exported file."),
2061
2065
        ]
2062
 
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2063
 
        root=None):
 
2066
    def run(self, dest, branch=None, revision=None, format=None, root=None):
2064
2067
        from bzrlib.export import export
2065
2068
 
2066
 
        if branch_or_subdir is None:
 
2069
        if branch is None:
2067
2070
            tree = WorkingTree.open_containing(u'.')[0]
2068
2071
            b = tree.branch
2069
 
            subdir = None
2070
2072
        else:
2071
 
            b, subdir = Branch.open_containing(branch_or_subdir)
 
2073
            b = Branch.open(branch)
2072
2074
            
2073
2075
        if revision is None:
2074
2076
            # should be tree.last_revision  FIXME
2076
2078
        else:
2077
2079
            if len(revision) != 1:
2078
2080
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2079
 
            rev_id = revision[0].as_revision_id(b)
 
2081
            rev_id = revision[0].in_history(b).rev_id
2080
2082
        t = b.repository.revision_tree(rev_id)
2081
2083
        try:
2082
 
            export(t, dest, format, root, subdir)
 
2084
            export(t, dest, format, root)
2083
2085
        except errors.NoSuchExportFormat, e:
2084
2086
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2085
2087
 
2105
2107
    def run(self, filename, revision=None, name_from_revision=False):
2106
2108
        if revision is not None and len(revision) != 1:
2107
2109
            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()
 
2110
                                        " one number")
 
2111
 
 
2112
        tree = None
2112
2113
        try:
2113
 
            return self._run(tree, branch, relpath, filename, revision,
2114
 
                             name_from_revision)
2115
 
        finally:
2116
 
            branch.unlock()
 
2114
            tree, b, relpath = \
 
2115
                    bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
2116
        except errors.NotBranchError:
 
2117
            pass
2117
2118
 
2118
 
    def _run(self, tree, b, relpath, filename, revision, name_from_revision):
 
2119
        if revision is not None and revision[0].get_branch() is not None:
 
2120
            b = Branch.open(revision[0].get_branch())
2119
2121
        if tree is None:
2120
2122
            tree = b.basis_tree()
2121
2123
        if revision is None:
2122
2124
            revision_id = b.last_revision()
2123
2125
        else:
2124
 
            revision_id = revision[0].as_revision_id(b)
 
2126
            revision_id = revision[0].in_history(b).rev_id
2125
2127
 
2126
2128
        cur_file_id = tree.path2id(relpath)
2127
2129
        rev_tree = b.repository.revision_tree(revision_id)
2132
2134
                raise errors.BzrCommandError("%r is not present in revision %s"
2133
2135
                                                % (filename, revision_id))
2134
2136
            else:
2135
 
                content = rev_tree.get_file_text(old_file_id)
 
2137
                rev_tree.print_file(old_file_id)
2136
2138
        elif cur_file_id is not None:
2137
 
            content = rev_tree.get_file_text(cur_file_id)
 
2139
            rev_tree.print_file(cur_file_id)
2138
2140
        elif old_file_id is not None:
2139
 
            content = rev_tree.get_file_text(old_file_id)
 
2141
            rev_tree.print_file(old_file_id)
2140
2142
        else:
2141
2143
            raise errors.BzrCommandError("%r is not present in revision %s" %
2142
2144
                                         (filename, revision_id))
2143
 
        self.outf.write(content)
2144
2145
 
2145
2146
 
2146
2147
class cmd_local_time_offset(Command):
2161
2162
    committed.  If a directory is specified then the directory and everything 
2162
2163
    within it is committed.
2163
2164
 
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
2165
    If author of the change is not the same person as the committer, you can
2171
2166
    specify the author's name using the --author option. The name should be
2172
2167
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2202
2197
    _see_also = ['bugs', 'uncommit']
2203
2198
    takes_args = ['selected*']
2204
2199
    takes_options = [
2205
 
            ListOption('exclude', type=str, short_name='x',
2206
 
                help="Do not consider changes made to a given path."),
2207
2200
            Option('message', type=unicode,
2208
2201
                   short_name='m',
2209
2202
                   help="Description of the new revision."),
2219
2212
                    "files in the working tree."),
2220
2213
             ListOption('fixes', type=str,
2221
2214
                    help="Mark a bug as being fixed by this revision."),
2222
 
             Option('author', type=unicode,
 
2215
             Option('author', type=str,
2223
2216
                    help="Set the author's name, if it's different "
2224
2217
                         "from the committer."),
2225
2218
             Option('local',
2258
2251
 
2259
2252
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2260
2253
            unchanged=False, strict=False, local=False, fixes=None,
2261
 
            author=None, show_diff=False, exclude=None):
 
2254
            author=None, show_diff=False):
2262
2255
        from bzrlib.errors import (
2263
2256
            PointlessCommit,
2264
2257
            ConflictsInTree,
2308
2301
                raise errors.BzrCommandError(
2309
2302
                    "please specify either --message or --file")
2310
2303
            if file:
2311
 
                my_message = codecs.open(file, 'rt',
 
2304
                my_message = codecs.open(file, 'rt', 
2312
2305
                                         bzrlib.user_encoding).read()
2313
2306
            if my_message == "":
2314
2307
                raise errors.BzrCommandError("empty commit message specified")
2319
2312
                        specific_files=selected_list,
2320
2313
                        allow_pointless=unchanged, strict=strict, local=local,
2321
2314
                        reporter=None, verbose=verbose, revprops=properties,
2322
 
                        author=author,
2323
 
                        exclude=safe_relpath_files(tree, exclude))
 
2315
                        author=author)
2324
2316
        except PointlessCommit:
2325
2317
            # FIXME: This should really happen before the file is read in;
2326
2318
            # perhaps prepare the commit; get the message; then actually commit
2341
2333
 
2342
2334
 
2343
2335
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:
 
2336
    """Validate consistency of branch history.
 
2337
 
 
2338
    This command checks various invariants about the branch storage to
 
2339
    detect data corruption or bzr bugs.
 
2340
 
 
2341
    Output fields:
2351
2342
 
2352
2343
        revisions: This is just the number of revisions checked.  It doesn't
2353
2344
            indicate a problem.
2362
2353
            in the checked revisions.  Texts can be repeated when their file
2363
2354
            entries are modified, but the file contents are not.  It does not
2364
2355
            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
2382
2356
    """
2383
2357
 
2384
2358
    _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.")]
 
2359
    takes_args = ['branch?']
 
2360
    takes_options = ['verbose']
2393
2361
 
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)
 
2362
    def run(self, branch=None, verbose=False):
 
2363
        from bzrlib.check import check
 
2364
        if branch is None:
 
2365
            branch = Branch.open_containing('.')[0]
 
2366
        else:
 
2367
            branch = Branch.open(branch)
 
2368
        check(branch, verbose)
2402
2369
 
2403
2370
 
2404
2371
class cmd_upgrade(Command):
2437
2404
 
2438
2405
        Set the current user::
2439
2406
 
2440
 
            bzr whoami "Frank Chu <fchu@example.com>"
 
2407
            bzr whoami 'Frank Chu <fchu@example.com>'
2441
2408
    """
2442
2409
    takes_options = [ Option('email',
2443
2410
                             help='Display email address only.'),
2498
2465
        print branch.nick
2499
2466
 
2500
2467
 
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
2468
class cmd_selftest(Command):
2572
2469
    """Run internal test suite.
2573
2470
    
2662
2559
                                 ' expression.'),
2663
2560
                     Option('strict', help='Fail on missing dependencies or '
2664
2561
                            '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.'),
2673
2562
                     ]
2674
2563
    encoding_type = 'replace'
2675
2564
 
2677
2566
            transport=None, benchmark=None,
2678
2567
            lsprof_timed=None, cache_dir=None,
2679
2568
            first=False, list_only=False,
2680
 
            randomize=None, exclude=None, strict=False,
2681
 
            load_list=None, debugflag=None, starting_with=None):
 
2569
            randomize=None, exclude=None, strict=False):
2682
2570
        import bzrlib.ui
2683
2571
        from bzrlib.tests import selftest
2684
2572
        import bzrlib.benchmarks as benchmarks
2685
2573
        from bzrlib.benchmarks import tree_creator
2686
2574
 
2687
 
        # Make deprecation warnings visible, unless -Werror is set
2688
 
        symbol_versioning.activate_deprecation_warnings(override=False)
2689
 
 
2690
2575
        if cache_dir is not None:
2691
2576
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2692
2577
        if not list_only:
2694
2579
            print '   %s (%s python%s)' % (
2695
2580
                    bzrlib.__path__[0],
2696
2581
                    bzrlib.version_string,
2697
 
                    bzrlib._format_version_tuple(sys.version_info),
 
2582
                    '.'.join(map(str, sys.version_info)),
2698
2583
                    )
2699
2584
        print
2700
2585
        if testspecs_list is not None:
2723
2608
                              random_seed=randomize,
2724
2609
                              exclude_pattern=exclude,
2725
2610
                              strict=strict,
2726
 
                              load_list=load_list,
2727
 
                              debug_flags=debugflag,
2728
 
                              starting_with=starting_with,
2729
2611
                              )
2730
2612
        finally:
2731
2613
            if benchfile is not None:
2732
2614
                benchfile.close()
2733
2615
        if result:
2734
 
            note('tests passed')
 
2616
            info('tests passed')
2735
2617
        else:
2736
 
            note('tests failed')
 
2618
            info('tests failed')
2737
2619
        return int(not result)
2738
2620
 
2739
2621
 
2741
2623
    """Show version of bzr."""
2742
2624
 
2743
2625
    encoding_type = 'replace'
2744
 
    takes_options = [
2745
 
        Option("short", help="Print just the version number."),
2746
 
        ]
2747
2626
 
2748
2627
    @display_command
2749
 
    def run(self, short=False):
 
2628
    def run(self):
2750
2629
        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)
 
2630
        show_version(to_file=self.outf)
2755
2631
 
2756
2632
 
2757
2633
class cmd_rocks(Command):
2777
2653
        
2778
2654
        branch1 = Branch.open_containing(branch)[0]
2779
2655
        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()
 
2656
 
 
2657
        last1 = ensure_null(branch1.last_revision())
 
2658
        last2 = ensure_null(branch2.last_revision())
 
2659
 
 
2660
        graph = branch1.repository.get_graph(branch2.repository)
 
2661
        base_rev_id = graph.find_unique_lca(last1, last2)
 
2662
 
 
2663
        print 'merge base is revision %s' % base_rev_id
2795
2664
 
2796
2665
 
2797
2666
class cmd_merge(Command):
2798
2667
    """Perform a three-way merge.
2799
2668
    
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.
 
2669
    The branch is the branch you will merge from.  By default, it will merge
 
2670
    the latest revision.  If you specify a revision, that revision will be
 
2671
    merged.  If you specify two revisions, the first will be used as a BASE,
 
2672
    and the second one as OTHER.  Revision numbers are always relative to the
 
2673
    specified branch.
2811
2674
 
2812
2675
    By default, bzr will try to merge in all new work from the other
2813
2676
    branch, automatically determining an appropriate base.  If this
2844
2707
        To merge the changes introduced by 82, without previous changes::
2845
2708
 
2846
2709
            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
2710
    """
2852
2711
 
2853
 
    encoding_type = 'exact'
2854
2712
    _see_also = ['update', 'remerge', 'status-flags']
2855
 
    takes_args = ['location?']
 
2713
    takes_args = ['branch?']
2856
2714
    takes_options = [
2857
2715
        'change',
2858
2716
        'revision',
2875
2733
               short_name='d',
2876
2734
               type=unicode,
2877
2735
               ),
2878
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
2879
2736
    ]
2880
2737
 
2881
 
    def run(self, location=None, revision=None, force=False,
2882
 
            merge_type=None, show_base=False, reprocess=False, remember=False,
 
2738
    def run(self, branch=None, revision=None, force=False, merge_type=None,
 
2739
            show_base=False, reprocess=False, remember=False,
2883
2740
            uncommitted=False, pull=False,
2884
2741
            directory=None,
2885
 
            preview=False,
2886
2742
            ):
 
2743
        # This is actually a branch (or merge-directive) *location*.
 
2744
        location = branch
 
2745
        del branch
 
2746
 
2887
2747
        if merge_type is None:
2888
2748
            merge_type = _mod_merge.Merge3Merger
2889
2749
 
2902
2762
            tree.lock_write()
2903
2763
            cleanups.append(tree.unlock)
2904
2764
            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
2910
 
                else:
 
2765
                mergeable, other_transport = _get_mergeable_helper(location)
 
2766
                if mergeable:
2911
2767
                    if uncommitted:
2912
2768
                        raise errors.BzrCommandError('Cannot use --uncommitted'
2913
2769
                            ' with bundles or merge directives.')
2917
2773
                            'Cannot use -r with merge directives or bundles')
2918
2774
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
2919
2775
                       mergeable, pb)
 
2776
                possible_transports.append(other_transport)
2920
2777
 
2921
2778
            if merger is None and uncommitted:
2922
2779
                if revision is not None and len(revision) > 0:
2927
2784
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
2928
2785
                    pb)
2929
2786
                allow_pending = False
2930
 
                if other_path != '':
2931
 
                    merger.interesting_files = [other_path]
2932
2787
 
2933
2788
            if merger is None:
2934
2789
                merger, allow_pending = self._get_merger_from_branch(tree,
2937
2792
            merger.merge_type = merge_type
2938
2793
            merger.reprocess = reprocess
2939
2794
            merger.show_base = show_base
 
2795
            merger.change_reporter = change_reporter
2940
2796
            self.sanity_check_merger(merger)
2941
2797
            if (merger.base_rev_id == merger.other_rev_id and
2942
 
                merger.other_rev_id is not None):
 
2798
                merger.other_rev_id != None):
2943
2799
                note('Nothing to do.')
2944
2800
                return 0
2945
2801
            if pull:
2951
2807
                    result.report(self.outf)
2952
2808
                    return 0
2953
2809
            merger.check_basis(not force)
2954
 
            if preview:
2955
 
                return self._do_preview(merger)
 
2810
            conflict_count = merger.do_merge()
 
2811
            if allow_pending:
 
2812
                merger.set_pending()
 
2813
            if verified == 'failed':
 
2814
                warning('Preview patch does not match changes')
 
2815
            if conflict_count != 0:
 
2816
                return 1
2956
2817
            else:
2957
 
                return self._do_merge(merger, change_reporter, allow_pending,
2958
 
                                      verified)
 
2818
                return 0
2959
2819
        finally:
2960
2820
            for cleanup in reversed(cleanups):
2961
2821
                cleanup()
2962
2822
 
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
2823
    def sanity_check_merger(self, merger):
2987
2824
        if (merger.show_base and
2988
2825
            not merger.merge_type is _mod_merge.Merge3Merger):
3000
2837
                                possible_transports, pb):
3001
2838
        """Produce a merger from a location, assuming it refers to a branch."""
3002
2839
        from bzrlib.tag import _merge_tags_if_possible
 
2840
        assert revision is None or len(revision) < 3
3003
2841
        # find the branch locations
3004
 
        other_loc, user_location = self._select_branch_location(tree, location,
 
2842
        other_loc, location = self._select_branch_location(tree, location,
3005
2843
            revision, -1)
3006
2844
        if revision is not None and len(revision) == 2:
3007
 
            base_loc, _unused = self._select_branch_location(tree,
3008
 
                location, revision, 0)
 
2845
            base_loc, location = self._select_branch_location(tree, location,
 
2846
                                                              revision, 0)
3009
2847
        else:
3010
2848
            base_loc = other_loc
3011
2849
        # Open the branches
3021
2859
            other_revision_id = _mod_revision.ensure_null(
3022
2860
                other_branch.last_revision())
3023
2861
        else:
3024
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
 
2862
            other_revision_id = \
 
2863
                _mod_revision.ensure_null(
 
2864
                    revision[-1].in_history(other_branch).rev_id)
3025
2865
        if (revision is not None and len(revision) == 2
3026
2866
            and revision[0] is not None):
3027
 
            base_revision_id = revision[0].as_revision_id(base_branch)
 
2867
            base_revision_id = \
 
2868
                _mod_revision.ensure_null(
 
2869
                    revision[0].in_history(base_branch).rev_id)
3028
2870
        else:
3029
2871
            base_revision_id = None
3030
2872
        # 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)
 
2873
        if ((tree.branch.get_parent() is None or remember) and
 
2874
            other_branch is not None):
 
2875
            tree.branch.set_parent(other_branch.base)
3034
2876
        _merge_tags_if_possible(other_branch, tree.branch)
3035
2877
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3036
2878
            other_revision_id, base_revision_id, other_branch, base_branch)
3041
2883
            allow_pending = True
3042
2884
        return merger, allow_pending
3043
2885
 
3044
 
    def _select_branch_location(self, tree, user_location, revision=None,
 
2886
    def _select_branch_location(self, tree, location, revision=None,
3045
2887
                                index=None):
3046
2888
        """Select a branch location, according to possible inputs.
3047
2889
 
3049
2891
        ``revision`` and ``index`` must be supplied.)
3050
2892
 
3051
2893
        Otherwise, the ``location`` parameter is used.  If it is None, then the
3052
 
        ``submit`` or ``parent`` location is used, and a note is printed.
 
2894
        ``parent`` location is used, and a note is printed.
3053
2895
 
3054
2896
        :param tree: The working tree to select a branch for merging into
3055
2897
        :param location: The location entered by the user
3056
2898
        :param revision: The revision parameter to the command
3057
2899
        :param index: The index to use for the revision parameter.  Negative
3058
2900
            indices are permitted.
3059
 
        :return: (selected_location, user_location).  The default location
3060
 
            will be the user-entered location.
 
2901
        :return: (selected_location, default_location).  The default location
 
2902
            will be the user-entered location, if any, or else the remembered
 
2903
            location.
3061
2904
        """
3062
2905
        if (revision is not None and index is not None
3063
2906
            and revision[index] is not None):
3064
2907
            branch = revision[index].get_branch()
3065
2908
            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
 
2909
                return branch, location
 
2910
        location = self._get_remembered_parent(tree, location, 'Merging from')
 
2911
        return location, location
3072
2912
 
3073
 
    def _get_remembered(self, tree, verb_string):
 
2913
    # TODO: move up to common parent; this isn't merge-specific anymore. 
 
2914
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
3074
2915
        """Use tree.branch's parent if none was supplied.
3075
2916
 
3076
2917
        Report if the remembered location was used.
3077
2918
        """
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"
 
2919
        if supplied_location is not None:
 
2920
            return supplied_location
 
2921
        stored_location = tree.branch.get_parent()
3083
2922
        mutter("%s", stored_location)
3084
2923
        if stored_location is None:
3085
2924
            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)
 
2925
        display_url = urlutils.unescape_for_display(stored_location,
 
2926
            self.outf.encoding)
 
2927
        self.outf.write("%s remembered location %s\n" % (verb_string,
 
2928
            display_url))
3089
2929
        return stored_location
3090
2930
 
3091
2931
 
3132
2972
                                             " merges.  Not cherrypicking or"
3133
2973
                                             " multi-merges.")
3134
2974
            repository = tree.branch.repository
 
2975
            graph = repository.get_graph()
 
2976
            base_revision = graph.find_unique_lca(parents[0], parents[1])
 
2977
            base_tree = repository.revision_tree(base_revision)
 
2978
            other_tree = repository.revision_tree(parents[1])
3135
2979
            interesting_ids = None
3136
2980
            new_conflicts = []
3137
2981
            conflicts = tree.conflicts()
3167
3011
            # list, we imply that the working tree text has seen and rejected
3168
3012
            # all the changes from the other tree, when in fact those changes
3169
3013
            # have not yet been seen.
3170
 
            pb = ui.ui_factory.nested_progress_bar()
3171
3014
            tree.set_parent_ids(parents[:1])
3172
3015
            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()
 
3016
                conflicts = _mod_merge.merge_inner(
 
3017
                                          tree.branch, other_tree, base_tree,
 
3018
                                          this_tree=tree,
 
3019
                                          interesting_ids=interesting_ids,
 
3020
                                          other_rev_id=parents[1],
 
3021
                                          merge_type=merge_type,
 
3022
                                          show_base=show_base,
 
3023
                                          reprocess=reprocess)
3180
3024
            finally:
3181
3025
                tree.set_parent_ids(parents)
3182
 
                pb.finished()
3183
3026
        finally:
3184
3027
            tree.unlock()
3185
3028
        if conflicts > 0:
3196
3039
    last committed revision is used.
3197
3040
 
3198
3041
    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.
 
3042
    merge instead.  For example, "merge . --r-2..-3" will remove the changes
 
3043
    introduced by -2, without affecting the changes introduced by -1.  Or
 
3044
    to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
3202
3045
    
3203
3046
    By default, any files that have been manually changed will be backed up
3204
3047
    first.  (Files changed only by merge are not backed up.)  Backup files have
3215
3058
 
3216
3059
    The working tree contains a list of pending merged revisions, which will
3217
3060
    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
 
3061
    list as well as reverting the files.  If any files, are specified, revert
 
3062
    leaves the pending merge list alnone and reverts only the files.  Use "bzr
3220
3063
    revert ." in the tree root to revert all files but keep the merge record,
3221
3064
    and "bzr revert --forget-merges" to clear the pending merge list without
3222
3065
    reverting any files.
3246
3089
        elif len(revision) != 1:
3247
3090
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3248
3091
        else:
3249
 
            rev_id = revision[0].as_revision_id(tree.branch)
 
3092
            rev_id = revision[0].in_history(tree.branch).rev_id
3250
3093
        pb = ui.ui_factory.nested_progress_bar()
3251
3094
        try:
3252
3095
            tree.revert(file_list,
3300
3143
        shellcomplete.shellcomplete(context)
3301
3144
 
3302
3145
 
 
3146
class cmd_fetch(Command):
 
3147
    """Copy in history from another branch but don't merge it.
 
3148
 
 
3149
    This is an internal method used for pull and merge.
 
3150
    """
 
3151
    hidden = True
 
3152
    takes_args = ['from_branch', 'to_branch']
 
3153
    def run(self, from_branch, to_branch):
 
3154
        from bzrlib.fetch import Fetcher
 
3155
        from_b = Branch.open(from_branch)
 
3156
        to_b = Branch.open(to_branch)
 
3157
        Fetcher(to_b, from_b)
 
3158
 
 
3159
 
3303
3160
class cmd_missing(Command):
3304
3161
    """Show unmerged/unpulled revisions between two branches.
3305
3162
    
3329
3186
        from bzrlib.missing import find_unmerged, iter_log_revisions
3330
3187
 
3331
3188
        if this:
3332
 
            mine_only = this
 
3189
          mine_only = this
3333
3190
        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'
 
3191
          theirs_only = other
3343
3192
 
3344
3193
        local_branch = Branch.open_containing(u".")[0]
3345
3194
        parent = local_branch.get_parent()
3350
3199
                                             " or specified.")
3351
3200
            display_url = urlutils.unescape_for_display(parent,
3352
3201
                                                        self.outf.encoding)
3353
 
            self.outf.write("Using saved parent location: "
3354
 
                    + display_url + "\n")
 
3202
            self.outf.write("Using last location: " + display_url + "\n")
3355
3203
 
3356
3204
        remote_branch = Branch.open(other_branch)
3357
3205
        if remote_branch.base == local_branch.base:
3360
3208
        try:
3361
3209
            remote_branch.lock_read()
3362
3210
            try:
3363
 
                local_extra, remote_extra = find_unmerged(
3364
 
                    local_branch, remote_branch, restrict)
3365
 
 
 
3211
                local_extra, remote_extra = find_unmerged(local_branch,
 
3212
                                                          remote_branch)
3366
3213
                if log_format is None:
3367
3214
                    registry = log.log_formatter_registry
3368
3215
                    log_format = registry.get_default(local_branch)
3370
3217
                                show_ids=show_ids,
3371
3218
                                show_timezone='original')
3372
3219
                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
 
3220
                    local_extra.reverse()
 
3221
                    remote_extra.reverse()
3379
3222
                if local_extra and not theirs_only:
3380
3223
                    self.outf.write("You have %d extra revision(s):\n" %
3381
3224
                                    len(local_extra))
3384
3227
                                        verbose):
3385
3228
                        lf.log_revision(revision)
3386
3229
                    printed_local = True
3387
 
                    status_code = 1
3388
3230
                else:
3389
3231
                    printed_local = False
3390
 
 
3391
3232
                if remote_extra and not mine_only:
3392
3233
                    if printed_local is True:
3393
3234
                        self.outf.write("\n\n\n")
3397
3238
                                        remote_branch.repository,
3398
3239
                                        verbose):
3399
3240
                        lf.log_revision(revision)
3400
 
                    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
 
3241
                if not remote_extra and not local_extra:
 
3242
                    status_code = 0
3412
3243
                    self.outf.write("Branches are up to date.\n")
 
3244
                else:
 
3245
                    status_code = 1
3413
3246
            finally:
3414
3247
                remote_branch.unlock()
3415
3248
        finally:
3444
3277
class cmd_plugins(Command):
3445
3278
    """List the installed plugins.
3446
3279
    
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.
 
3280
    This command displays the list of installed plugins including the
 
3281
    path where each one is located and a short description of each.
3451
3282
 
3452
3283
    A plugin is an external component for Bazaar that extends the
3453
3284
    revision control system, by adding or replacing code in Bazaar.
3460
3291
    install them. Instructions are also provided there on how to
3461
3292
    write new plugins using the Python programming language.
3462
3293
    """
3463
 
    takes_options = ['verbose']
3464
3294
 
3465
3295
    @display_command
3466
 
    def run(self, verbose=False):
 
3296
    def run(self):
3467
3297
        import bzrlib.plugin
3468
3298
        from inspect import getdoc
3469
 
        result = []
3470
3299
        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)
 
3300
            print plugin.path(), "[%s]" % plugin.__version__
3475
3301
            d = getdoc(plugin.module)
3476
3302
            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
 
3303
                print '\t', d.split('\n')[0]
3487
3304
 
3488
3305
 
3489
3306
class cmd_testament(Command):
3501
3318
            testament_class = StrictTestament
3502
3319
        else:
3503
3320
            testament_class = Testament
3504
 
        if branch == '.':
3505
 
            b = Branch.open_containing(branch)[0]
3506
 
        else:
3507
 
            b = Branch.open(branch)
 
3321
        b = WorkingTree.open_containing(branch)[0].branch
3508
3322
        b.lock_read()
3509
3323
        try:
3510
3324
            if revision is None:
3511
3325
                rev_id = b.last_revision()
3512
3326
            else:
3513
 
                rev_id = revision[0].as_revision_id(b)
 
3327
                rev_id = revision[0].in_history(b).rev_id
3514
3328
            t = testament_class.from_revision(b.repository, rev_id)
3515
3329
            if long:
3516
3330
                sys.stdout.writelines(t.as_text_lines())
3545
3359
    def run(self, filename, all=False, long=False, revision=None,
3546
3360
            show_ids=False):
3547
3361
        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()
 
3362
        tree, relpath = WorkingTree.open_containing(filename)
 
3363
        branch = tree.branch
 
3364
        branch.lock_read()
3554
3365
        try:
3555
3366
            if revision is None:
3556
3367
                revision_id = branch.last_revision()
3557
3368
            elif len(revision) != 1:
3558
3369
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3559
3370
            else:
3560
 
                revision_id = revision[0].as_revision_id(branch)
3561
 
            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)
 
3371
                revision_id = revision[0].in_history(branch).rev_id
 
3372
            file_id = tree.path2id(relpath)
3566
3373
            if file_id is None:
3567
3374
                raise errors.NotVersionedError(filename)
 
3375
            tree = branch.repository.revision_tree(revision_id)
3568
3376
            file_version = tree.inventory[file_id].revision
3569
3377
            annotate_file(branch, file_version, file_id, long, all, self.outf,
3570
3378
                          show_ids=show_ids)
3571
3379
        finally:
3572
 
            if wt is not None:
3573
 
                wt.unlock()
3574
 
            else:
3575
 
                branch.unlock()
 
3380
            branch.unlock()
3576
3381
 
3577
3382
 
3578
3383
class cmd_re_sign(Command):
3584
3389
    takes_options = ['revision']
3585
3390
    
3586
3391
    def run(self, revision_id_list=None, revision=None):
 
3392
        import bzrlib.gpg as gpg
3587
3393
        if revision_id_list is not None and revision is not None:
3588
3394
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3589
3395
        if revision_id_list is None and revision is None:
3590
3396
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3591
3397
        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
3398
        gpg_strategy = gpg.GPGStrategy(b.get_config())
3601
3399
        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()
 
3400
            for revision_id in revision_id_list:
 
3401
                b.repository.sign_revision(revision_id, gpg_strategy)
3611
3402
        elif revision is not None:
3612
3403
            if len(revision) == 1:
3613
3404
                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()
 
3405
                b.repository.sign_revision(rev_id, gpg_strategy)
3622
3406
            elif len(revision) == 2:
3623
3407
                # are they both on rh- if so we can walk between them
3624
3408
                # might be nice to have a range helper for arbitrary
3629
3413
                    to_revno = b.revno()
3630
3414
                if from_revno is None or to_revno is None:
3631
3415
                    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()
 
3416
                for revno in range(from_revno, to_revno + 1):
 
3417
                    b.repository.sign_revision(b.get_rev_id(revno), 
 
3418
                                               gpg_strategy)
3642
3419
            else:
3643
3420
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
3644
3421
 
3702
3479
    specified revision.  For example, "bzr uncommit -r 15" will leave the
3703
3480
    branch at revision 15.
3704
3481
 
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.
 
3482
    In the future, uncommit will create a revision bundle, which can then
 
3483
    be re-applied.
3708
3484
    """
3709
3485
 
3710
3486
    # TODO: jam 20060108 Add an option to allow uncommit to remove
3714
3490
    _see_also = ['commit']
3715
3491
    takes_options = ['verbose', 'revision',
3716
3492
                    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
 
                    ]
 
3493
                    Option('force', help='Say yes to all questions.')]
3723
3494
    takes_args = ['location?']
3724
3495
    aliases = []
3725
 
    encoding_type = 'replace'
3726
3496
 
3727
3497
    def run(self, location=None,
3728
3498
            dry_run=False, verbose=False,
3729
 
            revision=None, force=False, local=False):
 
3499
            revision=None, force=False):
 
3500
        from bzrlib.log import log_formatter, show_log
 
3501
        from bzrlib.uncommit import uncommit
 
3502
 
3730
3503
        if location is None:
3731
3504
            location = u'.'
3732
3505
        control, relpath = bzrdir.BzrDir.open_containing(location)
3737
3510
            tree = None
3738
3511
            b = control.open_branch()
3739
3512
 
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
3513
        rev_id = None
3760
3514
        if revision is None:
3761
 
            revno = last_revno
3762
 
            rev_id = last_rev_id
 
3515
            revno = b.revno()
3763
3516
        else:
3764
3517
            # 'bzr uncommit -r 10' actually means uncommit
3765
3518
            # so that the final tree is at revno 10.
3766
3519
            # but bzrlib.uncommit.uncommit() actually uncommits
3767
3520
            # the revisions that are supplied.
3768
3521
            # 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)
 
3522
            revno = revision[0].in_history(b).revno+1
3772
3523
 
3773
 
        if rev_id is None or _mod_revision.is_null(rev_id):
 
3524
        if revno <= b.revno():
 
3525
            rev_id = b.get_rev_id(revno)
 
3526
        if rev_id is None:
3774
3527
            self.outf.write('No revisions to uncommit.\n')
3775
3528
            return 1
3776
3529
 
3783
3536
                 verbose=False,
3784
3537
                 direction='forward',
3785
3538
                 start_revision=revno,
3786
 
                 end_revision=last_revno)
 
3539
                 end_revision=b.revno())
3787
3540
 
3788
3541
        if dry_run:
3789
3542
            print 'Dry-run, pretending to remove the above revisions.'
3797
3550
                    print 'Canceled'
3798
3551
                    return 0
3799
3552
 
3800
 
        mutter('Uncommitting from {%s} to {%s}',
3801
 
               last_rev_id, rev_id)
3802
3553
        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)
 
3554
                revno=revno)
3806
3555
 
3807
3556
 
3808
3557
class cmd_break_lock(Command):
3867
3616
        ]
3868
3617
 
3869
3618
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
3870
 
        from bzrlib import lockdir
3871
3619
        from bzrlib.smart import medium, server
3872
3620
        from bzrlib.transport import get_transport
3873
3621
        from bzrlib.transport.chroot import ChrootServer
 
3622
        from bzrlib.transport.remote import BZR_DEFAULT_PORT, BZR_DEFAULT_INTERFACE
3874
3623
        if directory is None:
3875
3624
            directory = os.getcwd()
3876
3625
        url = urlutils.local_path_to_url(directory)
3883
3632
            smart_server = medium.SmartServerPipeStreamMedium(
3884
3633
                sys.stdin, sys.stdout, t)
3885
3634
        else:
3886
 
            host = medium.BZR_DEFAULT_INTERFACE
 
3635
            host = BZR_DEFAULT_INTERFACE
3887
3636
            if port is None:
3888
 
                port = medium.BZR_DEFAULT_PORT
 
3637
                port = BZR_DEFAULT_PORT
3889
3638
            else:
3890
3639
                if ':' in port:
3891
3640
                    host, port = port.split(':')
3898
3647
        # be changed with care though, as we dont want to use bandwidth sending
3899
3648
        # progress over stderr to smart server clients!
3900
3649
        old_factory = ui.ui_factory
3901
 
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
3902
3650
        try:
3903
3651
            ui.ui_factory = ui.SilentUIFactory()
3904
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
3905
3652
            smart_server.serve()
3906
3653
        finally:
3907
3654
            ui.ui_factory = old_factory
3908
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
3909
3655
 
3910
3656
 
3911
3657
class cmd_join(Command):
3963
3709
 
3964
3710
 
3965
3711
class cmd_split(Command):
3966
 
    """Split a subdirectory of a tree into a separate tree.
 
3712
    """Split a tree into two trees.
3967
3713
 
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'.
 
3714
    This command is for experimental use only.  It requires the target tree
 
3715
    to be in dirstate-with-subtree format, which cannot be converted into
 
3716
    earlier formats.
3971
3717
 
3972
3718
    The TREE argument should be a subdirectory of a working tree.  That
3973
3719
    subdirectory will be converted into an independent tree, with its own
3974
3720
    branch.  Commits in the top-level tree will not apply to the new subtree.
 
3721
    If you want that behavior, do "bzr join --reference TREE".
3975
3722
    """
3976
3723
 
3977
 
    # join is not un-hidden yet
3978
 
    #_see_also = ['join']
 
3724
    _see_also = ['join']
3979
3725
    takes_args = ['tree']
3980
3726
 
 
3727
    hidden = True
 
3728
 
3981
3729
    def run(self, tree):
3982
3730
        containing_tree, subdir = WorkingTree.open_containing(tree)
3983
3731
        sub_id = containing_tree.path2id(subdir)
3989
3737
            raise errors.UpgradeRequired(containing_tree.branch.base)
3990
3738
 
3991
3739
 
 
3740
 
3992
3741
class cmd_merge_directive(Command):
3993
3742
    """Generate a merge directive for auto-merge tools.
3994
3743
 
4063
3812
            if len(revision) > 2:
4064
3813
                raise errors.BzrCommandError('bzr merge-directive takes '
4065
3814
                    'at most two one revision identifiers')
4066
 
            revision_id = revision[-1].as_revision_id(branch)
 
3815
            revision_id = revision[-1].in_history(branch).rev_id
4067
3816
            if len(revision) == 2:
4068
 
                base_revision_id = revision[0].as_revision_id(branch)
 
3817
                base_revision_id = revision[0].in_history(branch).rev_id
 
3818
                base_revision_id = ensure_null(base_revision_id)
4069
3819
        else:
4070
3820
            revision_id = branch.last_revision()
4071
3821
        revision_id = ensure_null(revision_id)
4115
3865
    for that mirror.
4116
3866
 
4117
3867
    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.
 
3868
    on Windows (it uses MAPI).  On *nix, it requires the xdg-email utility.  If
 
3869
    the preferred client can't be found (or used), your editor will be used.
4120
3870
    
4121
3871
    To use a specific mail program, set the mail_client configuration option.
4122
3872
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4123
3873
    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.
 
3874
    generic options are "default", "editor", "mapi", and "xdg-email".
4126
3875
 
4127
3876
    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.
 
3877
    either on the commandline, or by setting the submit_to configuration
 
3878
    option.
4131
3879
 
4132
3880
    Two formats are currently supported: "4" uses revision bundle format 4 and
4133
3881
    merge directive format 2.  It is significantly faster and smaller than
4134
3882
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4135
3883
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4136
3884
    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
3885
    """
4140
3886
 
4141
3887
    encoding_type = 'exact'
4142
3888
 
4143
 
    _see_also = ['merge', 'pull']
 
3889
    _see_also = ['merge']
4144
3890
 
4145
3891
    takes_args = ['submit_branch?', 'public_branch?']
4146
3892
 
4156
3902
               'rather than the one containing the working directory.',
4157
3903
               short_name='f',
4158
3904
               type=unicode),
4159
 
        Option('output', short_name='o',
4160
 
               help='Write merge directive to this file; '
4161
 
                    'use - for stdout.',
 
3905
        Option('output', short_name='o', help='Write directive to this file.',
4162
3906
               type=unicode),
4163
3907
        Option('mail-to', help='Mail the request to this address.',
4164
3908
               type=unicode),
4180
3924
    def _run(self, submit_branch, revision, public_branch, remember, format,
4181
3925
             no_bundle, no_patch, output, from_, mail_to, message):
4182
3926
        from bzrlib.revision import NULL_REVISION
4183
 
        branch = Branch.open_containing(from_)[0]
4184
3927
        if output is None:
4185
3928
            outfile = StringIO()
4186
3929
        elif output == '-':
4187
3930
            outfile = self.outf
4188
3931
        else:
4189
3932
            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
3933
        try:
 
3934
            branch = Branch.open_containing(from_)[0]
4194
3935
            if output is None:
4195
3936
                config = branch.get_config()
4196
3937
                if mail_to is None:
4197
3938
                    mail_to = config.get_user_option('submit_to')
 
3939
                if mail_to is None:
 
3940
                    raise errors.BzrCommandError('No mail-to address'
 
3941
                                                 ' specified')
4198
3942
                mail_client = config.get_mail_client()
4199
3943
            if remember and submit_branch is None:
4200
3944
                raise errors.BzrCommandError(
4201
3945
                    '--remember requires a branch to be specified.')
4202
3946
            stored_submit_branch = branch.get_submit_branch()
4203
 
            remembered_submit_branch = None
 
3947
            remembered_submit_branch = False
4204
3948
            if submit_branch is None:
4205
3949
                submit_branch = stored_submit_branch
4206
 
                remembered_submit_branch = "submit"
 
3950
                remembered_submit_branch = True
4207
3951
            else:
4208
3952
                if stored_submit_branch is None or remember:
4209
3953
                    branch.set_submit_branch(submit_branch)
4210
3954
            if submit_branch is None:
4211
3955
                submit_branch = branch.get_parent()
4212
 
                remembered_submit_branch = "parent"
 
3956
                remembered_submit_branch = True
4213
3957
            if submit_branch is None:
4214
3958
                raise errors.BzrCommandError('No submit branch known or'
4215
3959
                                             ' 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")
 
3960
            if remembered_submit_branch:
 
3961
                note('Using saved location: %s', submit_branch)
4224
3962
 
4225
3963
            stored_public_branch = branch.get_public_branch()
4226
3964
            if public_branch is None:
4236
3974
                if len(revision) > 2:
4237
3975
                    raise errors.BzrCommandError('bzr send takes '
4238
3976
                        'at most two one revision identifiers')
4239
 
                revision_id = revision[-1].as_revision_id(branch)
 
3977
                revision_id = revision[-1].in_history(branch).rev_id
4240
3978
                if len(revision) == 2:
4241
 
                    base_revision_id = revision[0].as_revision_id(branch)
 
3979
                    base_revision_id = revision[0].in_history(branch).rev_id
4242
3980
            if revision_id is None:
4243
3981
                revision_id = branch.last_revision()
4244
3982
            if revision_id == NULL_REVISION:
4276
4014
                else:
4277
4015
                    revision = branch.repository.get_revision(revision_id)
4278
4016
                    subject += revision.get_summary()
4279
 
                basename = directive.get_disk_name(branch)
4280
4017
                mail_client.compose_merge_request(mail_to, subject,
4281
 
                                                  outfile.getvalue(), basename)
 
4018
                                                  outfile.getvalue())
4282
4019
        finally:
4283
4020
            if output != '-':
4284
4021
                outfile.close()
4285
 
            branch.unlock()
4286
4022
 
4287
4023
 
4288
4024
class cmd_bundle_revisions(cmd_send):
4367
4103
 
4368
4104
    It is an error to give a tag name that already exists unless you pass 
4369
4105
    --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
4106
    """
4374
4107
 
4375
4108
    _see_also = ['commit', 'tags']
4407
4140
                        raise errors.BzrCommandError(
4408
4141
                            "Tags can only be placed on a single revision, "
4409
4142
                            "not on a range")
4410
 
                    revision_id = revision[0].as_revision_id(branch)
 
4143
                    revision_id = revision[0].in_history(branch).rev_id
4411
4144
                else:
4412
4145
                    revision_id = branch.last_revision()
4413
4146
                if (not force) and branch.tags.has_tag(tag_name):
4421
4154
class cmd_tags(Command):
4422
4155
    """List tags.
4423
4156
 
4424
 
    This command shows a table of tag names and the revisions they reference.
 
4157
    This tag shows a table of tag names and the revisions they reference.
4425
4158
    """
4426
4159
 
4427
4160
    _see_also = ['tag']
4431
4164
            short_name='d',
4432
4165
            type=unicode,
4433
4166
            ),
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
4167
    ]
4441
4168
 
4442
4169
    @display_command
4443
4170
    def run(self,
4444
4171
            directory='.',
4445
 
            sort='alpha',
4446
 
            show_ids=False,
4447
4172
            ):
4448
4173
        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
4461
 
                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))
 
4174
        for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
 
4175
            self.outf.write('%-20s %s\n' % (tag_name, target))
4472
4176
 
4473
4177
 
4474
4178
class cmd_reconfigure(Command):
4485
4189
    If none of these is available, --bind-to must be specified.
4486
4190
    """
4487
4191
 
4488
 
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
4489
4192
    takes_args = ['location?']
4490
4193
    takes_options = [RegistryOption.from_kwargs('target_type',
4491
4194
                     title='Target type',
4492
4195
                     help='The type to reconfigure the directory to.',
4493
4196
                     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.'),
 
4197
                     branch='Reconfigure to a branch.',
 
4198
                     tree='Reconfigure to a tree.',
 
4199
                     checkout='Reconfigure to a checkout.'),
4505
4200
                     Option('bind-to', help='Branch to bind checkout to.',
4506
4201
                            type=str),
4507
4202
                     Option('force',
4520
4215
        elif target_type == 'checkout':
4521
4216
            reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4522
4217
                                                                  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
4218
        reconfiguration.apply(force)
4531
4219
 
4532
4220
 
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
4221
def _create_prefix(cur_transport):
4594
4222
    needed = [cur_transport]
4595
4223
    # Recurse upwards until we can create a directory successfully
4612
4240
        cur_transport.ensure_base()
4613
4241
 
4614
4242
 
 
4243
def _get_mergeable_helper(location):
 
4244
    """Get a merge directive or bundle if 'location' points to one.
 
4245
 
 
4246
    Try try to identify a bundle and returns its mergeable form. If it's not,
 
4247
    we return the tried transport anyway so that it can reused to access the
 
4248
    branch
 
4249
 
 
4250
    :param location: can point to a bundle or a branch.
 
4251
 
 
4252
    :return: mergeable, transport
 
4253
    """
 
4254
    mergeable = None
 
4255
    url = urlutils.normalize_url(location)
 
4256
    url, filename = urlutils.split(url, exclude_trailing_slash=False)
 
4257
    location_transport = transport.get_transport(url)
 
4258
    if filename:
 
4259
        try:
 
4260
            # There may be redirections but we ignore the intermediate
 
4261
            # and final transports used
 
4262
            read = bundle.read_mergeable_from_transport
 
4263
            mergeable, t = read(location_transport, filename)
 
4264
        except errors.NotABundle:
 
4265
            # Continue on considering this url a Branch but adjust the
 
4266
            # location_transport
 
4267
            location_transport = location_transport.clone(filename)
 
4268
    return mergeable, location_transport
 
4269
 
 
4270
 
4615
4271
# these get imported and then picked up by the scan for cmd_*
4616
4272
# TODO: Some more consistent way to split command definitions across files;
4617
4273
# we do need to load at least some information about them to know of 
4623
4279
    cmd_bundle_info,
4624
4280
    )
4625
4281
from bzrlib.sign_my_commits import cmd_sign_my_commits
4626
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
 
4282
from bzrlib.weave_commands import cmd_versionedfile_list, cmd_weave_join, \
4627
4283
        cmd_weave_plan_merge, cmd_weave_merge_text