~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Andrew Bennetts
  • Date: 2008-07-28 06:53:44 UTC
  • mfrom: (3581 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3583.
  • Revision ID: andrew.bennetts@canonical.com-20080728065344-ocndjoycs903q6fz
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006, 2007, 2008 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
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('stacked',
 
725
            help='Create a stacked branch that references the public location '
 
726
                'of the parent branch.'),
 
727
        Option('stacked-on',
 
728
            help='Create a stacked branch that refers to another branch '
 
729
                'for the commit history. Only the work not present in the '
 
730
                'referenced branch is included in the branch created.',
 
731
            type=unicode),
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, stacked_on=None,
 
739
        stacked=False):
 
740
        from bzrlib.push import _show_push_branch
 
741
 
 
742
        # Get the source branch and revision_id
734
743
        if directory is None:
735
744
            directory = '.'
736
745
        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
746
        if revision is not None:
770
747
            if len(revision) == 1:
771
748
                revision_id = revision[0].in_history(br_from).rev_id
775
752
        else:
776
753
            revision_id = br_from.last_revision()
777
754
 
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
 
755
        # Get the stacked_on branch, if any
 
756
        if stacked_on is not None:
 
757
            stacked_on = urlutils.normalize_url(stacked_on)
 
758
        elif stacked:
 
759
            parent_url = br_from.get_parent()
 
760
            if parent_url:
 
761
                parent = Branch.open(parent_url)
 
762
                stacked_on = parent.get_public_branch()
 
763
                if not stacked_on:
 
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
                    stacked_on = parent_url
 
769
            if not stacked_on:
 
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
            stacked_on=stacked_on, 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_url())
 
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
 
1936
1855
class cmd_ignore(Command):
1937
1856
    """Ignore specified files or patterns.
1938
1857
 
 
1858
    See ``bzr help patterns`` for details on the syntax of patterns.
 
1859
 
1939
1860
    To remove patterns from the ignore list, edit the .bzrignore file.
1940
 
 
1941
 
    Trailing slashes on patterns are ignored. 
1942
 
    If the pattern contains a slash or is a regular expression, it is compared 
1943
 
    to the whole path from the branch root.  Otherwise, it is compared to only
1944
 
    the last component of the path.  To match a file only in the root 
1945
 
    directory, prepend './'.
1946
 
 
1947
 
    Ignore patterns specifying absolute paths are not allowed.
1948
 
 
1949
 
    Ignore patterns may include globbing wildcards such as::
1950
 
 
1951
 
      ? - Matches any single character except '/'
1952
 
      * - Matches 0 or more characters except '/'
1953
 
      /**/ - Matches 0 or more directories in a path
1954
 
      [a-z] - Matches a single character from within a group of characters
1955
 
 
1956
 
    Ignore patterns may also be Python regular expressions.  
1957
 
    Regular expression ignore patterns are identified by a 'RE:' prefix 
1958
 
    followed by the regular expression.  Regular expression ignore patterns
1959
 
    may not include named or numbered groups.
 
1861
    After adding, editing or deleting that file either indirectly by
 
1862
    using this command or directly by using an editor, be sure to commit
 
1863
    it.
1960
1864
 
1961
1865
    Note: ignore patterns containing shell wildcards must be quoted from 
1962
1866
    the shell on Unix.
1983
1887
            bzr ignore "RE:(?!debian/).*"
1984
1888
    """
1985
1889
 
1986
 
    _see_also = ['status', 'ignored']
 
1890
    _see_also = ['status', 'ignored', 'patterns']
1987
1891
    takes_args = ['name_pattern*']
