~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-12-20 16:16:34 UTC
  • mfrom: (3123.5.18 hardlinks)
  • Revision ID: pqm@pqm.ubuntu.com-20071220161634-2kcjb650o21ydko4
Accelerate build_tree using similar workingtrees (abentley)

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):
232
221
                if rev is None:
233
222
                    raise errors.BzrCommandError('You cannot specify a NULL'
234
223
                                                 ' revision.')
235
 
                rev_id = rev.as_revision_id(b)
 
224
                revno, rev_id = rev.in_history(b)
236
225
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
237
226
    
238
227
 
306
295
            revs.append(RevisionSpec.from_string('-1'))
307
296
 
308
297
        for rev in revs:
309
 
            revision_id = rev.as_revision_id(b)
310
 
            try:
311
 
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
312
 
            except errors.NoSuchRevision:
 
298
            revinfo = rev.in_history(b)
 
299
            if revinfo.revno is None:
313
300
                dotted_map = b.get_revision_id_to_revno_map()
314
 
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
315
 
            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)
316
305
 
317
306
    
318
307
class cmd_add(Command):
477
466
                    raise errors.BzrCommandError(
478
467
                        'bzr inventory --revision takes exactly one revision'
479
468
                        ' identifier')
480
 
                revision_id = revision[0].as_revision_id(work_tree.branch)
 
469
                revision_id = revision[0].in_history(work_tree.branch).rev_id
481
470
                tree = work_tree.branch.repository.revision_tree(revision_id)
482
471
 
483
472
                extra_trees = [work_tree]
545
534
        if len(names_list) < 2:
546
535
            raise errors.BzrCommandError("missing file argument")
547
536
        tree, rel_names = tree_files(names_list)
548
 
        tree.lock_write()
549
 
        try:
550
 
            self._run(tree, names_list, rel_names, after)
551
 
        finally:
552
 
            tree.unlock()
553
 
 
554
 
    def _run(self, tree, names_list, rel_names, after):
555
 
        into_existing = osutils.isdir(names_list[-1])
556
 
        if into_existing and len(names_list) == 2:
557
 
            # special cases:
558
 
            # a. case-insensitive filesystem and change case of dir
559
 
            # b. move directory after the fact (if the source used to be
560
 
            #    a directory, but now doesn't exist in the working tree
561
 
            #    and the target is an existing directory, just rename it)
562
 
            if (not tree.case_sensitive
563
 
                and rel_names[0].lower() == rel_names[1].lower()):
564
 
                into_existing = False
565
 
            else:
566
 
                inv = tree.inventory
567
 
                from_id = tree.path2id(rel_names[0])
568
 
                if (not osutils.lexists(names_list[0]) and
569
 
                    from_id and inv.get_file_kind(from_id) == "directory"):
570
 
                    into_existing = False
571
 
        # move/rename
572
 
        if into_existing:
 
537
        
 
538
        if os.path.isdir(names_list[-1]):
573
539
            # move into existing directory
574
540
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
575
541
                self.outf.write("%s => %s\n" % pair)
580
546
                                             ' directory')
581
547
            tree.rename_one(rel_names[0], rel_names[1], after=after)
582
548
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
583
 
 
584
 
 
 
549
            
 
550
    
585
551
class cmd_pull(Command):
586
552
    """Turn this branch into a mirror of another branch.
587
553
 
600
566
    that, you can omit the location to use the default.  To change the
601
567
    default, use --remember. The value will only be saved if the remote
602
568
    location can be accessed.
603
 
 
604
 
    Note: The location can be specified either in the form of a branch,
605
 
    or in the form of a path to a file containing a merge directive generated
606
 
    with bzr send.
607
569
    """
608
570
 
609
571
    _see_also = ['push', 'update', 'status-flags']
637
599
 
638
600
        possible_transports = []
639
601
        if location is not None:
640
 
            try:
641
 
                mergeable = bundle.read_mergeable_from_url(location,
642
 
                    possible_transports=possible_transports)
643
 
            except errors.NotABundle:
644
 
                mergeable = None
 
602
            mergeable, location_transport = _get_mergeable_helper(location)
 
603
            possible_transports.append(location_transport)
645
604
 
646
605
        stored_loc = branch_to.get_parent()
647
606
        if location is None:
651
610
            else:
652
611
                display_url = urlutils.unescape_for_display(stored_loc,
653
612
                        self.outf.encoding)
654
 
                if not is_quiet():
655
 
                    self.outf.write("Using saved location: %s\n" % display_url)
 
613
                self.outf.write("Using saved location: %s\n" % display_url)
656
614
                location = stored_loc
 
615
                location_transport = transport.get_transport(
 
616
                    location, possible_transports=possible_transports)
657
617
 
658
618
        if mergeable is not None:
659
619
            if revision is not None:
664
624
                mergeable.get_merge_request(branch_to.repository)
665
625
            branch_from = branch_to
666
626
        else:
667
 
            branch_from = Branch.open(location,
668
 
                possible_transports=possible_transports)
 
627
            branch_from = Branch.open_from_transport(location_transport)
669
628
 
670
629
            if branch_to.get_parent() is None or remember:
671
630
                branch_to.set_parent(branch_from.base)
672
631
 
673
632
        if revision is not None:
674
633
            if len(revision) == 1:
675
 
                revision_id = revision[0].as_revision_id(branch_from)
 
634
                revision_id = revision[0].in_history(branch_from).rev_id
676
635
            else:
677
636
                raise errors.BzrCommandError(
678
637
                    'bzr pull --revision takes one value.')
679
638
 
680
 
        branch_to.lock_write()
681
 
        try:
682
 
            if tree_to is not None:
683
 
                change_reporter = delta._ChangeReporter(
684
 
                    unversioned_filter=tree_to.is_ignored)
685
 
                result = tree_to.pull(branch_from, overwrite, revision_id,
686
 
                                      change_reporter,
687
 
                                      possible_transports=possible_transports)
688
 
            else:
689
 
                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)
690
649
 
691
 
            result.report(self.outf)
692
 
            if verbose and result.old_revid != result.new_revid:
693
 
                old_rh = list(
694
 
                    branch_to.repository.iter_reverse_revision_history(
695
 
                    result.old_revid))
696
 
                old_rh.reverse()
697
 
                new_rh = branch_to.revision_history()
698
 
                log.show_changed_revisions(branch_to, old_rh, new_rh,
699
 
                                           to_file=self.outf)
700
 
        finally:
701
 
            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)
702
655
 
703
656
 
