~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-01 19:18:09 UTC
  • mfrom: (6459 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6460.
  • Revision ID: jelmer@samba.org-20120201191809-xn340a5i5v4fqsfu
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
355
355
            location of this control directory.
356
356
        :param create_tree_if_local: If true, a working-tree will be created
357
357
            when working locally.
 
358
        :return: The created control directory
358
359
        """
359
360
        operation = cleanup.OperationWithCleanups(self._sprout)
360
361
        return operation.run(url, revision_id=revision_id,
809
810
    present within a BzrDir.
810
811
    """
811
812
 
 
813
    def _get_branch_path(self, name):
 
814
        """Obtain the branch path to use.
 
815
 
 
816
        This uses the API specified branch name first, and then falls back to
 
817
        the branch name specified in the URL. If neither of those is specified,
 
818
        it uses the default branch.
 
819
 
 
820
        :param name: Optional branch name to use
 
821
        :return: Relative path to branch
 
822
        """
 
823
        if name == "":
 
824
            return 'branch'
 
825
        return urlutils.join('branches', name.encode("utf-8"))
 
826
 
 
827
    def _read_branch_list(self):
 
828
        """Read the branch list.
 
829
 
 
830
        :return: List of utf-8 encoded branch names.
 
831
        """
 
832
        try:
 
833
            f = self.control_transport.get('branch-list')
 
834
        except errors.NoSuchFile:
 
835
            return []
 
836
 
 
837
        ret = []
 
838
        try:
 
839
            for name in f:
 
840
                ret.append(name.rstrip("\n"))
 
841
        finally:
 
842
            f.close()
 
843
        return ret
 
844
 
 
845
    def _write_branch_list(self, branches):
 
846
        """Write out the branch list.
 
847
 
 
848
        :param branches: List of utf-8 branch names to write
 
849
        """
 
850
        self.transport.put_bytes('branch-list',
 
851
            "".join([name+"\n" for name in branches]))
 
852
 
812
853
    def __init__(self, _transport, _format):
813
854
        super(BzrDirMeta1, self).__init__(_transport, _format)
814
 
        self.control_files = lockable_files.LockableFiles(self.control_transport,
815
 
            self._format._lock_file_name, self._format._lock_class)
 
855
        self.control_files = lockable_files.LockableFiles(
 
856
            self.control_transport, self._format._lock_file_name,
 
857
            self._format._lock_class)
816
858
 
817
859
    def can_convert_format(self):
818
860
        """See BzrDir.can_convert_format()."""
820
862
 
821
863
    def create_branch(self, name=None, repository=None,
822
864
            append_revisions_only=None):
823
 
        """See BzrDir.create_branch."""
 
865
        """See ControlDir.create_branch."""
824
866
        if name is None:
825
867
            name = self._get_selected_branch()
826
868
        return self._format.get_branch_format().initialize(self, name=name,
828
870
                append_revisions_only=append_revisions_only)
829
871
 
830
872
    def destroy_branch(self, name=None):
831
 
        """See BzrDir.create_branch."""
 
873
        """See ControlDir.destroy_branch."""
832
874
        if name is None:
833
875
            name = self._get_selected_branch()
 
876
        path = self._get_branch_path(name)
834
877
        if name != "":
835
 
            raise errors.NoColocatedBranchSupport(self)
836
 
        self.transport.delete_tree('branch')
 
878
            self.control_files.lock_write()
 
879
            try:
 
880
                branches = self._read_branch_list()
 
881
                try:
 
882
                    branches.remove(name.encode("utf-8"))
 
883
                except ValueError:
 
884
                    raise errors.NotBranchError(name)
 
885
                self._write_branch_list(branches)
 
886
            finally:
 
887
                self.control_files.unlock()
 
888
        try:
 
889
            self.transport.delete_tree(path)
 
890
        except errors.NoSuchFile:
 
891
            raise errors.NotBranchError(path=urlutils.join(self.transport.base,
 
892
                path), bzrdir=self)
837
893
 
838
894
    def create_repository(self, shared=False):
839
895
        """See BzrDir.create_repository."""
895
951
        """See BzrDir.get_branch_transport()."""
896
952
        if name is None:
897
953
            name = self._get_selected_branch()
898
 
        if name != "":
899
 
            raise errors.NoColocatedBranchSupport(self)
 
954
        path = self._get_branch_path(name)
900
955
        # XXX: this shouldn't implicitly create the directory if it's just
901
956
        # promising to get a transport -- mbp 20090727
902
957
        if branch_format is None:
903
 
            return self.transport.clone('branch')
 
958
            return self.transport.clone(path)
904
959
        try:
905
960
            branch_format.get_format_string()
906
961
        except NotImplementedError:
907
962
            raise errors.IncompatibleFormat(branch_format, self._format)
 
963
        if name != "":
 
964
            branches = self._read_branch_list()
 
965
            utf8_name = name.encode("utf-8")
 
966
            if not utf8_name in branches:
 
967
                self.control_files.lock_write()
 
968
                try:
 
969
                    branches = self._read_branch_list()
 
970
                    dirname = urlutils.dirname(utf8_name)
 
971
                    if dirname != "" and dirname in branches:
 
972
                        raise errors.ParentBranchExists(name)
 
973
                    child_branches = [
 
974
                        b.startswith(utf8_name+"/") for b in branches]
 
975
                    if any(child_branches):
 
976
                        raise errors.AlreadyBranchError(name)
 
977
                    branches.append(utf8_name)
 
978
                    self._write_branch_list(branches)
 
979
                finally:
 
980
                    self.control_files.unlock()
 
981
        branch_transport = self.transport.clone(path)
 
982
        mode = self._get_mkdir_mode()
 
983
        branch_transport.create_prefix(mode=mode)
908
984
        try:
909
 
            self.transport.mkdir('branch', mode=self._get_mkdir_mode())
 
985
            self.transport.mkdir(path, mode=mode)
910
986
        except errors.FileExists:
911
987
            pass
912
 
        return self.transport.clone('branch')
 
988
        return self.transport.clone(path)
913
989
 
914
990
    def get_repository_transport(self, repository_format):
915
991
        """See BzrDir.get_repository_transport()."""
939
1015
            pass
940
1016
        return self.transport.clone('checkout')
941
1017
 
 
1018
    def get_branches(self):
 
1019
        """See ControlDir.get_branches."""
 
1020
        ret = {}
 
1021
        try:
 
1022
            ret[""] = self.open_branch(name="")
 
1023
        except (errors.NotBranchError, errors.NoRepositoryPresent):
 
1024
            pass
 
1025
 
 
1026
        for name in self._read_branch_list():
 
1027
            ret[name] = self.open_branch(name=name.decode('utf-8'))
 
1028
 
 
1029
        return ret
 
1030
 
942
1031
    def has_workingtree(self):
943
1032
        """Tell if this bzrdir contains a working tree.
944
1033
 
1012
1101
        return config.TransportConfig(self.transport, 'control.conf')
1013
1102
 
1014
1103
 
1015
 
class BzrDirMeta1Colo(BzrDirMeta1):
1016
 
    """BzrDirMeta1 with support for colocated branches.
1017
 
 
1018
 
    This format is experimental, and will eventually be merged back into
1019
 
    BzrDirMeta1.
1020
 
    """
1021
 
 
1022
 
    def _get_branch_path(self, name):
1023
 
        """Obtain the branch path to use.
1024
 
 
1025
 
        This uses the API specified branch name first, and then falls back to
1026
 
        the branch name specified in the URL. If neither of those is specified,
1027
 
        it uses the default branch.
1028
 
 
1029
 
        :param name: Optional branch name to use
1030
 
        :return: Relative path to branch
1031
 
        """
1032
 
        if name == "":
1033
 
            return 'branch'
1034
 
        return urlutils.join('branches', name.encode("utf-8"))
1035
 
 
1036
 
    def _read_branch_list(self):
1037
 
        """Read the branch list.
1038
 
 
1039
 
        :return: List of utf-8 encoded branch names.
1040
 
        """
1041
 
        try:
1042
 
            f = self.control_transport.get('branch-list')
1043
 
        except errors.NoSuchFile:
1044
 
            return []
1045
 
 
1046
 
        ret = []
1047
 
        try:
1048
 
            for name in f:
1049
 
                ret.append(name.rstrip("\n"))
1050
 
        finally:
1051
 
            f.close()
1052
 
        return ret
1053
 
 
1054
 
    def _write_branch_list(self, branches):
1055
 
        """Write out the branch list.
1056
 
 
1057
 
        :param branches: List of utf-8 branch names to write
1058
 
        """
1059
 
        self.transport.put_bytes('branch-list',
1060
 
            "".join([name+"\n" for name in branches]))
1061
 
 
1062
 
    def destroy_branch(self, name=None):
1063
 
        """See BzrDir.create_branch."""
1064
 
        if name is None:
1065
 
            name = self._get_selected_branch()
1066
 
        path = self._get_branch_path(name)
1067
 
        if name != "":
1068
 
            self.control_files.lock_write()
1069
 
            try:
1070
 
                branches = self._read_branch_list()
1071
 
                try:
1072
 
                    branches.remove(name.encode("utf-8"))
1073
 
                except ValueError:
1074
 
                    raise errors.NotBranchError(name)
1075
 
                self._write_branch_list(branches)
1076
 
            finally:
1077
 
                self.control_files.unlock()
1078
 
        self.transport.delete_tree(path)
1079
 
 
1080
 
    def get_branches(self):
1081
 
        """See ControlDir.get_branches."""
1082
 
        ret = {}
1083
 
        try:
1084
 
            ret[""] = self.open_branch(name="")
1085
 
        except (errors.NotBranchError, errors.NoRepositoryPresent):
1086
 
            pass
1087
 
 
1088
 
        for name in self._read_branch_list():
1089
 
            ret[name] = self.open_branch(name=name.decode('utf-8'))
1090
 
 
1091
 
        return ret
1092
 
 
1093
 
    def get_branch_transport(self, branch_format, name=None):
1094
 
        """See BzrDir.get_branch_transport()."""
1095
 
        if name is None:
1096
 
            name = self._get_selected_branch()
1097
 
        path = self._get_branch_path(name)
1098
 
        # XXX: this shouldn't implicitly create the directory if it's just
1099
 
        # promising to get a transport -- mbp 20090727
1100
 
        if branch_format is None:
1101
 
            return self.transport.clone(path)
1102
 
        try:
1103
 
            branch_format.get_format_string()
1104
 
        except NotImplementedError:
1105
 
            raise errors.IncompatibleFormat(branch_format, self._format)
1106
 
        if name != "":
1107
 
            try:
1108
 
                self.transport.mkdir('branches', mode=self._get_mkdir_mode())
1109
 
            except errors.FileExists:
1110
 
                pass
1111
 
            branches = self._read_branch_list()
1112
 
            utf8_name = name.encode("utf-8")
1113
 
            if not utf8_name in branches:
1114
 
                self.control_files.lock_write()
1115
 
                try:
1116
 
                    branches = self._read_branch_list()
1117
 
                    branches.append(utf8_name)
1118
 
                    self._write_branch_list(branches)
1119
 
                finally:
1120
 
                    self.control_files.unlock()
1121
 
        try:
1122
 
            self.transport.mkdir(path, mode=self._get_mkdir_mode())
1123
 
        except errors.FileExists:
1124
 
            pass
1125
 
        return self.transport.clone(path)
1126
 
 
1127
 
 
1128
1104
class BzrFormat(object):
1129
1105
    """Base class for all formats of things living in metadirs.
1130
1106
 
1573
1549
 
1574
1550
    fixed_components = False
1575
1551
 
1576
 
    colocated_branches = False
 
1552
    colocated_branches = True
1577
1553
 
1578
1554
    def __init__(self):
1579
1555
        BzrDirFormat.__init__(self)
1706
1682
            return ConvertMetaToColo(format)
1707
1683
        if (type(self) is BzrDirMetaFormat1Colo and
1708
1684
            type(format) is BzrDirMetaFormat1):
1709
 
            return ConvertMetaRemoveColo(format)
 
1685
            return ConvertMetaToColo(format)
1710
1686
        if not isinstance(self, format.__class__):
1711
1687
            # converting away from metadir is not implemented
1712
1688
            raise NotImplementedError(self.get_converter)
1808
1784
        # problems.
1809
1785
        format = BzrDirMetaFormat1Colo()
1810
1786
        self._supply_sub_formats_to(format)
1811
 
        return BzrDirMeta1Colo(transport, format)
 
1787
        return BzrDirMeta1(transport, format)
1812
1788
 
1813
1789
 
1814
1790
BzrProber.formats.register(BzrDirMetaFormat1Colo.get_format_string(),
1910
1886
        return BzrDir.open_from_transport(to_convert.root_transport)
1911
1887
 
1912
1888
 
1913
 
class ConvertMetaRemoveColo(controldir.Converter):
1914
 
    """Remove colocated branch support from a bzrdir."""
 
1889
class ConvertMetaToColo(controldir.Converter):
 
1890
    """Convert a 'development-colo' bzrdir to a '2a' bzrdir."""
1915
1891
 
1916
1892
    def __init__(self, target_format):
1917
 
        """Create a converter.that downgrades a colocated branch metadir
1918
 
        to a regular metadir.
 
1893
        """Create a converter that converts a 'development-colo' metadir
 
1894
        to a '2a' metadir.
1919
1895
 
1920
1896
        :param target_format: The final metadir format that is desired.
1921
1897
        """
1923
1899
 
1924
1900
    def convert(self, to_convert, pb):
1925
1901
        """See Converter.convert()."""
1926
 
        to_convert.control_files.lock_write()
1927
 
        try:
1928
 
            branches = to_convert.list_branches()
1929
 
            if len(branches) > 1:
1930
 
                raise errors.BzrError("remove all but a single "
1931
 
                    "colocated branch when downgrading")
1932
 
        finally:
1933
 
            to_convert.control_files.unlock()
1934
1902
        to_convert.transport.put_bytes('branch-format',
1935
1903
            self.target_format.as_string())
1936
1904
        return BzrDir.open_from_transport(to_convert.root_transport)