check variable and family name
This commit is contained in:
parent
bd299e3d2b
commit
e60fd4adbc
@ -34,3 +34,4 @@ Rougail est un bibliothèque python3 qui permet de charger des dictionnaires (fi
|
||||
## Les templates
|
||||
|
||||
- Type creole
|
||||
FIXME ^^
|
||||
|
@ -29,7 +29,6 @@ from typing import List, Any
|
||||
|
||||
from ..i18n import _
|
||||
from ..error import DictConsistencyError
|
||||
from ..config import RougailConfig
|
||||
|
||||
from .target import TargetAnnotator
|
||||
from .param import ParamAnnotator
|
||||
@ -75,13 +74,13 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
|
||||
for variable in self.get_variables():
|
||||
if not variable.auto_freeze:
|
||||
continue
|
||||
if variable.namespace != RougailConfig['variable_namespace']:
|
||||
if variable.namespace != self.objectspace.rougailconfig['variable_namespace']:
|
||||
msg = _(f'auto_freeze is not allowed in extra "{variable.namespace}"')
|
||||
raise DictConsistencyError(msg, 49, variable.xmlfiles)
|
||||
new_condition = self.objectspace.condition(variable.xmlfiles)
|
||||
new_condition.name = 'auto_frozen_if_not_in'
|
||||
new_condition.namespace = variable.namespace
|
||||
new_condition.source = RougailConfig['auto_freeze_variable']
|
||||
new_condition.source = self.objectspace.rougailconfig['auto_freeze_variable']
|
||||
new_param = self.objectspace.param(variable.xmlfiles)
|
||||
new_param.text = True
|
||||
new_condition.param = [new_param]
|
||||
@ -114,12 +113,9 @@ class ConditionAnnotator(TargetAnnotator, ParamAnnotator, Walk):
|
||||
if condition.optional is False or \
|
||||
self.objectspace.paths.path_is_defined(condition.source):
|
||||
continue
|
||||
if hasattr(condition, 'apply_on_fallback'):
|
||||
apply_action = condition.apply_on_fallback
|
||||
else:
|
||||
apply_on_fallback = condition.name.endswith('_if_in'):
|
||||
remove_conditions.append(idx)
|
||||
if apply_action:
|
||||
if (hasattr(condition, 'apply_on_fallback') and condition.apply_on_fallback) or \
|
||||
(not hasattr(condition, 'apply_on_fallback') and condition.name.endswith('_if_in')):
|
||||
self.force_actions_to_variable(condition)
|
||||
remove_conditions.sort(reverse=True)
|
||||
for idx in remove_conditions:
|
||||
|
@ -25,6 +25,8 @@ along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
|
||||
from ..i18n import _
|
||||
from ..error import DictConsistencyError
|
||||
from ..objspace import convert_boolean
|
||||
|
||||
|
||||
@ -116,6 +118,9 @@ class VariableAnnotator(Walk): # pylint: disable=R0903
|
||||
if not hasattr(objectspace.space, 'variables'):
|
||||
return
|
||||
self.objectspace = objectspace
|
||||
self.forbidden_name = ['services', self.objectspace.rougailconfig['variable_namespace']]
|
||||
for extra in self.objectspace.rougailconfig['extra_dictionaries']:
|
||||
self.forbidden_name.append(extra)
|
||||
self.convert_variable()
|
||||
self.convert_test()
|
||||
self.convert_help()
|
||||
@ -141,6 +146,10 @@ class VariableAnnotator(Walk): # pylint: disable=R0903
|
||||
variable,
|
||||
variable_type: str,
|
||||
) -> None:
|
||||
if variable.namespace == self.objectspace.rougailconfig['variable_namespace'] and \
|
||||
variable.name in self.forbidden_name:
|
||||
msg = _(f'the name of the variable "{variable.name}" cannot be the same as the name of a namespace')
|
||||
raise DictConsistencyError(msg, 54, variable.xmlfiles)
|
||||
if variable.type != 'symlink' and not hasattr(variable, 'description'):
|
||||
variable.description = variable.name
|
||||
if hasattr(variable, 'value'):
|
||||
|
@ -58,16 +58,22 @@ from .error import DictConsistencyError
|
||||
class RougailConvert:
|
||||
"""Rougail object
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
xmlreflector = XMLReflector()
|
||||
rougailobjspace = RougailObjSpace(xmlreflector)
|
||||
def __init__(self,
|
||||
rougailconfig: RougailConfig=None,
|
||||
) -> None:
|
||||
if rougailconfig is None:
|
||||
rougailconfig = RougailConfig
|
||||
xmlreflector = XMLReflector(rougailconfig)
|
||||
rougailobjspace = RougailObjSpace(xmlreflector,
|
||||
rougailconfig,
|
||||
)
|
||||
self._load_dictionaries(xmlreflector,
|
||||
rougailobjspace,
|
||||
RougailConfig['variable_namespace'],
|
||||
RougailConfig['dictionaries_dir'],
|
||||
rougailconfig['variable_namespace'],
|
||||
rougailconfig['dictionaries_dir'],
|
||||
)
|
||||
for namespace, extra_dir in RougailConfig['extra_dictionaries'].items():
|
||||
if namespace in ['services', RougailConfig['variable_namespace']]:
|
||||
for namespace, extra_dir in rougailconfig['extra_dictionaries'].items():
|
||||
if namespace in ['services', rougailconfig['variable_namespace']]:
|
||||
msg = _(f'Namespace name "{namespace}" is not allowed')
|
||||
raise DictConsistencyError(msg, 21, None)
|
||||
self._load_dictionaries(xmlreflector,
|
||||
@ -75,7 +81,7 @@ class RougailConvert:
|
||||
namespace,
|
||||
extra_dir,
|
||||
)
|
||||
functions_file = RougailConfig['functions_file']
|
||||
functions_file = rougailconfig['functions_file']
|
||||
SpaceAnnotator(rougailobjspace,
|
||||
functions_file,
|
||||
)
|
||||
|
@ -32,7 +32,6 @@ from .xmlreflector import XMLReflector
|
||||
from .utils import normalize_family
|
||||
from .error import SpaceObjShallNotBeUpdated, DictConsistencyError
|
||||
from .path import Path
|
||||
from .config import RougailConfig
|
||||
|
||||
# RougailObjSpace's elements that shall be forced to the Redefinable type
|
||||
FORCE_REDEFINABLES = ('family', 'follower', 'service', 'disknod', 'variables')
|
||||
@ -101,9 +100,10 @@ class RougailObjSpace:
|
||||
|
||||
def __init__(self,
|
||||
xmlreflector: XMLReflector,
|
||||
rougailconfig: 'RougailConfig',
|
||||
) -> None:
|
||||
self.space = ObjSpace()
|
||||
self.paths = Path()
|
||||
self.paths = Path(rougailconfig)
|
||||
|
||||
self.forced_text_elts_as_name = set(FORCED_TEXT_ELTS_AS_NAME)
|
||||
self.list_conditions = {}
|
||||
@ -112,6 +112,7 @@ class RougailObjSpace:
|
||||
self.has_dyn_option = False
|
||||
|
||||
self.make_object_space_classes(xmlreflector)
|
||||
self.rougailconfig = rougailconfig
|
||||
|
||||
def make_object_space_classes(self,
|
||||
xmlreflector: XMLReflector,
|
||||
@ -197,12 +198,12 @@ class RougailObjSpace:
|
||||
family_names.append(child.attrib['name'])
|
||||
try:
|
||||
# variable objects creation
|
||||
variableobj = self.get_variableobj(xmlfile,
|
||||
child,
|
||||
space,
|
||||
namespace,
|
||||
redefine_variables,
|
||||
)
|
||||
exists, variableobj = self.get_variableobj(xmlfile,
|
||||
child,
|
||||
space,
|
||||
namespace,
|
||||
redefine_variables,
|
||||
)
|
||||
except SpaceObjShallNotBeUpdated:
|
||||
continue
|
||||
self.set_text(child,
|
||||
@ -216,11 +217,12 @@ class RougailObjSpace:
|
||||
variableobj,
|
||||
redefine_variables,
|
||||
)
|
||||
self.set_path(namespace,
|
||||
document,
|
||||
variableobj,
|
||||
space,
|
||||
)
|
||||
if not exists:
|
||||
self.set_path(namespace,
|
||||
document,
|
||||
variableobj,
|
||||
space,
|
||||
)
|
||||
self.add_to_tree_structure(variableobj,
|
||||
space,
|
||||
child,
|
||||
@ -260,11 +262,12 @@ class RougailObjSpace:
|
||||
if child.tag in vars(space):
|
||||
# Atom instance has to be a singleton here
|
||||
# we do not re-create it, we reuse it
|
||||
return getattr(space, child.tag)
|
||||
return obj(xmlfile, name)
|
||||
return False, getattr(space, child.tag)
|
||||
return False, obj(xmlfile, name)
|
||||
# UnRedefinable object
|
||||
if child.tag not in vars(space):
|
||||
setattr(space, child.tag, [])
|
||||
return obj(xmlfile, name)
|
||||
return False, obj(xmlfile, name)
|
||||
|
||||
def _get_name(self,
|
||||
child,
|
||||
@ -301,12 +304,12 @@ class RougailObjSpace:
|
||||
redefine = convert_boolean(subspace.get('redefine', default_redefine))
|
||||
if redefine is True:
|
||||
if isinstance(existed_var, self.variable): # pylint: disable=E1101
|
||||
if namespace == RougailConfig['variable_namespace']:
|
||||
if namespace == self.rougailconfig['variable_namespace']:
|
||||
redefine_variables.append(name)
|
||||
else:
|
||||
redefine_variables.append(space.path + '.' + name)
|
||||
existed_var.xmlfiles.append(xmlfile)
|
||||
return existed_var
|
||||
return True, existed_var
|
||||
exists = convert_boolean(subspace.get('exists', True))
|
||||
if exists is False:
|
||||
raise SpaceObjShallNotBeUpdated()
|
||||
@ -327,7 +330,7 @@ class RougailObjSpace:
|
||||
if tag not in vars(space):
|
||||
setattr(space, tag, {})
|
||||
obj = getattr(self, child.tag)(xmlfile, name)
|
||||
return obj
|
||||
return False, obj
|
||||
|
||||
def get_existed_obj(self,
|
||||
name: str,
|
||||
@ -340,7 +343,7 @@ class RougailObjSpace:
|
||||
if child.tag in ['variable', 'family']:
|
||||
name = normalize_family(name)
|
||||
if child.tag == 'variable': # pylint: disable=E1101
|
||||
if namespace != RougailConfig['variable_namespace']:
|
||||
if namespace != self.rougailconfig['variable_namespace']:
|
||||
name = space.path + '.' + name
|
||||
if not self.paths.path_is_defined(name):
|
||||
return None
|
||||
@ -474,7 +477,7 @@ class RougailObjSpace:
|
||||
)
|
||||
elif isinstance(variableobj, self.family): # pylint: disable=E1101
|
||||
family_name = normalize_family(variableobj.name)
|
||||
if namespace != RougailConfig['variable_namespace']:
|
||||
if namespace != self.rougailconfig['variable_namespace']:
|
||||
family_name = namespace + '.' + family_name
|
||||
self.paths.add_family(namespace,
|
||||
family_name,
|
||||
|
@ -26,7 +26,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
from .i18n import _
|
||||
from .error import DictConsistencyError
|
||||
from .config import RougailConfig
|
||||
from .utils import normalize_family
|
||||
|
||||
|
||||
@ -36,11 +35,14 @@ class Path:
|
||||
|
||||
sample: path="creole.general.condition"
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self,
|
||||
rougailconfig: 'RougailConfig',
|
||||
) -> None:
|
||||
self.variables = {}
|
||||
self.families = {}
|
||||
self.full_paths_families = {}
|
||||
self.full_paths_variables = {}
|
||||
self.variable_namespace = rougailconfig['variable_namespace']
|
||||
|
||||
# Family
|
||||
def add_family(self,
|
||||
@ -51,8 +53,10 @@ class Path:
|
||||
) -> str: # pylint: disable=C0111
|
||||
"""Add a new family
|
||||
"""
|
||||
if namespace == RougailConfig['variable_namespace']:
|
||||
if namespace == self.variable_namespace:
|
||||
full_name = '.'.join([subpath, name])
|
||||
if name in self.full_paths_families:
|
||||
raise DictConsistencyError(_(f'Duplicate family name "{name}"'), 55, variableobj.xmlfiles)
|
||||
self.full_paths_families[name] = full_name
|
||||
else:
|
||||
if '.' not in name: # pragma: no cover
|
||||
@ -93,7 +97,7 @@ class Path:
|
||||
if name not in self.families:
|
||||
raise DictConsistencyError(_(f'unknown option {name}'), 42, [])
|
||||
dico = self.families[name]
|
||||
if current_namespace not in [RougailConfig['variable_namespace'], 'services'] and \
|
||||
if current_namespace not in [self.variable_namespace, 'services'] and \
|
||||
current_namespace != dico['namespace']:
|
||||
msg = _(f'A family located in the "{dico["namespace"]}" namespace '
|
||||
f'shall not be used in the "{current_namespace}" namespace')
|
||||
@ -117,7 +121,7 @@ class Path:
|
||||
self.variables[new_path]['leader'] = leadership_path
|
||||
self.variables[new_path]['variableobj'].path = new_path
|
||||
self.variables[new_path]['family'] = leadership_path
|
||||
if namespace == RougailConfig['variable_namespace']:
|
||||
if namespace == self.variable_namespace:
|
||||
self.full_paths_variables[name] = new_path
|
||||
|
||||
def is_leader(self, path): # pylint: disable=C0111
|
||||
@ -141,7 +145,7 @@ class Path:
|
||||
"""
|
||||
if '.' not in name:
|
||||
full_path = '.'.join([family, name])
|
||||
if namespace == RougailConfig['variable_namespace']:
|
||||
if namespace == self.variable_namespace:
|
||||
self.full_paths_variables[name] = full_path
|
||||
else:
|
||||
full_path = name
|
||||
@ -180,7 +184,7 @@ class Path:
|
||||
with_suffix=True,
|
||||
)
|
||||
namespace = dico['variableobj'].namespace
|
||||
if namespace not in [RougailConfig['variable_namespace'], 'services'] and \
|
||||
if namespace not in [self.variable_namespace, 'services'] and \
|
||||
current_namespace != namespace:
|
||||
msg = _(f'A variable located in the "{namespace}" namespace shall not be used '
|
||||
f'in the "{current_namespace}" namespace')
|
||||
|
@ -223,14 +223,17 @@ class RougailTemplate:
|
||||
"""
|
||||
def __init__(self, # pylint: disable=R0913
|
||||
config: Config,
|
||||
rougailconfig: RougailConfig=None,
|
||||
) -> None:
|
||||
if rougailconfig is None:
|
||||
rougailconfig = RougailConfig
|
||||
self.config = config
|
||||
self.destinations_dir = abspath(RougailConfig['destinations_dir'])
|
||||
self.tmp_dir = abspath(RougailConfig['tmp_dir'])
|
||||
self.templates_dir = abspath(RougailConfig['templates_dir'])
|
||||
self.patches_dir = abspath(RougailConfig['patches_dir'])
|
||||
self.destinations_dir = abspath(rougailconfig['destinations_dir'])
|
||||
self.tmp_dir = abspath(rougailconfig['tmp_dir'])
|
||||
self.templates_dir = abspath(rougailconfig['templates_dir'])
|
||||
self.patches_dir = abspath(rougailconfig['patches_dir'])
|
||||
eos = {}
|
||||
functions_file = RougailConfig['functions_file']
|
||||
functions_file = rougailconfig['functions_file']
|
||||
if isfile(functions_file):
|
||||
eosfunc = load_modules(functions_file)
|
||||
for func in dir(eosfunc):
|
||||
@ -238,6 +241,7 @@ class RougailTemplate:
|
||||
eos[func] = getattr(eosfunc, func)
|
||||
self.eosfunc = eos
|
||||
self.rougail_variables_dict = {}
|
||||
self.rougailconfig = rougailconfig
|
||||
|
||||
def patch_template(self,
|
||||
filename: str,
|
||||
@ -343,7 +347,7 @@ class RougailTemplate:
|
||||
chdir(self.templates_dir)
|
||||
for option in await self.config.option.list(type='all'):
|
||||
namespace = await option.option.name()
|
||||
is_variable_namespace = namespace == RougailConfig['variable_namespace']
|
||||
is_variable_namespace = namespace == self.rougailconfig['variable_namespace']
|
||||
self.rougail_variables_dict[namespace] = await self.load_variables(option,
|
||||
is_variable_namespace,
|
||||
)
|
||||
|
@ -28,7 +28,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
from json import dumps
|
||||
from os.path import isfile
|
||||
|
||||
from .config import RougailConfig
|
||||
from .annotator import CONVERT_OPTION
|
||||
from .objspace import RootRougailObject
|
||||
|
||||
@ -96,10 +95,10 @@ class TiramisuReflector:
|
||||
because `extra` family could use `variable_namespace` variables.
|
||||
"""
|
||||
if hasattr(self.objectspace.space, 'variables'):
|
||||
if RougailConfig['variable_namespace'] in self.objectspace.space.variables:
|
||||
yield self.objectspace.space.variables[RougailConfig['variable_namespace']]
|
||||
if self.objectspace.rougailconfig['variable_namespace'] in self.objectspace.space.variables:
|
||||
yield self.objectspace.space.variables[self.objectspace.rougailconfig['variable_namespace']]
|
||||
for elt, value in self.objectspace.space.variables.items():
|
||||
if elt != RougailConfig['variable_namespace']:
|
||||
if elt != self.objectspace.rougailconfig['variable_namespace']:
|
||||
yield value
|
||||
if hasattr(self.objectspace.space, 'services'):
|
||||
yield self.objectspace.space.services
|
||||
|
@ -32,7 +32,6 @@ from lxml.etree import DTD, parse, XMLSyntaxError # pylint: disable=E0611
|
||||
|
||||
from .i18n import _
|
||||
from .error import DictConsistencyError
|
||||
from .config import RougailConfig
|
||||
|
||||
|
||||
class XMLReflector:
|
||||
@ -40,14 +39,16 @@ class XMLReflector:
|
||||
parsing it, validating against the Creole DTD,
|
||||
writing the xml result on the disk
|
||||
"""
|
||||
def __init__(self):
|
||||
def __init__(self,
|
||||
rougailconfig: 'RougailConfig',
|
||||
) -> None:
|
||||
"""Loads the Creole DTD
|
||||
|
||||
:raises IOError: if the DTD is not found
|
||||
|
||||
:param dtdfilename: the full filename of the Creole DTD
|
||||
"""
|
||||
dtdfilename = RougailConfig['dtdfilename']
|
||||
dtdfilename = rougailconfig['dtdfilename']
|
||||
if not isfile(dtdfilename):
|
||||
raise IOError(_("no such DTD file: {}").format(dtdfilename))
|
||||
with open(dtdfilename, 'r') as dtdfd:
|
||||
|
15
tests/dictionaries/60extra_variable_name_extra/00-base.xml
Normal file
15
tests/dictionaries/60extra_variable_name_extra/00-base.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail>
|
||||
<variables>
|
||||
<family name="général">
|
||||
<variable name="mode_conteneur_actif" type="string" description="No change" hidden="True">
|
||||
<value>non</value>
|
||||
</variable>
|
||||
<variable name="activer_ejabberd" type="string" description="No change" hidden="True">
|
||||
<value>non</value>
|
||||
</variable>
|
||||
</family>
|
||||
</variables>
|
||||
</rougail>
|
||||
<!-- vim: ts=4 sw=4 expandtab
|
||||
-->
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<rougail>
|
||||
<variables>
|
||||
<variable name="extra"/>
|
||||
</variables>
|
||||
</rougail>
|
@ -0,0 +1 @@
|
||||
{"rougail.general.mode_conteneur_actif": "non", "rougail.general.activer_ejabberd": "non", "extra.extra": null}
|
@ -0,0 +1,20 @@
|
||||
from importlib.machinery import SourceFileLoader
|
||||
from importlib.util import spec_from_loader, module_from_spec
|
||||
loader = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
|
||||
spec = spec_from_loader(loader.name, loader)
|
||||
func = module_from_spec(spec)
|
||||
loader.exec_module(func)
|
||||
for key, value in dict(locals()).items():
|
||||
if key != ['SourceFileLoader', 'func']:
|
||||
setattr(func, key, value)
|
||||
try:
|
||||
from tiramisu3 import *
|
||||
except:
|
||||
from tiramisu import *
|
||||
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||
option_4 = StrOption(name="activer_ejabberd", doc="No change", default="non", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||
option_2 = OptionDescription(name="general", doc="général", children=[option_3, option_4], properties=frozenset({"normal"}))
|
||||
option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2])
|
||||
option_6 = StrOption(name="extra", doc="extra", properties=frozenset({"normal"}))
|
||||
option_5 = OptionDescription(name="extra", doc="extra", children=[option_6])
|
||||
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_5])
|
12
tests/dictionaries/80family_unique/00-base.xml
Normal file
12
tests/dictionaries/80family_unique/00-base.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail>
|
||||
<variables>
|
||||
<family name="general">
|
||||
<family name="general">
|
||||
<variable name="my_variable"/>
|
||||
</family>
|
||||
</family>
|
||||
</variables>
|
||||
</rougail>
|
||||
<!-- vim: ts=4 sw=4 expandtab
|
||||
-->
|
0
tests/dictionaries/80family_unique/__init__.py
Normal file
0
tests/dictionaries/80family_unique/__init__.py
Normal file
0
tests/dictionaries/80family_unique/errno_55
Normal file
0
tests/dictionaries/80family_unique/errno_55
Normal file
8
tests/dictionaries/80variable_extra/00-base.xml
Normal file
8
tests/dictionaries/80variable_extra/00-base.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail>
|
||||
<variables>
|
||||
<variable name="extra"/>
|
||||
</variables>
|
||||
</rougail>
|
||||
<!-- vim: ts=4 sw=4 expandtab
|
||||
-->
|
0
tests/dictionaries/80variable_extra/__init__.py
Normal file
0
tests/dictionaries/80variable_extra/__init__.py
Normal file
0
tests/dictionaries/80variable_extra/errno_54
Normal file
0
tests/dictionaries/80variable_extra/errno_54
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<rougail>
|
||||
<variables>
|
||||
<variable name="day"/>
|
||||
</variables>
|
||||
</rougail>
|
8
tests/dictionaries/80variable_rougail/00-base.xml
Normal file
8
tests/dictionaries/80variable_rougail/00-base.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<rougail>
|
||||
<variables>
|
||||
<variable name="rougail"/>
|
||||
</variables>
|
||||
</rougail>
|
||||
<!-- vim: ts=4 sw=4 expandtab
|
||||
-->
|
0
tests/dictionaries/80variable_rougail/__init__.py
Normal file
0
tests/dictionaries/80variable_rougail/__init__.py
Normal file
0
tests/dictionaries/80variable_rougail/errno_54
Normal file
0
tests/dictionaries/80variable_rougail/errno_54
Normal file
Loading…
Reference in New Issue
Block a user