704
657
class cmd_push(Command):
728
681
    """
729
682
 
730
683
    _see_also = ['pull', 'update', 'working-trees']
731
 
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
 
684
    takes_options = ['remember', 'overwrite', 'verbose',
732
685
        Option('create-prefix',
733
686
               help='Create the path leading up to the branch '
734
687
                    'if it does not already exist.'),
743
696
                    ' directory exists, but does not already'
744
697
                    ' have a control directory.  This flag will'
745
698
                    ' allow push to proceed.'),
746
 
        Option('stacked',
747
 
            help='Create a stacked branch that references the public location '
748
 
                'of the parent branch.'),
749
 
        Option('stacked-on',
750
 
            help='Create a stacked branch that refers to another branch '
751
 
                'for the commit history. Only the work not present in the '
752
 
                'referenced branch is included in the branch created.',
753
 
            type=unicode),
754
699
        ]
755
700
    takes_args = ['location?']
756
701
    encoding_type = 'replace'
757
702
 
758
703
    def run(self, location=None, remember=False, overwrite=False,
759
 
        create_prefix=False, verbose=False, revision=None,
760
 
        use_existing_dir=False, directory=None, stacked_on=None,
761
 
        stacked=False):
762
 
        from bzrlib.push import _show_push_branch
763
 
 
764
 
        # 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.
765
709
        if directory is None:
766
710
            directory = '.'
767
711
        br_from = Branch.open_containing(directory)[0]
768
 
        if revision is not None:
769
 
            if len(revision) == 1:
770
 
                revision_id = revision[0].in_history(br_from).rev_id
771
 
            else:
772
 
                raise errors.BzrCommandError(
773
 
                    'bzr push --revision takes one value.')
774
 
        else:
775
 
            revision_id = br_from.last_revision()
776
 
 
777
 
        # Get the stacked_on branch, if any
778
 
        if stacked_on is not None:
779
 
            stacked_on = urlutils.normalize_url(stacked_on)
780
 
        elif stacked:
781
 
            parent_url = br_from.get_parent()
782
 
            if parent_url:
783
 
                parent = Branch.open(parent_url)
784
 
                stacked_on = parent.get_public_branch()
785
 
                if not stacked_on:
786
 
                    # I considered excluding non-http url's here, thus forcing
787
 
                    # 'public' branches only, but that only works for some
788
 
                    # users, so it's best to just depend on the user spotting an
789
 
                    # error by the feedback given to them. RBC 20080227.
790
 
                    stacked_on = parent_url
791
 
            if not stacked_on:
792
 
                raise errors.BzrCommandError(
793
 
                    "Could not determine branch to refer to.")
794
 
 
795
 
        # Get the destination location
 
712
        stored_loc = br_from.get_push_location()
796
713
        if location is None:
797
 
            stored_loc = br_from.get_push_location()
798
714
            if stored_loc is None:
799
 
                raise errors.BzrCommandError(
800
 
                    "No push location known or specified.")
 
715
                raise errors.BzrCommandError("No push location known or specified.")
801
716
            else:
802
717
                display_url = urlutils.unescape_for_display(stored_loc,
803
718
                        self.outf.encoding)
804
719
                self.outf.write("Using saved location: %s\n" % display_url)
805
720
                location = stored_loc
806
721
 
807
 
        _show_push_branch(br_from, revision_id, location, self.outf,
808
 
            verbose=verbose, overwrite=overwrite, remember=remember,
809
 
            stacked_on=stacked_on, create_prefix=create_prefix,
810
 
            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
 
 
751
            def make_directory(transport):
 
752
                transport.mkdir('.')
 
753
                return transport
 
754
 
 
755
            def redirected(redirected_transport, e, redirection_notice):
 
756
                return transport.get_transport(e.get_target_url())
 
757
 
 
758
            try:
 
759
                to_transport = transport.do_catching_redirections(
 
760
                    make_directory, to_transport, redirected)
 
761
            except errors.FileExists:
 
762
                if not use_existing_dir:
 
763
                    raise errors.BzrCommandError("Target directory %s"
 
764
                         " already exists, but does not have a valid .bzr"
 
765
                         " directory. Supply --use-existing-dir to push"
 
766
                         " there anyway." % location)
 
767
            except errors.NoSuchFile:
 
768
                if not create_prefix:
 
769
                    raise errors.BzrCommandError("Parent directory of %s"
 
770
                        " does not exist."
 
771
                        "\nYou may supply --create-prefix to create all"
 
772
                        " leading parent directories."
 
773
                        % location)
 
774
                _create_prefix(to_transport)
 
775
            except errors.TooManyRedirections:
 
776
                raise errors.BzrCommandError("Too many redirections trying "
 
777
                                             "to make %s." % location)
 
778
 
 
779
            # Now the target directory exists, but doesn't have a .bzr
 
780
            # directory. So we need to create it, along with any work to create
 
781
            # all of the dependent branches, etc.
 
782
            dir_to = br_from.bzrdir.clone_on_transport(to_transport,
 
783
                revision_id=br_from.last_revision())
 
784
            br_to = dir_to.open_branch()
 
785
            # TODO: Some more useful message about what was copied
 
786
            note('Created new branch.')
 
787
            # We successfully created the target, remember it
 
788
            if br_from.get_push_location() is None or remember:
 
789
                br_from.set_push_location(br_to.base)
 
790
        elif repository_to is None:
 
791
            # we have a bzrdir but no branch or repository
 
792
            # XXX: Figure out what to do other than complain.
 
793
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
 
794
                " directory, but not a branch or repository. This is an"
 
795
                " unsupported configuration. Please move the target directory"
 
796
                " out of the way and try again."
 
797
                % location)
 
798
        elif br_to is None:
 
799
            # We have a repository but no branch, copy the revisions, and then
 
800
            # create a branch.
 
801
            last_revision_id = br_from.last_revision()
 
802
            repository_to.fetch(br_from.repository,
 
803
                                revision_id=last_revision_id)
 
804
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
 
805
            note('Created new branch.')
 
806
            if br_from.get_push_location() is None or remember:
 
807
                br_from.set_push_location(br_to.base)
 
808
        else: # We have a valid to branch
 
809
            # We were able to connect to the remote location, so remember it
 
810
            # we don't need to successfully push because of possible divergence.
 
811
            if br_from.get_push_location() is None or remember:
 
812
                br_from.set_push_location(br_to.base)
 
813
            if verbose:
 
814
                old_rh = br_to.revision_history()
 
815
            try:
 
816
                try:
 
817
                    tree_to = dir_to.open_workingtree()
 
818
                except errors.NotLocalUrl:
 
819
                    warning("This transport does not update the working " 
 
820
                            "tree of: %s. See 'bzr help working-trees' for "
 
821
                            "more information." % br_to.base)
 
822
                    push_result = br_from.push(br_to, overwrite)
 
823
                except errors.NoWorkingTree:
 
824
                    push_result = br_from.push(br_to, overwrite)
 
825
                else:
 
826
                    tree_to.lock_write()
 
827
                    try:
 
828
                        push_result = br_from.push(tree_to.branch, overwrite)
 
829
                        tree_to.update()
 
830
                    finally:
 
831
                        tree_to.unlock()
 
832
            except errors.DivergedBranches:
 
833
                raise errors.BzrCommandError('These branches have diverged.'
 
834
                                        '  Try using "merge" and then "push".')
 
835
        if push_result is not None:
 
836
            push_result.report(self.outf)
 
837
        elif verbose:
 
838
            new_rh = br_to.revision_history()
 
839
            if old_rh != new_rh:
 
840
                # Something changed
 
841
                from bzrlib.log import show_changed_revisions
 
842
                show_changed_revisions(br_to, old_rh, new_rh,
 
843
                                       to_file=self.outf)
 
844
        else:
 
845
            # we probably did a clone rather than a push, so a message was
 
846
            # emitted above
 
847
            pass
811
848
 
812
849
 
813
850
class cmd_branch(Command):
826
863
 
827
864
    _see_also = ['checkout']
828
865
    takes_args = ['from_location', 'to_location?']
829
 
    takes_options = ['revision', Option('hardlink',
830
 
        help='Hard-link working tree files where possible.'),
831
 
        Option('stacked',
832
 
            help='Create a stacked branch referring to the source branch. '
833
 
                'The new branch will depend on the availability of the source '
834
 
                'branch for all operations.'),
835
 
        ]
 
866
    takes_options = ['revision']
836
867
    aliases = ['get', 'clone']
837
868
 
838
 
    def run(self, from_location, to_location=None, revision=None,
839
 
            hardlink=False, stacked=False):
 
869
    def run(self, from_location, to_location=None, revision=None):
840
870
        from bzrlib.tag import _merge_tags_if_possible
841
871
        if revision is None:
842
872
            revision = [None]
849
879
        br_from.lock_read()
850
880
        try:
851
881
            if len(revision) == 1 and revision[0] is not None:
852
 
                revision_id = revision[0].as_revision_id(br_from)
 
882
                revision_id = revision[0].in_history(br_from)[1]
853
883
            else:
854
884
                # FIXME - wt.last_revision, fallback to branch, fall back to
855
885
                # None or perhaps NULL_REVISION to mean copy nothing
857
887
                revision_id = br_from.last_revision()
858
888
            if to_location is None:
859
889
                to_location = urlutils.derive_to_location(from_location)
 
890
                name = None
 
891
            else:
 
892
                name = os.path.basename(to_location) + '\n'
 
893
 
860
894
            to_transport = transport.get_transport(to_location)
861
895
            try:
862
896
                to_transport.mkdir('.')
870
904
                # preserve whatever source format we have.
871
905
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
872
906
                                            possible_transports=[to_transport],
873
 
                                            accelerator_tree=accelerator_tree,
874
 
                                            hardlink=hardlink, stacked=stacked)
 
907
                                            accelerator_tree=accelerator_tree)
875
908
                branch = dir.open_branch()
876
909
            except errors.NoSuchRevision:
877
910
                to_transport.delete_tree('.')
878
 
                msg = "The branch %s has no revision %s." % (from_location,
879
 
                    revision[0])
 
911
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
880
912
                raise errors.BzrCommandError(msg)
 
913
            if name:
 
914
                branch.control_files.put_utf8('branch-name', name)
881
915
            _merge_tags_if_possible(br_from, branch)
882
 
            # If the source branch is stacked, the new branch may
883
 
            # be stacked whether we asked for that explicitly or not.
884
 
            # We therefore need a try/except here and not just 'if stacked:'
885
 
            try:
886
 
                note('Created new stacked branch referring to %s.' %
887
 
                    branch.get_stacked_on_url())
888
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
889
 
                errors.UnstackableRepositoryFormat), e:
890
 
                note('Branched %d revision(s).' % branch.revno())
 
916
            note('Branched %d revision(s).' % branch.revno())
891
917
        finally:
892
918
            br_from.unlock()
893
919
 
923
949
                                 "common operations like diff and status without "
924
950
                                 "such access, and also support local commits."
925
951
                            ),
926
 
                     Option('files-from', type=str,
927
 
                            help="Get file contents from this tree."),
928
 
                     Option('hardlink',
929
 
                            help='Hard-link working tree files where possible.'
930
 
                            ),
 
952
                     Option('files-from',
 
953
                            help="Get file contents from this tree.", type=str)
931
954
                     ]
932
955
    aliases = ['co']
933
956
 
934
957
    def run(self, branch_location=None, to_location=None, revision=None,
935
 
            lightweight=False, files_from=None, hardlink=False):
 
958
            lightweight=False, files_from=None):
 
959
        if files_from is not None:
 
960
            accelerator_tree = WorkingTree.open(files_from)
 
961
        else:
 
962
            accelerator_tree = None
936
963
        if revision is None:
937
964
            revision = [None]
938
965
        elif len(revision) > 1:
941
968
        if branch_location is None:
942
969
            branch_location = osutils.getcwd()
943
970
            to_location = branch_location
944
 
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
945
 
            branch_location)
946
 
        if files_from is not None:
947
 
            accelerator_tree = WorkingTree.open(files_from)
 
971
        source = Branch.open(branch_location)
948
972
        if len(revision) == 1 and revision[0] is not None:
949
 
            revision_id = revision[0].as_revision_id(source)
 
973
            revision_id = _mod_revision.ensure_null(
 
974
                revision[0].in_history(source)[1])
950
975
        else:
951
976
            revision_id = None
952
977
        if to_location is None:
962
987
                source.bzrdir.create_workingtree(revision_id)
963
988
                return
964
989
        source.create_checkout(to_location, revision_id, lightweight,
965
 
                               accelerator_tree, hardlink)
 
990
                               accelerator_tree)
966
991
 
967
992
 
968
993
class cmd_renames(Command):
1074
1099
class cmd_remove(Command):
1075
1100
    """Remove files or directories.
1076
1101
 
1077
 
    This makes bzr stop tracking changes to the specified files. bzr will delete
1078
 
    them if they can easily be recovered using revert. If no options or
1079
 
    parameters are given bzr will scan for files that are being tracked by bzr
1080
 
    but missing in your tree and stop tracking them for you.
 
1102
    This makes bzr stop tracking changes to the specified files and
 
1103
    delete them if they can easily be recovered using revert.
 
1104
 
 
1105
    You can specify one or more files, and/or --new.  If you specify --new,
 
1106
    only 'added' files will be removed.  If you specify both, then new files
 
1107
    in the specified directories will be removed.  If the directories are
 
1108
    also new, they will also be removed.
