~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Jelmer Vernooij
  • Date: 2012-01-28 12:47:17 UTC
  • mfrom: (6437.3.28 2.5)
  • mto: This revision was merged to the branch mainline in revision 6451.
  • Revision ID: jelmer@canonical.com-20120128124717-80ggi7q1y7m2wjf0
MergeĀ 2.5.

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()."""
831
873
        """See BzrDir.create_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
        self.transport.delete_tree(path)
837
889
 
838
890
    def create_repository(self, shared=False):
839
891
        """See BzrDir.create_repository."""
895
947
        """See BzrDir.get_branch_transport()."""
896
948
        if name is None:
897
949
            name = self._get_selected_branch()
898
 
        if name != "":
899
 
            raise errors.NoColocatedBranchSupport(self)
 
950
        path = self._get_branch_path(name)
900
951
        # XXX: this shouldn't implicitly create the directory if it's just
901
952
        # promising to get a transport -- mbp 20090727
902
953
        if branch_format is None:
903
 
            return self.transport.clone('branch')
 
954
            return self.transport.clone(path)
904
955
        try:
905
956
            branch_format.get_format_string()
906
957
        except NotImplementedError:
907
958
            raise errors.IncompatibleFormat(branch_format, self._format)
 
959
        if name != "":
 
960
            branches = self._read_branch_list()
 
961
            utf8_name = name.encode("utf-8")
 
962
            if not utf8_name in branches:
 
963
                self.control_files.lock_write()
 
964
                try:
 
965
                    branches = self._read_branch_list()
 
966
                    dirname = urlutils.dirname(utf8_name)
 
967
                    if dirname != "" and dirname in branches:
 
968
                        raise errors.ParentBranchExists(name)
 
969
                    child_branches = [
 
970
                        b.startswith(utf8_name+"/") for b in branches]
 
971
                    if any(child_branches):
 
972
                        raise errors.AlreadyBranchError(name)
 
973
                    branches.append(utf8_name)
 
974
                    self._write_branch_list(branches)
 
975
                finally:
 
976
                    self.control_files.unlock()
 
977
        branch_transport = self.transport.clone(path)
 
978
        mode = self._get_mkdir_mode()
 
979
        branch_transport.create_prefix(mode=mode)
908
980
        try:
909
 
            self.transport.mkdir('branch', mode=self._get_mkdir_mode())
 
981
            self.transport.mkdir(path, mode=mode)
910
982
        except errors.FileExists:
911
983
            pass
912
 
        return self.transport.clone('branch')
 
984
        return self.transport.clone(path)
913
985
 
914
986
    def get_repository_transport(self, repository_format):
915
987
        """See BzrDir.get_repository_transport()."""
939
1011
            pass
940
1012
        return self.transport.clone('checkout')
941
1013
 
 
1014
    def get_branches(self):
 
1015
        """See ControlDir.get_branches."""
 
1016
        ret = {}
 
1017
        try:
 
1018
            ret[""] = self.open_branch(name="")
 
1019
        except (errors.NotBranchError, errors.NoRepositoryPresent):
 
1020
            pass
 
1021
 
 
1022
        for name in self._read_branch_list():
 
1023
            ret[name] = self.open_branch(name=name.decode('utf-8'))
 
1024
 
 
1025
        return ret
 
1026
 
942
1027
    def has_workingtree(self):
943
1028
        """Tell if this bzrdir contains a working tree.
944
1029
 
1012
1097
        return config.TransportConfig(self.transport, 'control.conf')
1013
1098
 
1014
1099
 
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
1100
class BzrFormat(object):
1129
1101
    """Base class for all formats of things living in metadirs.
1130
1102
 
1573
1545
 
1574
1546
    fixed_components = False
1575
1547
 
1576
 
    colocated_branches = False
 
1548
    colocated_branches = True
1577
1549
 
1578
1550
    def __init__(self):
1579
1551
        BzrDirFormat.__init__(self)
1706
1678
            return ConvertMetaToColo(format)
1707
1679
        if (type(self) is BzrDirMetaFormat1Colo and
1708
1680
            type(format) is BzrDirMetaFormat1):
1709
 
            return ConvertMetaRemoveColo(format)
 
1681
            return ConvertMetaToColo(format)
1710
1682
        if not isinstance(self, format.__class__):
1711
1683
            # converting away from metadir is not implemented
1712
1684
            raise NotImplementedError(self.get_converter)
1808
1780
        # problems.
1809
1781
        format = BzrDirMetaFormat1Colo()
1810
1782
        self._supply_sub_formats_to(format)
1811
 
        return BzrDirMeta1Colo(transport, format)
 
1783
        return BzrDirMeta1(transport, format)
1812
1784
 
1813
1785
 
1814
1786
BzrProber.formats.register(BzrDirMetaFormat1Colo.get_format_string(),
1910
1882
        return BzrDir.open_from_transport(to_convert.root_transport)
1911
1883
 
1912
1884
 
1913
 
class ConvertMetaRemoveColo(controldir.Converter):
1914
 
    """Remove colocated branch support from a bzrdir."""
 
1885
class ConvertMetaToColo(controldir.Converter):
 
1886
    """Convert a 'development-colo' bzrdir to a '2a' bzrdir."""
1915
1887
 
1916
1888
    def __init__(self, target_format):
1917
 
        """Create a converter.that downgrades a colocated branch metadir
1918
 
        to a regular metadir.
 
1889
        """Create a converter that converts a 'development-colo' metadir
 
1890
        to a '2a' metadir.
1919
1891
 
1920
1892
        :param target_format: The final metadir format that is desired.
1921
1893
        """
1923
1895
 
1924
1896
    def convert(self, to_convert, pb):
1925
1897
        """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
1898
        to_convert.transport.put_bytes('branch-format',
1935
1899
            self.target_format.as_string())
1936
1900
        return BzrDir.open_from_transport(to_convert.root_transport)