comparison configmix/config.py @ 679:aa39c1856de4

Begin "ref:" support for jails. Currently jailed configurations do not work if the jail's root is located at a substitution.
author Franz Glasner <fzglas.hg@dom66.de>
date Fri, 09 Jun 2023 09:24:41 +0200
parents f39b96e2bb2a
children a9eef98e5038
comparison
equal deleted inserted replaced
678:f39b96e2bb2a 679:aa39c1856de4
936 if not pu.fragment: 936 if not pu.fragment:
937 return self 937 return self
938 if pu.fragment.startswith(_DOT): 938 if pu.fragment.startswith(_DOT):
939 raise ValueError("relative refs not supported") 939 raise ValueError("relative refs not supported")
940 return self.getvar(pu.fragment) 940 return self.getvar(pu.fragment)
941
942 def try_get_reference_uri(self, v):
943 """Check whether `v` is a configuration reference and -- if true --
944 return the configuration path where the reference points to.
945
946 If `v` is not a text type or not a reference return `None`.
947
948 Does not check whether the referenced configuration object exists.
949
950 :rtype: None or str
951
952 """
953 if not isinstance(v, _TEXTTYPE):
954 return None
955 if v.startswith(_STARTTOK_REF) and v.endswith(_ENDTOK_REF):
956 uri = v[len(_STARTTOK_REF):-len(_ENDTOK_REF)]
957 pu = urlsplit(uri)
958 if pu.scheme or pu.netloc or pu.path or pu.query:
959 raise ValueError("only fragment-only URIs are supported")
960 if not pu.fragment:
961 return _EMPTY_STR
962 if pu.fragment.startswith(_DOT):
963 raise ValueError("relative refs not supported")
964 return pu.fragment
965 return None
941 966
942 def substitute_variables_in_obj(self, obj): 967 def substitute_variables_in_obj(self, obj):
943 """Recursively expand variables in the object tree `obj`.""" 968 """Recursively expand variables in the object tree `obj`."""
944 ty = type(obj) 969 ty = type(obj)
945 if issubclass(ty, _TEXTTYPE): 970 if issubclass(ty, _TEXTTYPE):
1060 raise NameError("Filter %r not found" % (name, )) 1085 raise NameError("Filter %r not found" % (name, ))
1061 else: 1086 else:
1062 value = filterfn(self, value) 1087 value = filterfn(self, value)
1063 return value 1088 return value
1064 1089
1065 def jailed(self, rootpath=None, root=None, bind_root=True): 1090 def jailed(self, rootpath=None, root=None,
1091 bind_root=True, resolve_ref=True):
1066 """Return a "jailed" configuration of the current configuration. 1092 """Return a "jailed" configuration of the current configuration.
1067 1093
1068 :param rootpath: a sequence of strings (or objects) that shall 1094 :param rootpath: a sequence of strings (or objects) that shall
1069 emcompass the chroot-like jail of the returned 1095 emcompass the chroot-like jail of the returned
1070 configuration 1096 configuration
1073 the chroot-like jail of the returned configuration 1099 the chroot-like jail of the returned configuration
1074 :param bool bind_root: if you do a :meth:`~.rebind` just after 1100 :param bool bind_root: if you do a :meth:`~.rebind` just after
1075 creation of a jailed config you can set 1101 creation of a jailed config you can set
1076 `bind_root` to `False`; otherwise use 1102 `bind_root` to `False`; otherwise use
1077 the default 1103 the default
1104 :param bool resolve_ref: If `True` then the jail's root is checked
1105 whether it is a reference. If it is a
1106 reference then the jail is effectively rooted
1107 where the reference points to.
1078 :return: a jailed (aka restricted) configuration 1108 :return: a jailed (aka restricted) configuration
1079 :rtype: _JailedConfiguration 1109 :rtype: _JailedConfiguration
1080 1110
1081 Exactly one of `rootpath` or `root` must be given. 1111 Exactly one of `rootpath` or `root` must be given.
1082 1112
1092 varns, varname = _split_ns(root) 1122 varns, varname = _split_ns(root)
1093 if varns: 1123 if varns:
1094 raise ValueError( 1124 raise ValueError(
1095 "jailed configurations do not support namespaces") 1125 "jailed configurations do not support namespaces")
1096 rootpath = pathstr2path(root) 1126 rootpath = pathstr2path(root)
1127 if resolve_ref:
1128 while True:
1129 target = self.getvarl(*rootpath)
1130 target_uri = self.try_get_reference_uri(target)
1131 if target_uri is None:
1132 break
1133 rootpath = pathstr2path(target_uri)
1097 jc = _JailedConfiguration(*rootpath) 1134 jc = _JailedConfiguration(*rootpath)
1098 if bind_root: 1135 if bind_root:
1099 jc.rebind(self) 1136 jc.rebind(self)
1100 return jc 1137 return jc
1101 1138
1321 1358
1322 def __bool__(self): 1359 def __bool__(self):
1323 """Map- and list-style evaluation in boolean context""" 1360 """Map- and list-style evaluation in boolean context"""
1324 return bool(self._base.getvarl_s(*self._path)) 1361 return bool(self._base.getvarl_s(*self._path))
1325 1362
1326 def jailed(self, rootpath=None, root=None, bind_root=True): 1363 def jailed(self, rootpath=None, root=None,
1364 bind_root=True, resolve_ref=True):
1327 """Return a "jailed" configuration that effectively is a 1365 """Return a "jailed" configuration that effectively is a
1328 subjail of the current jail 1366 subjail of the current jail
1329 1367
1330 For a more complete description see :meth:`.Configuration.jailed`. 1368 For a more complete description see :meth:`.Configuration.jailed`.
1331 1369
1345 rootpath = pathstr2path(varname) 1383 rootpath = pathstr2path(varname)
1346 if self._path: 1384 if self._path:
1347 new_rootpath = self._path + tuple(rootpath) 1385 new_rootpath = self._path + tuple(rootpath)
1348 else: 1386 else:
1349 new_rootpath = tuple(rootpath) 1387 new_rootpath = tuple(rootpath)
1388 if resolve_ref:
1389 while True:
1390 target = self._base.getvarl(*new_rootpath)
1391 target_uri = self._base.try_get_reference_uri(target)
1392 if target_uri is None:
1393 break
1394 new_rootpath = pathstr2path(target_uri)
1350 sjc = _JailedConfiguration(*new_rootpath) 1395 sjc = _JailedConfiguration(*new_rootpath)
1351 if bind_root: 1396 if bind_root:
1352 sjc.rebind(self._base) 1397 sjc.rebind(self._base)
1353 return sjc 1398 return sjc
1354 1399