1081
1109
    """
1082
1110
    takes_args = ['file*']
1083
1111
    takes_options = ['verbose',
1084
 
        Option('new', help='Only remove files that have never been committed.'),
 
1112
        Option('new', help='Remove newly-added files.'),
1085
1113
        RegistryOption.from_kwargs('file-deletion-strategy',
1086
1114
            'The file deletion mode to be used.',
1087
1115
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1090
1118
            keep="Don't delete any files.",
1091
1119
            force='Delete all the specified files, even if they can not be '
1092
1120
                'recovered and even if they are non-empty directories.')]
1093
 
    aliases = ['rm', 'del']
 
1121
    aliases = ['rm']
1094
1122
    encoding_type = 'replace'
1095
1123
 
1096
1124
    def run(self, file_list, verbose=False, new=False,
1099
1127
 
1100
1128
        if file_list is not None:
1101
1129
            file_list = [f for f in file_list]
 
1130
        elif not new:
 
1131
            raise errors.BzrCommandError('Specify one or more files to'
 
1132
            ' remove, or use --new.')
1102
1133
 
1103
 
        tree.lock_write()
1104
 
        try:
1105
 
            # Heuristics should probably all move into tree.remove_smart or
1106
 
            # some such?
1107
 
            if new:
1108
 
                added = tree.changes_from(tree.basis_tree(),
1109
 
                    specific_files=file_list).added
1110
 
                file_list = sorted([f[0] for f in added], reverse=True)
1111
 
                if len(file_list) == 0:
1112
 
                    raise errors.BzrCommandError('No matching files.')
1113
 
            elif file_list is None:
1114
 
                # missing files show up in iter_changes(basis) as
1115
 
                # versioned-with-no-kind.
1116
 
                missing = []
1117
 
                for change in tree.iter_changes(tree.basis_tree()):
1118
 
                    # Find paths in the working tree that have no kind:
1119
 
                    if change[1][1] is not None and change[6][1] is None:
1120
 
                        missing.append(change[1][1])
1121
 
                file_list = sorted(missing, reverse=True)
1122
 
                file_deletion_strategy = 'keep'
1123
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1124
 
                keep_files=file_deletion_strategy=='keep',
1125
 
                force=file_deletion_strategy=='force')
1126
 
        finally:
1127
 
            tree.unlock()
 
1134
        if new:
 
1135
            added = tree.changes_from(tree.basis_tree(),
 
1136
                specific_files=file_list).added
 
1137
            file_list = sorted([f[0] for f in added], reverse=True)
 
1138
            if len(file_list) == 0:
 
1139
                raise errors.BzrCommandError('No matching files.')
 
1140
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1141
            keep_files=file_deletion_strategy=='keep',
 
1142
            force=file_deletion_strategy=='force')
1128
1143
 
1129
1144
 
1130
1145
class cmd_file_id(Command):
1235
1250
            last_revision = wt.last_revision()
1236
1251
 
1237
1252
        revision_ids = b.repository.get_ancestry(last_revision)
 
1253
        assert revision_ids[0] is None
1238
1254
        revision_ids.pop(0)
1239
1255
        for revision_id in revision_ids:
1240
1256
            self.outf.write(revision_id + '\n')
1329
1345
            except errors.UpgradeRequired:
1330
1346
                raise errors.BzrCommandError('This branch format cannot be set'
1331
1347
                    ' to append-revisions-only.  Try --experimental-branch6')
1332
 
        if not is_quiet():
1333
 
            from bzrlib.info import show_bzrdir_info
1334
 
            show_bzrdir_info(bzrdir.BzrDir.open_containing_from_transport(
1335
 
                to_transport)[0], verbose=0, outfile=self.outf)
1336
1348
 
1337
1349
 
1338
1350
class cmd_init_repository(Command):
1384
1396
        newdir = format.initialize_on_transport(to_transport)
1385
1397
        repo = newdir.create_repository(shared=True)
1386
1398
        repo.set_make_working_trees(not no_trees)
1387
 
        if not is_quiet():
1388
 
            from bzrlib.info import show_bzrdir_info
1389
 
            show_bzrdir_info(bzrdir.BzrDir.open_containing_from_transport(
1390
 
                to_transport)[0], verbose=0, outfile=self.outf)
1391
1399
 
1392
1400
 
1393
1401
class cmd_diff(Command):
1446
1454
 
1447
1455
            bzr diff --prefix old/:new/
1448
1456
    """
 
1457
    # TODO: Option to use external diff command; could be GNU diff, wdiff,
 
1458
    #       or a graphical diff.
 
1459
 
 
1460
    # TODO: Python difflib is not exactly the same as unidiff; should
 
1461
    #       either fix it up or prefer to use an external diff.
 
1462
 
 
1463
    # TODO: Selected-file diff is inefficient and doesn't show you
 
1464
    #       deleted files.
 
1465
 
 
1466
    # TODO: This probably handles non-Unix newlines poorly.
 
1467
 
1449
1468
    _see_also = ['status']
1450
1469
    takes_args = ['file*']
1451
1470
    takes_options = [
1465
1484
            ),
1466
1485
        'revision',
1467
1486
        'change',
1468
 
        Option('using',
1469
 
            help='Use this command to compare files.',
1470
 
            type=unicode,
1471
 
            ),
1472
1487
        ]
1473
1488
    aliases = ['di', 'dif']
1474
1489
    encoding_type = 'exact'
1475
1490
 
1476
1491
    @display_command
1477
1492
    def run(self, revision=None, file_list=None, diff_options=None,
1478
 
            prefix=None, old=None, new=None, using=None):
 
1493
            prefix=None, old=None, new=None):
1479
1494
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
1480
1495
 
1481
1496
        if (prefix is None) or (prefix == '0'):
1502
1517
                               specific_files=specific_files,
1503
1518
                               external_diff_options=diff_options,
1504
1519
                               old_label=old_label, new_label=new_label,
1505
 
                               extra_trees=extra_trees, using=using)
 
1520
                               extra_trees=extra_trees)
1506
1521
 
1507
1522
 
1508
1523
class cmd_deleted(Command):
1544
1559
 
1545
1560
    hidden = True
1546
1561
    _see_also = ['status', 'ls']
1547
 
    takes_options = [
1548
 
            Option('null',
1549
 
                   help='Write an ascii NUL (\\0) separator '
1550
 
                   'between files rather than a newline.')
1551
 
            ]
1552
1562
 
1553
1563
    @display_command
1554
 
    def run(self, null=False):
 
1564
    def run(self):
1555
1565
        tree = WorkingTree.open_containing(u'.')[0]
1556
1566
        td = tree.changes_from(tree.basis_tree())
1557
1567
        for path, id, kind, text_modified, meta_modified in td.modified:
1558
 
            if null:
1559
 
                self.outf.write(path + '\0')
1560
 
            else:
1561
 
                self.outf.write(osutils.quotefn(path) + '\n')
 
1568
            self.outf.write(path + '\n')
1562
1569
 
1563
1570
 
1564
1571
class cmd_added(Command):
1567
1574
 
1568
1575
    hidden = True
1569
1576
    _see_also = ['status', 'ls']
1570
 
    takes_options = [
1571
 
            Option('null',
1572
 
                   help='Write an ascii NUL (\\0) separator '
1573
 
                   'between files rather than a newline.')
1574
 
            ]
1575
1577
 
1576
1578
    @display_command
1577
 
    def run(self, null=False):
 
1579
    def run(self):
1578
1580
        wt = WorkingTree.open_containing(u'.')[0]
1579
1581
        wt.lock_read()
1580
1582
        try:
1591
1593
                    path = inv.id2path(file_id)
1592
1594
                    if not os.access(osutils.abspath(path), os.F_OK):
1593
1595
                        continue
1594
 
                    if null:
1595
 
                        self.outf.write(path + '\0')
1596
 
                    else:
1597
 
                        self.outf.write(osutils.quotefn(path) + '\n')
 
1596
                    self.outf.write(path + '\n')
1598
1597
            finally:
1599
1598
                basis.unlock()
1600
1599
        finally:
1683
1682
            message=None,
1684
1683
            limit=None):
1685
1684
        from bzrlib.log import show_log
 
1685
        assert message is None or isinstance(message, basestring), \
 
1686
            "invalid message argument %r" % message
1686
1687
        direction = (forward and 'forward') or 'reverse'
1687
1688
        
1688
1689
        # log everything
1795
1796
            Option('from-root',
1796
1797
                   help='Print paths relative to the root of the branch.'),
1797
1798
            Option('unknown', help='Print unknown files.'),
1798
 
            Option('versioned', help='Print versioned files.',
1799
 
                   short_name='V'),
 
1799
            Option('versioned', help='Print versioned files.'),
1800
1800
            Option('ignored', help='Print ignored files.'),
1801
1801
            Option('null',
1802
1802
                   help='Write an ascii NUL (\\0) separator '
1838
1838
            relpath += '/'
1839
1839
        if revision is not None:
1840
1840
            tree = branch.repository.revision_tree(
1841
 
                revision[0].as_revision_id(branch))
 
1841
                revision[0].in_history(branch).rev_id)
1842
1842
        elif tree is None:
1843
1843
            tree = branch.basis_tree()
1844
1844
 
1895
1895
class cmd_ignore(Command):
1896
1896
    """Ignore specified files or patterns.
1897
1897
 
1898
 
    See ``bzr help patterns`` for details on the syntax of patterns.
1899
 
 
1900
1898
    To remove patterns from the ignore list, edit the .bzrignore file.
1901
 
    After adding, editing or deleting that file either indirectly by
1902
 
    using this command or directly by using an editor, be sure to commit
1903
 
    it.
 
1899
 
 
1900
    Trailing slashes on patterns are ignored. 
 
1901
    If the pattern contains a slash or is a regular expression, it is compared 
 
1902
    to the whole path from the branch root.  Otherwise, it is compared to only
 
1903
    the last component of the path.  To match a file only in the root 
 
1904
    directory, prepend './'.
 
1905
 
 
1906
    Ignore patterns specifying absolute paths are not allowed.
 
1907
 
 
1908
    Ignore patterns may include globbing wildcards such as::
 
1909
 
 
1910
      ? - Matches any single character except '/'
 
1911
      * - Matches 0 or more characters except '/'
 
1912
      /**/ - Matches 0 or more directories in a path
 
1913
      [a-z] - Matches a single character from within a group of characters
 
1914
 
 
1915
    Ignore patterns may also be Python regular expressions.  
 
1916
    Regular expression ignore patterns are identified by a 'RE:' prefix 
 
1917
    followed by the regular expression.  Regular expression ignore patterns
 
1918
    may not include named or numbered groups.
1904
1919
 
1905
1920
    Note: ignore patterns containing shell wildcards must be quoted from 
1906
1921
    the shell on Unix.
1921
1936
        Ignore .o files under the lib directory::
1922
1937
 
1923
1938
            bzr ignore "RE:lib/.*\.o"
1924
 
 
1925
 
        Ignore everything but the "debian" toplevel directory::
1926
 
 
1927
 
            bzr ignore "RE:(?!debian/).*"
1928
1939
    """
1929
1940
 
1930
 
    _see_also = ['status', 'ignored', 'patterns']
 
1941
    _see_also = ['status', 'ignored']
1931
1942
    takes_args = ['name_pattern*']
