~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: 2008-07-14 08:21:19 UTC
  • mfrom: (3517.4.20 stacking)
  • Revision ID: pqm@pqm.ubuntu.com-20080714082119-ju6qe5weo8pp7f1c
merge integrated branch stacking

Show diffs side-by-side

added added

removed removed

Lines of Context:
721
721
                    ' directory exists, but does not already'
722
722
                    ' have a control directory.  This flag will'
723
723
                    ' allow push to proceed.'),
 
724
        Option('reference',
 
725
            help='Create a stacked branch that refers to another branch '
 
726
                'for the commit history. Only the work not present in the '
 
727
                'referenced branch is included in the branch created.',
 
728
            type=unicode),
 
729
        Option('stacked',
 
730
            help='Create a stacked branch that references the public location '
 
731
                'of the parent branch. See --reference for more information.'),
724
732
        ]
725
733
    takes_args = ['location?']
726
734
    encoding_type = 'replace'
727
735
 
728
736
    def run(self, location=None, remember=False, overwrite=False,
729
 
            create_prefix=False, verbose=False, revision=None,
730
 
            use_existing_dir=False,
731
 
            directory=None):
732
 
        # FIXME: Way too big!  Put this into a function called from the
733
 
        # command.
 
737
        create_prefix=False, verbose=False, revision=None,
 
738
        use_existing_dir=False, directory=None, reference=None, stacked=False):
 
739
        from bzrlib.push import _show_push_branch
 
740
 
 
741
        # Get the source branch and revision_id
734
742
        if directory is None:
735
743
            directory = '.'
736
744
        br_from = Branch.open_containing(directory)[0]
737
 
        stored_loc = br_from.get_push_location()
738
 
        if location is None:
739
 
            if stored_loc is None:
740
 
                raise errors.BzrCommandError("No push location known or specified.")
741
 
            else:
742
 
                display_url = urlutils.unescape_for_display(stored_loc,
743
 
                        self.outf.encoding)
744
 
                self.outf.write("Using saved location: %s\n" % display_url)
745
 
                location = stored_loc
746
 
 
747
 
        to_transport = transport.get_transport(location)
748
 
 
749
 
        br_to = repository_to = dir_to = None
750
 
        try:
751
 
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
752
 
        except errors.NotBranchError:
753
 
            pass # Didn't find anything
754
 
        else:
755
 
            # If we can open a branch, use its direct repository, otherwise see
756
 
            # if there is a repository without a branch.
757
 
            try:
758
 
                br_to = dir_to.open_branch()
759
 
            except errors.NotBranchError:
760
 
                # Didn't find a branch, can we find a repository?
761
 
                try:
762
 
                    repository_to = dir_to.find_repository()
763
 
                except errors.NoRepositoryPresent:
764
 
                    pass
765
 
            else:
766
 
                # Found a branch, so we must have found a repository
767
 
                repository_to = br_to.repository
768
 
 
769
745
        if revision is not None:
770
746
            if len(revision) == 1:
771
747
                revision_id = revision[0].in_history(br_from).rev_id
775
751
        else:
776
752
            revision_id = br_from.last_revision()
777
753
 
778
 
        push_result = None
779
 
        if verbose:
780
 
            old_rh = []
781
 
        if dir_to is None:
782
 
            # The destination doesn't exist; create it.
783
 
            # XXX: Refactor the create_prefix/no_create_prefix code into a
784
 
            #      common helper function
785
 
 
786
 
            def make_directory(transport):
787
 
                transport.mkdir('.')
788
 
                return transport
789
 
 
790
 
            def redirected(redirected_transport, e, redirection_notice):
791
 
                return transport.get_transport(e.get_target_url())
792
 
 
793
 
            try:
794
 
                to_transport = transport.do_catching_redirections(
795
 
                    make_directory, to_transport, redirected)
796
 
            except errors.FileExists:
797
 
                if not use_existing_dir:
798
 
                    raise errors.BzrCommandError("Target directory %s"
799
 
                         " already exists, but does not have a valid .bzr"
800
 
                         " directory. Supply --use-existing-dir to push"
801
 
                         " there anyway." % location)
802
 
            except errors.NoSuchFile:
803
 
                if not create_prefix:
804
 
                    raise errors.BzrCommandError("Parent directory of %s"
805
 
                        " does not exist."
806
 
                        "\nYou may supply --create-prefix to create all"
807
 
                        " leading parent directories."
808
 
                        % location)
809
 
                _create_prefix(to_transport)
810
 
            except errors.TooManyRedirections:
811
 
                raise errors.BzrCommandError("Too many redirections trying "
812
 
                                             "to make %s." % location)
813
 
 
814
 
            # Now the target directory exists, but doesn't have a .bzr
815
 
            # directory. So we need to create it, along with any work to create
816
 
            # all of the dependent branches, etc.
817
 
            dir_to = br_from.bzrdir.clone_on_transport(to_transport,
818
 
                                                       revision_id=revision_id)
819
 
            br_to = dir_to.open_branch()
820
 
            # TODO: Some more useful message about what was copied
821
 
            note('Created new branch.')
822
 
            # We successfully created the target, remember it
823
 
            if br_from.get_push_location() is None or remember:
824
 
                br_from.set_push_location(br_to.base)
825
 
        elif repository_to is None:
826
 
            # we have a bzrdir but no branch or repository
827
 
            # XXX: Figure out what to do other than complain.
828
 
            raise errors.BzrCommandError("At %s you have a valid .bzr control"
829
 
                " directory, but not a branch or repository. This is an"
830
 
                " unsupported configuration. Please move the target directory"
831
 
                " out of the way and try again."
832
 
                % location)
833
 
        elif br_to is None:
834
 
            # We have a repository but no branch, copy the revisions, and then
835
 
            # create a branch.
836
 
            repository_to.fetch(br_from.repository, revision_id=revision_id)
837
 
            br_to = br_from.clone(dir_to, revision_id=revision_id)
838
 
            note('Created new branch.')
839
 
            if br_from.get_push_location() is None or remember:
840
 
                br_from.set_push_location(br_to.base)
841
 
        else: # We have a valid to branch
842
 
            # We were able to connect to the remote location, so remember it
843
 
            # we don't need to successfully push because of possible divergence.
844
 
            if br_from.get_push_location() is None or remember:
845
 
                br_from.set_push_location(br_to.base)
846
 
            if verbose:
847
 
                old_rh = br_to.revision_history()
848
 
            try:
849
 
                try:
850
 
                    tree_to = dir_to.open_workingtree()
851
 
                except errors.NotLocalUrl:
852
 
                    warning("This transport does not update the working " 
853
 
                            "tree of: %s. See 'bzr help working-trees' for "
854
 
                            "more information." % br_to.base)
855
 
                    push_result = br_from.push(br_to, overwrite,
856
 
                                               stop_revision=revision_id)
857
 
                except errors.NoWorkingTree:
858
 
                    push_result = br_from.push(br_to, overwrite,
859
 
                                               stop_revision=revision_id)
860
 
                else:
861
 
                    tree_to.lock_write()
862
 
                    try:
863
 
                        push_result = br_from.push(tree_to.branch, overwrite,
864
 
                                                   stop_revision=revision_id)
865
 
                        tree_to.update()
866
 
                    finally:
867
 
                        tree_to.unlock()
868
 
            except errors.DivergedBranches:
869
 
                raise errors.BzrCommandError('These branches have diverged.'
870
 
                                        '  Try using "merge" and then "push".')
871
 
        if push_result is not None:
872
 
            push_result.report(self.outf)
873
 
        elif verbose:
874
 
            new_rh = br_to.revision_history()
875
 
            if old_rh != new_rh:
876
 
                # Something changed
877
 
                from bzrlib.log import show_changed_revisions