1988
1892
    takes_options = [
1989
1893
        Option('old-default-rules',
1991
1895
        ]
1992
1896
    
1993
1897
    def run(self, name_pattern_list=None, old_default_rules=None):
1994
 
        from bzrlib.atomicfile import AtomicFile
 
1898
        from bzrlib import ignores
1995
1899
        if old_default_rules is not None:
1996
1900
            # dump the rules and exit
1997
1901
            for pattern in ignores.OLD_DEFAULTS:
2008
1912
                raise errors.BzrCommandError(
2009
1913
                    "NAME_PATTERN should not be an absolute path")
2010
1914
        tree, relpath = WorkingTree.open_containing(u'.')
2011
 
        ifn = tree.abspath('.bzrignore')
2012
 
        if os.path.exists(ifn):
2013
 
            f = open(ifn, 'rt')
2014
 
            try:
2015
 
                igns = f.read().decode('utf-8')
2016
 
            finally:
2017
 
                f.close()
2018
 
        else:
2019
 
            igns = ''
2020
 
 
2021
 
        # TODO: If the file already uses crlf-style termination, maybe
2022
 
        # we should use that for the newly added lines?
2023
 
 
2024
 
        if igns and igns[-1] != '\n':
2025
 
            igns += '\n'
2026
 
        for name_pattern in name_pattern_list:
2027
 
            igns += name_pattern + '\n'
2028
 
 
2029
 
        f = AtomicFile(ifn, 'wb')
2030
 
        try:
2031
 
            f.write(igns.encode('utf-8'))
2032
 
            f.commit()
2033
 
        finally:
2034
 
            f.close()
2035
 
 
2036
 
        if not tree.path2id('.bzrignore'):
2037
 
            tree.add(['.bzrignore'])
2038
 
 
 
1915
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
2039
1916
        ignored = globbing.Globster(name_pattern_list)
2040
1917
        matches = []
2041
1918
        tree.lock_read()
3555
3432
            testament_class = StrictTestament
3556
3433
        else:
3557
3434
            testament_class = Testament
3558
 
        b = WorkingTree.open_containing(branch)[0].branch
 
3435
        if branch == '.':
 
3436
            b = Branch.open_containing(branch)[0]
 
3437
        else:
 
3438
            b = Branch.open(branch)
3559
3439
        b.lock_read()
3560
3440
        try:
3561
3441
            if revision is None:
4168
4048
    To use a specific mail program, set the mail_client configuration option.
4169
4049
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4170
4050
    specific clients are "evolution", "kmail", "mutt", and "thunderbird";
4171
 
    generic options are "default", "editor", "mapi", and "xdg-email".
 
4051
    generic options are "default", "editor", "emacsclient", "mapi", and
 
4052
    "xdg-email".
4172
4053
 
4173
4054
    If mail is being sent, a to address is required.  This can be supplied
4174
4055
    either on the commandline, by setting the submit_to configuration
4524
4405
    If none of these is available, --bind-to must be specified.
4525
4406
    """
4526
4407
 
 
4408
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
4527
4409
    takes_args = ['location?']
4528
4410
    takes_options = [RegistryOption.from_kwargs('target_type',
4529
4411
                     title='Target type',
4530
4412
                     help='The type to reconfigure the directory to.',
4531
4413
                     value_switches=True, enum_switch=False,
4532
 
                     branch='Reconfigure to a branch.',
4533
 
                     tree='Reconfigure to a tree.',
4534
 
                     checkout='Reconfigure to a checkout.',
4535
 
                     lightweight_checkout='Reconfigure to a lightweight'
4536
 
                     ' checkout.',
4537
 
                     standalone='Reconfigure to be standalone.',
 
4414
                     branch='Reconfigure to be an unbound branch '
 
4415
                        'with no working tree.',
 
4416
                     tree='Reconfigure to be an unbound branch '
 
4417
                        'with a working tree.',
 
4418
                     checkout='Reconfigure to be a bound branch '
 
4419
                        'with a working tree.',
 
4420
                     lightweight_checkout='Reconfigure to be a lightweight'
 
4421
                     ' checkout (with no local history).',
 
4422
                     standalone='Reconfigure to be a standalone branch '
 
4423
                        '(i.e. stop using shared repository).',
4538
4424
                     use_shared='Reconfigure to use a shared repository.'),
4539
4425
                     Option('bind-to', help='Branch to bind checkout to.',
4540
4426
                            type=str),