1932
1943
    takes_options = [
1933
1944
        Option('old-default-rules',
1935
1946
        ]
1936
1947
    
1937
1948
    def run(self, name_pattern_list=None, old_default_rules=None):
1938
 
        from bzrlib import ignores
 
1949
        from bzrlib.atomicfile import AtomicFile
1939
1950
        if old_default_rules is not None:
1940
1951
            # dump the rules and exit
1941
1952
            for pattern in ignores.OLD_DEFAULTS:
1952
1963
                raise errors.BzrCommandError(
1953
1964
                    "NAME_PATTERN should not be an absolute path")
1954
1965
        tree, relpath = WorkingTree.open_containing(u'.')
1955
 
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
 
1966
        ifn = tree.abspath('.bzrignore')
 
1967
        if os.path.exists(ifn):
 
1968
            f = open(ifn, 'rt')
 
1969
            try:
 
1970
                igns = f.read().decode('utf-8')
 
1971
            finally:
 
1972
                f.close()
 
1973
        else:
 
1974
            igns = ''
 
1975
 
 
1976
        # TODO: If the file already uses crlf-style termination, maybe
 
1977
        # we should use that for the newly added lines?
 
1978
 
 
1979
        if igns and igns[-1] != '\n':
 
1980
            igns += '\n'
 
1981
        for name_pattern in name_pattern_list:
 
1982
            igns += name_pattern + '\n'
 
1983
 
 
1984
        f = AtomicFile(ifn, 'wb')
 
1985
        try:
 
1986
            f.write(igns.encode('utf-8'))
 
1987
            f.commit()
 
1988
        finally:
 
1989
            f.close()
 
1990
 
 
1991
        if not tree.path2id('.bzrignore'):
 
1992
            tree.add(['.bzrignore'])
 
1993
 
1956
1994
        ignored = globbing.Globster(name_pattern_list)
1957
1995
        matches = []
1958
1996
        tree.lock_read()
1967
2005
            print "Warning: the following files are version controlled and" \
1968
2006
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
1969
2007
 
1970
 
 
1971
2008
class cmd_ignored(Command):
1972
2009
    """List ignored files and the patterns that matched them.
1973
 
 
1974
 
    List all the ignored files and the ignore pattern that caused the file to
1975
 
    be ignored.
1976
 
 
1977
 
    Alternatively, to list just the files::
1978
 
 
1979
 
        bzr ls --ignored
1980
2010
    """
1981
2011
 
1982
2012
    encoding_type = 'replace'
1983
 
    _see_also = ['ignore', 'ls']
 
2013
    _see_also = ['ignore']
1984
2014
 
1985
2015
    @display_command
1986
2016
    def run(self):
2044
2074
         zip                          .zip
2045
2075
      =================       =========================
2046
2076
    """
2047
 
    takes_args = ['dest', 'branch_or_subdir?']
 
2077
    takes_args = ['dest', 'branch?']
2048
2078
    takes_options = [
2049
2079
        Option('format',
2050
2080
               help="Type of file to export to.",
2054
2084
               type=str,
2055
2085
               help="Name of the root directory inside the exported file."),
2056
2086
        ]
2057
 
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2058
 
        root=None):
 
2087
    def run(self, dest, branch=None, revision=None, format=None, root=None):
2059
2088
        from bzrlib.export import export
2060
2089
 
2061
 
        if branch_or_subdir is None:
 
2090
        if branch is None:
2062
2091
            tree = WorkingTree.open_containing(u'.')[0]
2063
2092
            b = tree.branch
2064
 
            subdir = None
2065
2093
        else:
2066
 
            b, subdir = Branch.open_containing(branch_or_subdir)
 
2094
            b = Branch.open(branch)
2067
2095
            
2068
2096
        if revision is None:
2069
2097
            # should be tree.last_revision  FIXME
2071
2099
        else:
2072
2100
            if len(revision) != 1:
2073
2101
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2074
 
            rev_id = revision[0].as_revision_id(b)
 
2102
            rev_id = revision[0].in_history(b).rev_id
2075
2103
        t = b.repository.revision_tree(rev_id)
2076
2104
        try:
2077
 
            export(t, dest, format, root, subdir)
 
2105
            export(t, dest, format, root)
2078
2106
        except errors.NoSuchExportFormat, e:
2079
2107
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2080
2108
 
2116
2144
        if revision is None:
2117
2145
            revision_id = b.last_revision()
2118
2146
        else:
2119
 
            revision_id = revision[0].as_revision_id(b)
 
2147
            revision_id = revision[0].in_history(b).rev_id
2120
2148
 
2121
2149
        cur_file_id = tree.path2id(relpath)
2122
2150
        rev_tree = b.repository.revision_tree(revision_id)
2127
2155
                raise errors.BzrCommandError("%r is not present in revision %s"
2128
2156
                                                % (filename, revision_id))
2129
2157
            else:
2130
 
                content = rev_tree.get_file_text(old_file_id)
 
2158
                rev_tree.print_file(old_file_id)
2131
2159
        elif cur_file_id is not None:
2132
 
            content = rev_tree.get_file_text(cur_file_id)
 
2160
            rev_tree.print_file(cur_file_id)
2133
2161
        elif old_file_id is not None:
2134
 
            content = rev_tree.get_file_text(old_file_id)
 
2162
            rev_tree.print_file(old_file_id)
2135
2163
        else:
2136
2164
            raise errors.BzrCommandError("%r is not present in revision %s" %
2137
2165
                                         (filename, revision_id))
2138
 
        self.outf.write(content)
2139
2166
 
2140
2167
 
2141
2168
class cmd_local_time_offset(Command):
2156
2183
    committed.  If a directory is specified then the directory and everything 
2157
2184
    within it is committed.
2158
2185
 
2159
 
    When excludes are given, they take precedence over selected files.
2160
 
    For example, too commit only changes within foo, but not changes within
2161
 
    foo/bar::
2162
 
 
2163
 
      bzr commit foo -x foo/bar
2164
 
 
2165
2186
    If author of the change is not the same person as the committer, you can
2166
2187
    specify the author's name using the --author option. The name should be
2167
2188
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2197
2218
    _see_also = ['bugs', 'uncommit']
2198
2219
    takes_args = ['selected*']
2199
2220
    takes_options = [
2200
 
            ListOption('exclude', type=str, short_name='x',
2201
 
                help="Do not consider changes made to a given path."),
2202
2221
            Option('message', type=unicode,
2203
2222
                   short_name='m',
2204
2223
                   help="Description of the new revision."),
2253
2272
 
2254
2273
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2255
2274
            unchanged=False, strict=False, local=False, fixes=None,
2256
 
            author=None, show_diff=False, exclude=None):
 
2275
            author=None, show_diff=False):
2257
2276
        from bzrlib.errors import (
2258
2277
            PointlessCommit,
2259
2278
            ConflictsInTree,
2303
2322
                raise errors.BzrCommandError(
2304
2323
                    "please specify either --message or --file")
2305
2324
            if file:
2306
 
                my_message = codecs.open(file, 'rt',
 
2325
                my_message = codecs.open(file, 'rt', 
2307
2326
                                         bzrlib.user_encoding).read()
2308
2327
            if my_message == "":
2309
2328
                raise errors.BzrCommandError("empty commit message specified")
2314
2333
                        specific_files=selected_list,
2315
2334
                        allow_pointless=unchanged, strict=strict, local=local,
2316
2335
                        reporter=None, verbose=verbose, revprops=properties,
2317
 
                        author=author,
2318
 
                        exclude=safe_relpath_files(tree, exclude))
 
2336
                        author=author)
2319
2337
        except PointlessCommit:
2320
2338
            # FIXME: This should really happen before the file is read in;
2321
2339
            # perhaps prepare the commit; get the message; then actually commit
2336
2354
 
2337
2355
 
2338
2356
class cmd_check(Command):
2339
 
    """Validate working tree structure, branch consistency and repository history.
2340
 
 
2341
 
    This command checks various invariants about branch and repository storage
2342
 
    to detect data corruption or bzr bugs.
2343
 
 
2344
 
    The working tree and branch checks will only give output if a problem is
2345
 
    detected. The output fields of the repository check are:
 
2357
    """Validate consistency of branch history.
 
2358
 
 
2359
    This command checks various invariants about the branch storage to
 
2360
    detect data corruption or bzr bugs.
 
2361
 
 
2362
    Output fields:
2346
2363
 
2347
2364
        revisions: This is just the number of revisions checked.  It doesn't
2348
2365
            indicate a problem.
2357
2374
            in the checked revisions.  Texts can be repeated when their file
2358
2375
            entries are modified, but the file contents are not.  It does not
2359
2376
            indicate a problem.
2360
 
 
2361
 
    If no restrictions are specified, all Bazaar data that is found at the given
2362
 
    location will be checked.
2363
 
 
2364
 
    :Examples:
2365
 
 
2366
 
        Check the tree and branch at 'foo'::
2367
 
 
2368
 
            bzr check --tree --branch foo
2369
 
 
2370
 
        Check only the repository at 'bar'::
2371
 
 
2372
 
            bzr check --repo bar
2373
 
 
2374
 
        Check everything at 'baz'::
2375
 
 
2376
 
            bzr check baz
2377
2377
    """
2378
2378
 
2379
2379
    _see_also = ['reconcile']
2380
 
    takes_args = ['path?']
2381
 
    takes_options = ['verbose',
2382
 
                     Option('branch', help="Check the branch related to the"
2383
 
                                           " current directory."),
2384
 
                     Option('repo', help="Check the repository related to the"
2385
 
                                         " current directory."),
2386
 
                     Option('tree', help="Check the working tree related to"
2387
 
                                         " the current directory.")]
 
2380
    takes_args = ['branch?']
 
2381
    takes_options = ['verbose']
2388
2382
 
2389
 
    def run(self, path=None, verbose=False, branch=False, repo=False,
2390
 
            tree=False):
2391
 
        from bzrlib.check import check_dwim
2392
 
        if path is None:
2393
 
            path = '.'
2394
 
        if not branch and not repo and not tree:
2395
 
            branch = repo = tree = True
2396
 
        check_dwim(path, verbose, do_branch=branch, do_repo=repo, do_tree=tree)
 
2383
    def run(self, branch=None, verbose=False):
 
2384
        from bzrlib.check import check
 
2385
        if branch is None:
 
2386
            branch_obj = Branch.open_containing('.')[0]
 
2387
        else:
 
2388
            branch_obj = Branch.open(branch)
 
2389
        check(branch_obj, verbose)
 
2390
        # bit hacky, check the tree parent is accurate
 
2391
        try:
 
2392
            if branch is None:
 
2393
                tree = WorkingTree.open_containing('.')[0]
 
2394
            else:
 
2395
                tree = WorkingTree.open(branch)
 
2396
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
2397
            pass
 
2398
        else:
 
2399
            # This is a primitive 'check' for tree state. Currently this is not
 
2400
            # integrated into the main check logic as yet.
 
2401
            tree.lock_read()
 
2402
            try:
 
2403
                tree_basis = tree.basis_tree()
 
2404
                tree_basis.lock_read()
 
2405
                try:
 
2406
                    repo_basis = tree.branch.repository.revision_tree(
 
2407
                        tree.last_revision())
 
2408
                    if len(list(repo_basis._iter_changes(tree_basis))):
 
2409
                        raise errors.BzrCheckError(
 
2410
                            "Mismatched basis inventory content.")
 
2411
                    tree._validate()
 
2412
                finally:
 
2413
                    tree_basis.unlock()
 
2414
            finally:
 
2415
                tree.unlock()
2397
2416
 
2398
2417
 
2399
2418
class cmd_upgrade(Command):
2493
2512
        print branch.nick
2494
2513
 
2495
2514
 
2496
 
class cmd_alias(Command):
2497
 
    """Set/unset and display aliases.
2498
 
 
2499
 
    :Examples:
2500
 
        Show the current aliases::
2501
 
 
2502
 
            bzr alias
2503
 
 
2504
 
        Show the alias specified for 'll'::
2505
 
 
2506
 
            bzr alias ll
2507
 
 
2508
 
        Set an alias for 'll'::
2509
 
 
2510
 
            bzr alias ll="log --line -r-10..-1"
2511
 
 
2512
 
        To remove an alias for 'll'::
2513
 
 
2514
 
            bzr alias --remove ll
2515
 
 
2516
 
    """
2517
 
    takes_args = ['name?']
2518
 
    takes_options = [
2519
 
        Option('remove', help='Remove the alias.'),
2520
 
        ]
2521
 
 
2522
 
    def run(self, name=None, remove=False):
2523
 
        if remove:
2524
 
            self.remove_alias(name)
2525
 
        elif name is None:
2526
 
            self.print_aliases()
2527
 
        else:
2528
 
            equal_pos = name.find('=')
2529
 
            if equal_pos == -1:
2530
 
                self.print_alias(name)
2531
 
            else:
2532
 
                self.set_alias(name[:equal_pos], name[equal_pos+1:])
2533
 
 
2534
 
    def remove_alias(self, alias_name):
2535
 
        if alias_name is None:
2536
 
            raise errors.BzrCommandError(
2537
 
                'bzr alias --remove expects an alias to remove.')
2538
 
        # If alias is not found, print something like:
2539
 
        # unalias: foo: not found
2540
 
        c = config.GlobalConfig()
2541
 
        c.unset_alias(alias_name)
2542
 
 
2543
 
    @display_command
2544
 
    def print_aliases(self):
2545
 
        """Print out the defined aliases in a similar format to bash."""
2546
 
        aliases = config.GlobalConfig().get_aliases()
2547
 
        for key, value in sorted(aliases.iteritems()):
2548
 
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
2549
 
 
2550
 
    @display_command
2551
 
    def print_alias(self, alias_name):
2552
 
        from bzrlib.commands import get_alias
2553
 
        alias = get_alias(alias_name)
2554
 
        if alias is None:
2555
 
            self.outf.write("bzr alias: %s: not found\n" % alias_name)
2556
 
        else:
2557
 
            self.outf.write(
2558
 
                'bzr alias %s="%s"\n' % (alias_name, ' '.join(alias)))
2559
 
 
2560
 
    def set_alias(self, alias_name, alias_command):
2561
 
        """Save the alias in the global config."""
2562
 
        c = config.GlobalConfig()
2563
 
        c.set_alias(alias_name, alias_command)
2564
 
 
2565
 
 
2566
2515
class cmd_selftest(Command):
2567
2516
    """Run internal test suite.
2568
2517
    
2657
2606
                                 ' expression.'),
2658
2607
                     Option('strict', help='Fail on missing dependencies or '
2659
2608
                            'known failures.'),
2660
 
                     Option('load-list', type=str, argname='TESTLISTFILE',
2661
 
                            help='Load a test id list from a text file.'),
2662
 
                     ListOption('debugflag', type=str, short_name='E',
2663
 
                                help='Turn on a selftest debug flag.'),
2664
 
                     Option('starting-with', type=str, argname='TESTID',
2665
 
                            short_name='s',
2666
 
                            help='Load only the tests starting with TESTID.'),
 
2609
                     Option('coverage', type=str, argname="DIRECTORY",
 
2610
                            help='Generate line coverage report in this '
 
2611
                                 'directory.'),
2667
2612
                     ]
2668
2613
    encoding_type = 'replace'
2669
2614
 
2671
2616
            transport=None, benchmark=None,
2672
2617
            lsprof_timed=None, cache_dir=None,
2673
2618
            first=False, list_only=False,
2674
 
            randomize=None, exclude=None, strict=False,
2675
 
            load_list=None, debugflag=None, starting_with=None):
 
2619
            randomize=None, exclude=None, strict=False, coverage=None):
2676
2620
        import bzrlib.ui
2677
2621
        from bzrlib.tests import selftest
2678
2622
        import bzrlib.benchmarks as benchmarks
2679
2623
        from bzrlib.benchmarks import tree_creator
2680
2624
 
2681
 
        # Make deprecation warnings visible, unless -Werror is set
2682
 
        symbol_versioning.activate_deprecation_warnings(override=False)
2683
 
 
2684
2625
        if cache_dir is not None:
2685
2626
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2686
2627
        if not list_only:
2688
2629
            print '   %s (%s python%s)' % (
2689
2630
                    bzrlib.__path__[0],
2690
2631
                    bzrlib.version_string,
2691
 
                    bzrlib._format_version_tuple(sys.version_info),
 
2632
                    '.'.join(map(str, sys.version_info)),
2692
2633
                    )
2693
2634
        print
2694
2635
        if testspecs_list is not None:
2717
2658
                              random_seed=randomize,
2718
2659
                              exclude_pattern=exclude,
2719
2660
                              strict=strict,
2720
 
                              load_list=load_list,
2721
 
                              debug_flags=debugflag,
2722
 
                              starting_with=starting_with,
 
2661
                              coverage_dir=coverage,
2723
2662
                              )
2724
2663
        finally:
2725
2664
            if benchfile is not None:
2726
2665
                benchfile.close()
2727
2666
        if result:
2728
 
            note('tests passed')
 
2667
            info('tests passed')
2729
2668
        else:
2730
 
            note('tests failed')
 
2669
            info('tests failed')
2731
2670
        return int(not result)
2732
2671
 
2733
2672
 
2735
2674
    """Show version of bzr."""
2736
2675
 
2737
2676
    encoding_type = 'replace'
2738
 
    takes_options = [
2739
 
        Option("short", help="Print just the version number."),
2740
 
        ]
2741
2677
 
2742
2678
    @display_command
2743
 
    def run(self, short=False):
 
2679
    def run(self):
2744
2680
        from bzrlib.version import show_version
2745
 
        if short:
2746
 
            self.outf.write(bzrlib.version_string + '\n')
2747
 
        else:
2748
 
            show_version(to_file=self.outf)
 
2681
        show_version(to_file=self.outf)
2749
2682
 
2750
2683
 
2751
2684
class cmd_rocks(Command):
2791
2724
class cmd_merge(Command):
2792
2725
    """Perform a three-way merge.
2793
2726
    
2794
 
    The source of the merge can be specified either in the form of a branch,
2795
 
    or in the form of a path to a file containing a merge directive generated
2796
 
    with bzr send. If neither is specified, the default is the upstream branch
2797
 
    or the branch most recently merged using --remember.
2798
 
 
2799
 
    When merging a branch, by default the tip will be merged. To pick a different
2800
 
    revision, pass --revision. If you specify two values, the first will be used as
2801
 
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
2802
 
    available revisions, like this is commonly referred to as "cherrypicking".
2803
 
 
2804
 
    Revision numbers are always relative to the branch being merged.
 
2727
    The branch is the branch you will merge from.  By default, it will merge
 
2728
    the latest revision.  If you specify a revision, that revision will be
 
2729
    merged.  If you specify two revisions, the first will be used as a BASE,
 
2730
    and the second one as OTHER.  Revision numbers are always relative to the
 
2731
    specified branch.
2805
2732
 
2806
2733
    By default, bzr will try to merge in all new work from the other
2807
2734
    branch, automatically determining an appropriate base.  If this
2838
2765
        To merge the changes introduced by 82, without previous changes::
2839
2766
 
2840
2767
            bzr merge -r 81..82 ../bzr.dev
2841
 
 
2842
 
        To apply a merge directive contained in in /tmp/merge:
2843
 
 
2844
 
            bzr merge /tmp/merge
2845
2768
    """
2846
2769
 
2847
 
    encoding_type = 'exact'
2848
2770
    _see_also = ['update', 'remerge', 'status-flags']
2849
 
    takes_args = ['location?']
 
2771
    takes_args = ['branch?']
2850
2772
    takes_options = [
2851
2773
        'change',
2852
2774
        'revision',
2869
2791
               short_name='d',
2870
2792
               type=unicode,
2871
2793
               ),
2872
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
2873
2794
    ]
2874
2795
 
2875
 
    def run(self, location=None, revision=None, force=False,
2876
 
            merge_type=None, show_base=False, reprocess=False, remember=False,
 
2796
    def run(self, branch=None, revision=None, force=False, merge_type=None,
 
2797
            show_base=False, reprocess=False, remember=False,
2877
2798
            uncommitted=False, pull=False,
2878
2799
            directory=None,
2879
 
            preview=False,
2880
2800
            ):
 
2801
        # This is actually a branch (or merge-directive) *location*.
 
2802
        location = branch
 
2803
        del branch
 
2804
 
2881
2805
        if merge_type is None:
2882
2806
            merge_type = _mod_merge.Merge3Merger
2883
2807
 
2896
2820
            tree.lock_write()
2897
2821
            cleanups.append(tree.unlock)
2898
2822
            if location is not None:
2899
 
                try:
2900
 
                    mergeable = bundle.read_mergeable_from_url(location,
2901
 
                        possible_transports=possible_transports)
2902
 
                except errors.NotABundle:
2903
 
                    mergeable = None
2904
 
                else:
 
2823
                mergeable, other_transport = _get_mergeable_helper(location)
 
2824
                if mergeable:
2905
2825
                    if uncommitted:
2906
2826
                        raise errors.BzrCommandError('Cannot use --uncommitted'
2907
2827
                            ' with bundles or merge directives.')
2911
2831
                            'Cannot use -r with merge directives or bundles')
2912
2832
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
2913
2833
                       mergeable, pb)
 
2834
                possible_transports.append(other_transport)
2914
2835
 
2915
2836
            if merger is None and uncommitted:
2916
2837
                if revision is not None and len(revision) > 0:
2931
2852
            merger.merge_type = merge_type
2932
2853
            merger.reprocess = reprocess
2933
2854
            merger.show_base = show_base
 
2855
            merger.change_reporter = change_reporter
2934
2856
            self.sanity_check_merger(merger)
2935
2857
            if (merger.base_rev_id == merger.other_rev_id and
2936
 
                merger.other_rev_id is not None):
 
2858
                merger.other_rev_id != None):
2937
2859
                note('Nothing to do.')
2938
2860
                return 0
2939
2861
            if pull:
2945
2867
                    result.report(self.outf)
2946
2868
                    return 0
2947
2869
            merger.check_basis(not force)
2948
 
            if preview:
2949
 
                return self._do_preview(merger)
 
2870
            conflict_count = merger.do_merge()
 
2871
            if allow_pending:
 
2872
                merger.set_pending()
 
2873
            if verified == 'failed':
 
2874
                warning('Preview patch does not match changes')
 
2875
            if conflict_count != 0:
 
2876
                return 1
2950
2877
            else:
2951
 
                return self._do_merge(merger, change_reporter, allow_pending,
2952
 
                                      verified)
 
2878
                return 0
2953
2879
        finally:
2954
2880
            for cleanup in reversed(cleanups):
2955
2881
                cleanup()
2956
2882
 
2957
 
    def _do_preview(self, merger):
2958
 
        from bzrlib.diff import show_diff_trees
2959
 
        tree_merger = merger.make_merger()
2960
 
        tt = tree_merger.make_preview_transform()
2961
 
        try:
2962
 
            result_tree = tt.get_preview_tree()
2963
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
2964
 
                            old_label='', new_label='')
2965
 
        finally:
2966
 
            tt.finalize()
2967
 
 
2968
 
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
2969
 
        merger.change_reporter = change_reporter
2970
 
        conflict_count = merger.do_merge()
2971
 
        if allow_pending:
2972
 
            merger.set_pending()
2973
 
        if verified == 'failed':
2974
 
            warning('Preview patch does not match changes')
2975
 
        if conflict_count != 0:
2976
 
            return 1
2977
 
        else:
2978
 
            return 0
2979
 
 
2980
2883
    def sanity_check_merger(self, merger):
2981
2884
        if (merger.show_base and
2982
2885
            not merger.merge_type is _mod_merge.Merge3Merger):
2994
2897
                                possible_transports, pb):
2995
2898
        """Produce a merger from a location, assuming it refers to a branch."""
2996
2899
        from bzrlib.tag import _merge_tags_if_possible
 
2900
        assert revision is None or len(revision) < 3
2997
2901
        # find the branch locations
2998
 
        other_loc, user_location = self._select_branch_location(tree, location,
 
2902
        other_loc, location = self._select_branch_location(tree, location,
2999
2903
            revision, -1)
3000
2904
        if revision is not None and len(revision) == 2:
3001
 
            base_loc, _unused = self._select_branch_location(tree,
3002
 
                location, revision, 0)
 
2905
            base_loc, location = self._select_branch_location(tree, location,
 
2906
                                                              revision, 0)
3003
2907
        else:
3004
2908
            base_loc = other_loc
3005
2909
        # Open the branches
3015
2919
            other_revision_id = _mod_revision.ensure_null(
3016
2920
                other_branch.last_revision())
3017
2921
        else:
3018
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
 
2922
            other_revision_id = \
 
2923
                _mod_revision.ensure_null(
 
2924
                    revision[-1].in_history(other_branch).rev_id)
3019
2925
        if (revision is not None and len(revision) == 2
3020
2926
            and revision[0] is not None):
3021
 
            base_revision_id = revision[0].as_revision_id(base_branch)
 
2927
            base_revision_id = \
 
2928
                _mod_revision.ensure_null(
 
2929
                    revision[0].in_history(base_branch).rev_id)
3022
2930
        else:
3023
2931
            base_revision_id = None
3024
2932
        # Remember where we merge from
3025
 
        if ((remember or tree.branch.get_submit_branch() is None) and
3026
 
             user_location is not None):
3027
 
            tree.branch.set_submit_branch(other_branch.base)
 
2933
        if ((tree.branch.get_parent() is None or remember) and
 
2934
            other_branch is not None):
 
2935
            tree.branch.set_parent(other_branch.base)
3028
2936
        _merge_tags_if_possible(other_branch, tree.branch)
3029
2937
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3030
2938
            other_revision_id, base_revision_id, other_branch, base_branch)
3035
2943
            allow_pending = True
3036
2944
        return merger, allow_pending
3037
2945
 
3038
 
    def _select_branch_location(self, tree, user_location, revision=None,
 
2946
    def _select_branch_location(self, tree, location, revision=None,
3039
2947
                                index=None):
3040
2948
        """Select a branch location, according to possible inputs.
3041
2949
 
3043
2951
        ``revision`` and ``index`` must be supplied.)