878
 
                show_changed_revisions(br_to, old_rh, new_rh,
879
 
                                       to_file=self.outf)
880
 
        else:
881
 
            # we probably did a clone rather than a push, so a message was
882
 
            # emitted above
883
 
            pass
 
754
        # Get the reference branch, if any
 
755
        if reference is not None:
 
756
            reference = urlutils.normalize_url(reference)
 
757
        elif stacked:
 
758
            reference = None
 
759
            parent_url = br_from.get_parent()
 
760
            if parent_url:
 
761
                parent = Branch.open(parent_url)
 
762
                reference = parent.get_public_branch()
 
763
                if not reference:
 
764
                    # I considered excluding non-http url's here, thus forcing
 
765
                    # 'public' branches only, but that only works for some
 
766
                    # users, so it's best to just depend on the user spotting an
 
767
                    # error by the feedback given to them. RBC 20080227.
 
768
                    reference = parent_url
 
769
            if not reference:
 
770
                raise errors.BzrCommandError(
 
771
                    "Could not determine branch to refer to.")
 
772
 
 
773
        # Get the destination location
 
774
        if location is None:
 
775
            stored_loc = br_from.get_push_location()
 
776
            if stored_loc is None:
 
777
                raise errors.BzrCommandError(
 
778
                    "No push location known or specified.")
 
779
            else:
 
780
                display_url = urlutils.unescape_for_display(stored_loc,
 
781
                        self.outf.encoding)
 
782
                self.outf.write("Using saved location: %s\n" % display_url)
 
783
                location = stored_loc
 
784
 
 
785
        _show_push_branch(br_from, revision_id, location, self.outf,
 
786
            verbose=verbose, overwrite=overwrite, remember=remember,
 
787
            reference=reference, create_prefix=create_prefix,
 
788
            use_existing_dir=use_existing_dir)
884
789
 
885
790
 
886
791
class cmd_branch(Command):
900
805
    _see_also = ['checkout']
901
806
    takes_args = ['from_location', 'to_location?']
902
807
    takes_options = ['revision', Option('hardlink',
903
 
        help='Hard-link working tree files where possible.')]
 
808
        help='Hard-link working tree files where possible.'),
 
809
        Option('stacked',
 
810
            help='Create a stacked branch referring to the source branch. '
 
811
                'The new branch will depend on the availability of the source '
 
812
                'branch for all operations.'),
 
813
        ]
904
814
    aliases = ['get', 'clone']
905
815
 
906
816
    def run(self, from_location, to_location=None, revision=None,
907
 
            hardlink=False):
 
817
            hardlink=False, stacked=False):
908
818
        from bzrlib.tag import _merge_tags_if_possible
909
819
        if revision is None:
910
820
            revision = [None]
939
849
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
940
850
                                            possible_transports=[to_transport],
941
851
                                            accelerator_tree=accelerator_tree,
942
 
                                            hardlink=hardlink)
 
852
                                            hardlink=hardlink, stacked=stacked)
943
853
                branch = dir.open_branch()
944
854
            except errors.NoSuchRevision:
945
855
                to_transport.delete_tree('.')
946
 
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
 
856
                msg = "The branch %s has no revision %s." % (from_location,
 
857
                    revision[0])
947
858
                raise errors.BzrCommandError(msg)
948
859
            _merge_tags_if_possible(br_from, branch)
949
 
            note('Branched %d revision(s).' % branch.revno())
 
860
            # If the source branch is stacked, the new branch may
 
861
            # be stacked whether we asked for that explicitly or not.
 
862
            # We therefore need a try/except here and not just 'if stacked:'
 
863
            try:
 
864
                note('Created new stacked branch referring to %s.' %
 
865
                    branch.get_stacked_on())
 
866
            except (errors.NotStacked, errors.UnstackableBranchFormat,
 
867
                errors.UnstackableRepositoryFormat), e:
 
868
                note('Branched %d revision(s).' % branch.revno())
950
869
        finally:
951
870
            br_from.unlock()
952
871