3044
2952
 
3045
2953
        Otherwise, the ``location`` parameter is used.  If it is None, then the
3046
 
        ``submit`` or ``parent`` location is used, and a note is printed.
 
2954
        ``parent`` location is used, and a note is printed.
3047
2955
 
3048
2956
        :param tree: The working tree to select a branch for merging into
3049
2957
        :param location: The location entered by the user
3050
2958
        :param revision: The revision parameter to the command
3051
2959
        :param index: The index to use for the revision parameter.  Negative
3052
2960
            indices are permitted.
3053
 
        :return: (selected_location, user_location).  The default location
3054
 
            will be the user-entered location.
 
2961
        :return: (selected_location, default_location).  The default location
 
2962
            will be the user-entered location, if any, or else the remembered
 
2963
            location.
3055
2964
        """
3056
2965
        if (revision is not None and index is not None
3057
2966
            and revision[index] is not None):
3058
2967
            branch = revision[index].get_branch()
3059
2968
            if branch is not None:
3060
 
                return branch, branch
3061
 
        if user_location is None:
3062
 
            location = self._get_remembered(tree, 'Merging from')
3063
 
        else:
3064
 
            location = user_location
3065
 
        return location, user_location
 
2969
                return branch, location
 
2970
        location = self._get_remembered_parent(tree, location, 'Merging from')
 
2971
        return location, location
3066
2972
 
3067
 
    def _get_remembered(self, tree, verb_string):
 
2973
    # TODO: move up to common parent; this isn't merge-specific anymore. 
 
2974
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
3068
2975
        """Use tree.branch's parent if none was supplied.
3069
2976
 
3070
2977
        Report if the remembered location was used.
3071
2978
        """
3072
 
        stored_location = tree.branch.get_submit_branch()
3073
 
        if stored_location is None:
3074
 
            stored_location = tree.branch.get_parent()
 
2979
        if supplied_location is not None:
 
2980
            return supplied_location
 
2981
        stored_location = tree.branch.get_parent()
3075
2982
        mutter("%s", stored_location)
3076
2983
        if stored_location is None:
3077
2984
            raise errors.BzrCommandError("No location specified or remembered")
3078
 
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
3079
 
        note(u"%s remembered location %s", verb_string, display_url)
 
2985
        display_url = urlutils.unescape_for_display(stored_location,
 
2986
            self.outf.encoding)
 
2987
        self.outf.write("%s remembered location %s\n" % (verb_string,
 
2988
            display_url))
3080
2989
        return stored_location
3081
2990
 
3082
2991
 
3237
3146
        elif len(revision) != 1:
3238
3147
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3239
3148
        else:
3240
 
            rev_id = revision[0].as_revision_id(tree.branch)
 
3149
            rev_id = revision[0].in_history(tree.branch).rev_id
3241
3150
        pb = ui.ui_factory.nested_progress_bar()
3242
3151
        try:
3243
3152
            tree.revert(file_list,
3291
3200
        shellcomplete.shellcomplete(context)
3292
3201
 
3293
3202
 
 
3203
class cmd_fetch(Command):
 
3204
    """Copy in history from another branch but don't merge it.
 
3205
 
 
3206
    This is an internal method used for pull and merge.
 
3207
    """
 
3208
    hidden = True
 
3209
    takes_args = ['from_branch', 'to_branch']
 
3210
    def run(self, from_branch, to_branch):
 
3211
        from bzrlib.fetch import Fetcher
 
3212
        from_b = Branch.open(from_branch)
 
3213
        to_b = Branch.open(to_branch)
 
3214
        Fetcher(to_b, from_b)
 
3215
 
 
3216
 
3294
3217
class cmd_missing(Command):
3295
3218
    """Show unmerged/unpulled revisions between two branches.
3296
3219
    
3320
3243
        from bzrlib.missing import find_unmerged, iter_log_revisions
3321
3244
 
3322
3245
        if this:
3323
 
            mine_only = this
 
3246
          mine_only = this
3324
3247
        if other:
3325
 
            theirs_only = other
3326
 
        # TODO: We should probably check that we don't have mine-only and
3327
 
        #       theirs-only set, but it gets complicated because we also have
3328
 
        #       this and other which could be used.
3329
 
        restrict = 'all'
3330
 
        if mine_only:
3331
 
            restrict = 'local'
3332
 
        elif theirs_only:
3333
 
            restrict = 'remote'
 
3248
          theirs_only = other
3334
3249
 
3335
3250
        local_branch = Branch.open_containing(u".")[0]
3336
3251
        parent = local_branch.get_parent()
3350
3265
        try:
3351
3266
            remote_branch.lock_read()
3352
3267
            try:
3353
 
                local_extra, remote_extra = find_unmerged(
3354
 
                    local_branch, remote_branch, restrict)
3355
 
 
 
3268
                local_extra, remote_extra = find_unmerged(local_branch,
 
3269
                                                          remote_branch)
3356
3270
                if log_format is None:
3357
3271
                    registry = log.log_formatter_registry
3358
3272
                    log_format = registry.get_default(local_branch)
3360
3274
                                show_ids=show_ids,
3361
3275
                                show_timezone='original')
3362
3276
                if reverse is False:
3363
 
                    if local_extra is not None:
3364
 
                        local_extra.reverse()
3365
 
                    if remote_extra is not None:
3366
 
                        remote_extra.reverse()
3367
 
 
3368
 
                status_code = 0
 
3277
                    local_extra.reverse()
 
3278
                    remote_extra.reverse()
3369
3279
                if local_extra and not theirs_only:
3370
3280
                    self.outf.write("You have %d extra revision(s):\n" %
3371
3281
                                    len(local_extra))
3374
3284
                                        verbose):
3375
3285
                        lf.log_revision(revision)
3376
3286
                    printed_local = True
3377
 
                    status_code = 1
3378
3287
                else:
3379
3288
                    printed_local = False
3380
 
 
3381
3289
                if remote_extra and not mine_only:
3382
3290
                    if printed_local is True:
3383
3291
                        self.outf.write("\n\n\n")
3387
3295
                                        remote_branch.repository,
3388
3296
                                        verbose):
3389
3297
                        lf.log_revision(revision)
3390
 
                    status_code = 1
3391
 
 
3392
 
                if mine_only and not local_extra:
3393
 
                    # We checked local, and found nothing extra
3394
 
                    self.outf.write('This branch is up to date.\n')
3395
 
                elif theirs_only and not remote_extra:
3396
 
                    # We checked remote, and found nothing extra
3397
 
                    self.outf.write('Other branch is up to date.\n')
3398
 
                elif not (mine_only or theirs_only or local_extra or
3399
 
                          remote_extra):
3400
 
                    # We checked both branches, and neither one had extra
3401
 
                    # revisions
 
3298
                if not remote_extra and not local_extra:
 
3299
                    status_code = 0
3402
3300
                    self.outf.write("Branches are up to date.\n")
 
3301
                else:
 
3302
                    status_code = 1
3403
3303
            finally:
3404
3304
                remote_branch.unlock()
3405
3305
        finally:
3434
3334
class cmd_plugins(Command):
3435
3335
    """List the installed plugins.
3436
3336
    
3437
 
    This command displays the list of installed plugins including
3438
 
    version of plugin and a short description of each.
3439
 
 
3440
 
    --verbose shows the path where each plugin is located.
 
3337
    This command displays the list of installed plugins including the
 
3338
    path where each one is located and a short description of each.
3441
3339
 
3442
3340
    A plugin is an external component for Bazaar that extends the
3443
3341
    revision control system, by adding or replacing code in Bazaar.
3450
3348
    install them. Instructions are also provided there on how to
3451
3349
    write new plugins using the Python programming language.
3452
3350
    """
3453
 
    takes_options = ['verbose']
3454
3351
 
3455
3352
    @display_command
3456
 
    def run(self, verbose=False):
 
3353
    def run(self):
3457
3354
        import bzrlib.plugin
3458
3355
        from inspect import getdoc
3459
 
        result = []
3460
3356
        for name, plugin in bzrlib.plugin.plugins().items():
3461
 
            version = plugin.__version__
3462
 
            if version == 'unknown':
3463
 
                version = ''
3464
 
            name_ver = '%s %s' % (name, version)
 
3357
            print plugin.path(), "[%s]" % plugin.__version__
3465
3358
            d = getdoc(plugin.module)
3466
3359
            if d:
3467
 
                doc = d.split('\n')[0]
3468
 
            else:
3469
 
                doc = '(no description)'
3470
 
            result.append((name_ver, doc, plugin.path()))
3471
 
        for name_ver, doc, path in sorted(result):
3472
 
            print name_ver
3473
 
            print '   ', doc
3474
 
            if verbose:
3475
 
                print '   ', path
3476
 
            print
 
3360
                print '\t', d.split('\n')[0]
3477
3361
 
3478
3362
 
3479
3363
class cmd_testament(Command):
3491
3375
            testament_class = StrictTestament
3492
3376
        else:
3493
3377
            testament_class = Testament
3494
 
        if branch == '.':
3495
 
            b = Branch.open_containing(branch)[0]
3496
 
        else:
3497
 
            b = Branch.open(branch)
 
3378
        b = WorkingTree.open_containing(branch)[0].branch
3498
3379
        b.lock_read()
3499
3380
        try:
3500
3381
            if revision is None:
3501
3382
                rev_id = b.last_revision()
3502
3383
            else:
3503
 
                rev_id = revision[0].as_revision_id(b)
 
3384
                rev_id = revision[0].in_history(b).rev_id
3504
3385
            t = testament_class.from_revision(b.repository, rev_id)
3505
3386
            if long:
3506
3387
                sys.stdout.writelines(t.as_text_lines())
3535
3416
    def run(self, filename, all=False, long=False, revision=None,
3536
3417
            show_ids=False):
3537
3418
        from bzrlib.annotate import annotate_file
3538
 
        wt, branch, relpath = \
3539
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
3540
 
        if wt is not None:
3541
 
            wt.lock_read()
3542
 
        else:
3543
 
            branch.lock_read()
 
3419
        tree, relpath = WorkingTree.open_containing(filename)
 
3420
        branch = tree.branch
 
3421
        branch.lock_read()
3544
3422
        try:
3545
3423
            if revision is None:
3546
3424
                revision_id = branch.last_revision()
3547
3425
            elif len(revision) != 1:
3548
3426
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3549
3427
            else:
3550
 
                revision_id = revision[0].as_revision_id(branch)
3551
 
            tree = branch.repository.revision_tree(revision_id)
3552
 
            if wt is not None:
3553
 
                file_id = wt.path2id(relpath)
3554
 
            else:
3555
 
                file_id = tree.path2id(relpath)
 
3428
                revision_id = revision[0].in_history(branch).rev_id
 
3429
            file_id = tree.path2id(relpath)
3556
3430
            if file_id is None:
3557
3431
                raise errors.NotVersionedError(filename)
 
3432
            tree = branch.repository.revision_tree(revision_id)
3558
3433
            file_version = tree.inventory[file_id].revision
3559
3434
            annotate_file(branch, file_version, file_id, long, all, self.outf,
3560
3435
                          show_ids=show_ids)
3561
3436
        finally:
3562
 
            if wt is not None:
3563
 
                wt.unlock()
3564
 
            else:
3565
 
                branch.unlock()
 
3437
            branch.unlock()
3566
3438
 
3567
3439
 
3568
3440
class cmd_re_sign(Command):
3692
3564
    specified revision.  For example, "bzr uncommit -r 15" will leave the
3693
3565
    branch at revision 15.
3694
3566
 
3695
 
    Uncommit leaves the working tree ready for a new commit.  The only change
3696
 
    it may make is to restore any pending merges that were present before
3697
 
    the commit.
 
3567
    In the future, uncommit will create a revision bundle, which can then
 
3568
    be re-applied.
3698
3569
    """
3699
3570
 
3700
3571
    # TODO: jam 20060108 Add an option to allow uncommit to remove
3704
3575
    _see_also = ['commit']
3705
3576
    takes_options = ['verbose', 'revision',
3706
3577
                    Option('dry-run', help='Don\'t actually make changes.'),
3707
 
                    Option('force', help='Say yes to all questions.'),
3708
 
                    Option('local',
3709
 
                           help="Only remove the commits from the local branch"
3710
 
                                " when in a checkout."
3711
 
                           ),
3712
 
                    ]
 
3578
                    Option('force', help='Say yes to all questions.')]
3713
3579
    takes_args = ['location?']
3714
3580
    aliases = []
3715
3581
    encoding_type = 'replace'
3716
3582
 
3717
3583
    def run(self, location=None,
3718
3584
            dry_run=False, verbose=False,
3719
 
            revision=None, force=False, local=False):
 
3585
            revision=None, force=False):
3720
3586
        if location is None:
3721
3587
            location = u'.'
3722
3588
        control, relpath = bzrdir.BzrDir.open_containing(location)
3732
3598
        else:
3733
3599
            b.lock_write()
3734
3600
        try:
3735
 
            return self._run(b, tree, dry_run, verbose, revision, force,
3736
 
                             local=local)
 
3601
            return self._run(b, tree, dry_run, verbose, revision, force)
3737
3602
        finally:
3738
3603
            if tree is not None:
3739
3604
                tree.unlock()
3740
3605
            else:
3741
3606
                b.unlock()
3742
3607
 
3743
 
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
 
3608
    def _run(self, b, tree, dry_run, verbose, revision, force):
3744
3609
        from bzrlib.log import log_formatter, show_log
3745
3610
        from bzrlib.uncommit import uncommit
3746
3611
 
3787
3652
                    print 'Canceled'
3788
3653
                    return 0
3789
3654
 
3790
 
        mutter('Uncommitting from {%s} to {%s}',
3791
 
               last_rev_id, rev_id)
3792
3655
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3793
 
                 revno=revno, local=local)
3794
 
        note('You can restore the old tip by running:\n'
3795
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
3656
                 revno=revno)
3796
3657
 
3797
3658
 
3798
3659
class cmd_break_lock(Command):
3857
3718
        ]
3858
3719
 
3859
3720
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
3860
 
        from bzrlib import lockdir
3861
3721
        from bzrlib.smart import medium, server
3862
3722
        from bzrlib.transport import get_transport
3863
3723
        from bzrlib.transport.chroot import ChrootServer
3888
3748
        # be changed with care though, as we dont want to use bandwidth sending
3889
3749
        # progress over stderr to smart server clients!
3890
3750
        old_factory = ui.ui_factory
3891
 
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
3892
3751
        try:
3893
3752
            ui.ui_factory = ui.SilentUIFactory()
3894
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
3895
3753
            smart_server.serve()
3896
3754
        finally:
3897
3755
            ui.ui_factory = old_factory
3898
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
3899
3756
 
3900
3757
 
3901
3758
class cmd_join(Command):
4053
3910
            if len(revision) > 2:
4054
3911
                raise errors.BzrCommandError('bzr merge-directive takes '
4055
3912
                    'at most two one revision identifiers')
4056
 
            revision_id = revision[-1].as_revision_id(branch)
 
3913
            revision_id = revision[-1].in_history(branch).rev_id
4057
3914
            if len(revision) == 2:
4058
 
                base_revision_id = revision[0].as_revision_id(branch)
 
3915
                base_revision_id = revision[0].in_history(branch).rev_id
 
3916
                base_revision_id = ensure_null(base_revision_id)
4059
3917
        else:
4060
3918
            revision_id = branch.last_revision()
4061
3919
        revision_id = ensure_null(revision_id)
4111
3969
    To use a specific mail program, set the mail_client configuration option.
4112
3970
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4113
3971
    specific clients are "evolution", "kmail", "mutt", and "thunderbird";
4114
 
    generic options are "default", "editor", "emacsclient", "mapi", and
4115
 
    "xdg-email".
 
3972
    generic options are "default", "editor", "mapi", and "xdg-email".
4116
3973
 
4117
3974
    If mail is being sent, a to address is required.  This can be supplied
4118
 
    either on the commandline, by setting the submit_to configuration
4119
 
    option in the branch itself or the child_submit_to configuration option 
4120
 
    in the submit branch.
 
3975
    either on the commandline, or by setting the submit_to configuration
 
3976
    option.
4121
3977
 
4122
3978
    Two formats are currently supported: "4" uses revision bundle format 4 and
4123
3979
    merge directive format 2.  It is significantly faster and smaller than
4124
3980
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
4125
3981
    default.  "0.9" uses revision bundle format 0.9 and merge directive
4126
3982
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
4127
 
    
4128
 
    Merge directives are applied using the merge command or the pull command.
4129
3983
    """
4130
3984
 
4131
3985
    encoding_type = 'exact'
4132
3986
 
4133
 
    _see_also = ['merge', 'pull']
 
3987
    _see_also = ['merge']
4134
3988
 
4135
3989
    takes_args = ['submit_branch?', 'public_branch?']
4136
3990
 
4146
4000
               'rather than the one containing the working directory.',
4147
4001
               short_name='f',
4148
4002
               type=unicode),
4149
 
        Option('output', short_name='o',
4150
 
               help='Write merge directive to this file; '
4151
 
                    'use - for stdout.',
 
4003
        Option('output', short_name='o', help='Write directive to this file.',
4152
4004
               type=unicode),
4153
4005
        Option('mail-to', help='Mail the request to this address.',
4154
4006
               type=unicode),
4204
4056
                raise errors.BzrCommandError('No submit branch known or'
4205
4057
                                             ' specified')
4206
4058
            if remembered_submit_branch:
4207
 
                note('Using saved location "%s" to determine what changes to submit.', submit_branch)
4208
 
 
4209
 
            if mail_to is None:
4210
 
                submit_config = Branch.open(submit_branch).get_config()
4211
 
                mail_to = submit_config.get_user_option("child_submit_to")
 
4059
                note('Using saved location: %s', submit_branch)
4212
4060
 
4213
4061
            stored_public_branch = branch.get_public_branch()
4214
4062
            if public_branch is None:
4224
4072
                if len(revision) > 2:
4225
4073
                    raise errors.BzrCommandError('bzr send takes '
4226
4074
                        'at most two one revision identifiers')
4227
 
                revision_id = revision[-1].as_revision_id(branch)
 
4075
                revision_id = revision[-1].in_history(branch).rev_id
4228
4076
                if len(revision) == 2:
4229
 
                    base_revision_id = revision[0].as_revision_id(branch)
 
4077
                    base_revision_id = revision[0].in_history(branch).rev_id
4230
4078
            if revision_id is None:
4231
4079
                revision_id = branch.last_revision()
4232
4080
            if revision_id == NULL_REVISION:
4264
4112
                else:
4265
4113
                    revision = branch.repository.get_revision(revision_id)
4266
4114
                    subject += revision.get_summary()
4267
 
                basename = directive.get_disk_name(branch)
4268
4115
                mail_client.compose_merge_request(mail_to, subject,
4269
 
                                                  outfile.getvalue(), basename)
 
4116
                                                  outfile.getvalue())
4270
4117
        finally:
4271
4118
            if output != '-':
4272
4119
                outfile.close()
4355
4202
 
4356
4203
    It is an error to give a tag name that already exists unless you pass 
4357
4204
    --force, in which case the tag is moved to point to the new revision.
4358
 
 
4359
 
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
4360
 
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
4361
4205
    """
4362
4206
 
4363
4207
    _see_also = ['commit', 'tags']
4395
4239
                        raise errors.BzrCommandError(
4396
4240
                            "Tags can only be placed on a single revision, "
4397
4241
                            "not on a range")
4398
 
                    revision_id = revision[0].as_revision_id(branch)
 
4242
                    revision_id = revision[0].in_history(branch).rev_id
4399
4243
                else:
4400
4244
                    revision_id = branch.last_revision()
4401
4245
                if (not force) and branch.tags.has_tag(tag_name):
4435
4279
            ):
4436
4280
        branch, relpath = Branch.open_containing(directory)
4437
4281
        tags = branch.tags.get_tag_dict().items()
4438
 
        if not tags:
4439
 
            return
4440
4282
        if sort == 'alpha':
4441
4283
            tags.sort()
4442
4284
        elif sort == 'time':
4473
4315
    If none of these is available, --bind-to must be specified.
4474
4316
    """
4475
4317
 
4476
 
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
4477
4318
    takes_args = ['location?']
4478
4319
    takes_options = [RegistryOption.from_kwargs('target_type',
4479
4320
                     title='Target type',
4480
4321
                     help='The type to reconfigure the directory to.',
4481
4322
                     value_switches=True, enum_switch=False,
4482
 
                     branch='Reconfigure to be an unbound branch '
4483
 
                        'with no working tree.',
4484
 
                     tree='Reconfigure to be an unbound branch '
4485
 
                        'with a working tree.',
4486
 
                     checkout='Reconfigure to be a bound branch '
4487
 
                        'with a working tree.',
4488
 
                     lightweight_checkout='Reconfigure to be a lightweight'
4489
 
                     ' checkout (with no local history).',
4490
 
                     standalone='Reconfigure to be a standalone branch '
4491
 
                        '(i.e. stop using shared repository).',
4492
 
                     use_shared='Reconfigure to use a shared repository.'),
 
4323
                     branch='Reconfigure to a branch.',
 
4324
                     tree='Reconfigure to a tree.',
 
4325
                     checkout='Reconfigure to a checkout.',
 
4326
                     lightweight_checkout='Reconfigure to a lightweight'
 
4327
                     ' checkout.'),
4493
4328
                     Option('bind-to', help='Branch to bind checkout to.',
4494
4329
                            type=str),
4495
4330
                     Option('force',
4511
4346
        elif target_type == 'lightweight-checkout':
4512
4347
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
4513
4348
                directory, bind_to)
4514
 
        elif target_type == 'use-shared':
4515
 
            reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
4516
 
        elif target_type == 'standalone':
4517
 
            reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
4518
4349
        reconfiguration.apply(force)
4519
4350
 
4520
4351
 
4530
4361
    are merged. The user can commit or revert these as they desire.
4531
4362
 
4532
4363
    Pending merges need to be committed or reverted before using switch.
4533
 
 
4534
 
    The path to the branch to switch to can be specified relative to the parent
4535
 
    directory of the current branch. For example, if you are currently in a
4536
 
    checkout of /path/to/branch, specifying 'newbranch' will find a branch at
4537
 
    /path/to/newbranch.
4538
4364
    """
4539
4365
 
4540
4366
    takes_args = ['to_location']
4544
4370
 
4545
4371
    def run(self, to_location, force=False):
4546
4372
        from bzrlib import switch
 
4373
        to_branch = Branch.open(to_location)
4547
4374
        tree_location = '.'
4548
4375
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4549
 
        try:
4550
 
            to_branch = Branch.open(to_location)
4551
 
        except errors.NotBranchError:
4552
 
            to_branch = Branch.open(
4553
 
                control_dir.open_branch().base + '../' + to_location)
4554
4376
        switch.switch(control_dir, to_branch, force)
4555
4377
        note('Switched to branch: %s',
4556
4378
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4557
4379
 
4558
4380
 
4559
 
class cmd_hooks(Command):
4560
 
    """Show a branch's currently registered hooks.
4561
 
    """
4562
 
 
4563
 
    hidden = True
4564
 
    takes_args = ['path?']
4565
 
 
4566
 
    def run(self, path=None):
4567
 
        if path is None:
4568
 
            path = '.'
4569
 
        branch_hooks = Branch.open(path).hooks
4570
 
        for hook_type in branch_hooks:
4571
 
            hooks = branch_hooks[hook_type]
4572
 
            self.outf.write("%s:\n" % (hook_type,))
4573
 
            if hooks:
4574
 
                for hook in hooks:
4575
 
                    self.outf.write("  %s\n" %
4576
 
                                    (branch_hooks.get_hook_name(hook),))
4577
 
            else:
4578
 
                self.outf.write("  <no hooks installed>\n")
4579
 
 
4580
 
 
4581
4381
def _create_prefix(cur_transport):
4582
4382
    needed = [cur_transport]
4583
4383
    # Recurse upwards until we can create a directory successfully
4600
4400
        cur_transport.ensure_base()
4601
4401
 
4602
4402
 
 
4403
def _get_mergeable_helper(location):
 
4404
    """Get a merge directive or bundle if 'location' points to one.
 
4405
 
 
4406
    Try try to identify a bundle and returns its mergeable form. If it's not,
 
4407
    we return the tried transport anyway so that it can reused to access the
 
4408
    branch
 
4409
 
 
4410
    :param location: can point to a bundle or a branch.
 
4411
 
 
4412
    :return: mergeable, transport
 
4413
    """
 
4414
    mergeable = None
 
4415
    url = urlutils.normalize_url(location)
 
4416
    url, filename = urlutils.split(url, exclude_trailing_slash=False)
 
4417
    location_transport = transport.get_transport(url)
 
4418
    if filename:
 
4419
        try:
 
4420
            # There may be redirections but we ignore the intermediate
 
4421
            # and final transports used
 
4422
            read = bundle.read_mergeable_from_transport
 
4423
            mergeable, t = read(location_transport, filename)
 
4424
        except errors.NotABundle:
 
4425
            # Continue on considering this url a Branch but adjust the
 
4426
            # location_transport
 
4427
            location_transport = location_transport.clone(filename)
 
4428
    return mergeable, location_transport
 
4429
 
 
4430
 
4603
4431
# these get imported and then picked up by the scan for cmd_*
4604
4432
# TODO: Some more consistent way to split command definitions across files;
4605
4433
# we do need to load at least some information about them to know of 
4611
4439
    cmd_bundle_info,
4612
4440
    )
4613
4441
from bzrlib.sign_my_commits import cmd_sign_my_commits
4614
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
 
4442
from bzrlib.weave_commands import cmd_versionedfile_list, cmd_weave_join, \
4615
4443
        cmd_weave_plan_merge, cmd_weave_merge_text