|
@@ -7,114 +7,7 @@ from metadocker.cmdline.base import ArgsFromFile
|
|
from metadocker.common.errors import MetadockerError
|
|
from metadocker.common.errors import MetadockerError
|
|
from metadocker.common.misc import get_root_dir
|
|
from metadocker.common.misc import get_root_dir
|
|
from metadocker.docker import DockerBuilder
|
|
from metadocker.docker import DockerBuilder
|
|
-
|
|
|
|
-NoneType=None.__class__
|
|
|
|
-
|
|
|
|
-def get_types(x):
|
|
|
|
- if x is None:
|
|
|
|
- return tuple()
|
|
|
|
- if not isinstance(x, (list, tuple, set)):
|
|
|
|
- return (x,)
|
|
|
|
- return x
|
|
|
|
-
|
|
|
|
-class Var:
|
|
|
|
-
|
|
|
|
- class VarException(MetadockerError):
|
|
|
|
- def get_error(self):
|
|
|
|
- raise NotImplementedError()
|
|
|
|
-
|
|
|
|
- class RequiredException(VarException):
|
|
|
|
- def __init__(self, name):
|
|
|
|
- super().__init__(name)
|
|
|
|
- self.name = name
|
|
|
|
-
|
|
|
|
- def get_error(self):
|
|
|
|
- return f"La variable {self.name} est requise"
|
|
|
|
-
|
|
|
|
- class ValidationException(VarException):
|
|
|
|
- def __init__(self, name, err):
|
|
|
|
- super().__init__(name, err)
|
|
|
|
- self.name = name
|
|
|
|
- self.err = err
|
|
|
|
-
|
|
|
|
- def get_error(self):
|
|
|
|
- return f"La variable {self.name} est invalide : {self.err}"
|
|
|
|
-
|
|
|
|
- class TypeException(VarException):
|
|
|
|
- def __init__(self, name, types, found):
|
|
|
|
- super().__init__(name, types)
|
|
|
|
- self.name = name
|
|
|
|
-
|
|
|
|
- if isinstance(types, type):
|
|
|
|
- types = [types]
|
|
|
|
- types = [x.__name__ for x in types]
|
|
|
|
- self.types = tuple(types)
|
|
|
|
- self.found = found
|
|
|
|
-
|
|
|
|
- def get_error(self):
|
|
|
|
- return f"La variable {self.name} doit être de type {'('+', '.join(self.types)+')'}. Type trouvé {self.found.__class__.__name__}"
|
|
|
|
-
|
|
|
|
- def __init__(self, name, default_value=None, required=False, validate=None,
|
|
|
|
- expected_types=None, help=None, is_meta=False, null=False):
|
|
|
|
- self.name = name
|
|
|
|
- self.default_value = default_value
|
|
|
|
- self.required = required
|
|
|
|
- self._validate = validate if validate else lambda x: x
|
|
|
|
- self.expected_types = expected_types
|
|
|
|
- self.help = help
|
|
|
|
- self.null = null
|
|
|
|
- self.is_meta = is_meta
|
|
|
|
-
|
|
|
|
- def validate(self, obj):
|
|
|
|
- if not hasattr(obj, self.name):
|
|
|
|
- if self.required:
|
|
|
|
- raise self.RequiredException(self.name)
|
|
|
|
- return self.default_value
|
|
|
|
- data = getattr(obj, self.name)
|
|
|
|
- if self.expected_types:
|
|
|
|
- if data is None and self.null:
|
|
|
|
- pass
|
|
|
|
- elif not isinstance(data, self.expected_types):
|
|
|
|
- raise self.TypeException(self.name, self.expected_types, data)
|
|
|
|
-
|
|
|
|
- data = self._validate(data)
|
|
|
|
-
|
|
|
|
- return data
|
|
|
|
-
|
|
|
|
- def __repr__(self):
|
|
|
|
- return f"<{self.__class__.__name__} {self.name}>"
|
|
|
|
-
|
|
|
|
-class VarStr(Var):
|
|
|
|
- def __init__(self, name, default_value=None, required=False, validate=None, help=None,
|
|
|
|
- is_meta=False, expected_types=None, null=False):
|
|
|
|
- super().__init__(name, default_value, required, validate, help=help,
|
|
|
|
- expected_types=(str, *get_types(expected_types)), is_meta=is_meta, null=null)
|
|
|
|
-
|
|
|
|
-class VarPath(Var):
|
|
|
|
- def __init__(self, name, default_value=None, required=False, validate=None, help=None,
|
|
|
|
- is_meta=False, expected_types=None, null=False):
|
|
|
|
- super().__init__(name, default_value, required, help=help, is_meta=is_meta,
|
|
|
|
- validate=validate or (lambda x: Path(x)),
|
|
|
|
- expected_types=(str, Path, *get_types(expected_types)), null=null)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-class VarInt(Var):
|
|
|
|
- def __init__(self, name, default_value=None, required=False, validate=None, help=None,
|
|
|
|
- is_meta=False, expected_types=None, null=False):
|
|
|
|
- super().__init__(name, default_value, required, validate, help=help, is_meta=is_meta,
|
|
|
|
- expected_types=(int, *get_types(expected_types)), null=null)
|
|
|
|
-
|
|
|
|
-class VarNumber(Var):
|
|
|
|
- def __init__(self, name, default_value=None, required=False, validate=None, help=None,
|
|
|
|
- is_meta=False, expected_types=None, null=False):
|
|
|
|
- super().__init__(name, default_value, required, validate, help=help, is_meta=is_meta,
|
|
|
|
- expected_types=(float, int, *get_types(expected_types)), null=null)
|
|
|
|
-
|
|
|
|
-class VarDict(Var):
|
|
|
|
- def __init__(self, name, default_value=None, required=False, validate=None, help=None,
|
|
|
|
- is_meta=False, expected_types=None, null=False):
|
|
|
|
- super().__init__(name, default_value, required, validate, help=help, is_meta=is_meta,
|
|
|
|
- expected_types=(dict, *get_types(expected_types)), null=null)
|
|
|
|
|
|
+from metadocker.env.var import VarDict, VarStr, VarPath, NotEmpty, Var, EmptyValue
|
|
|
|
|
|
|
|
|
|
class EnvHolder:
|
|
class EnvHolder:
|
|
@@ -139,8 +32,40 @@ class EnvHolder:
|
|
|
|
|
|
class Env:
|
|
class Env:
|
|
_current_env = None
|
|
_current_env = None
|
|
- _vars_ = []
|
|
|
|
|
|
+
|
|
|
|
+ PROJECT : str
|
|
|
|
+ PROJECT_VERSION : str
|
|
|
|
+ DOCKER_TAG : str
|
|
|
|
+ DOCKER_NAME : str
|
|
|
|
+ ENV : dict
|
|
|
|
+ PORTS : dict
|
|
|
|
+ VOLUMES : dict
|
|
|
|
+ COPY : dict
|
|
|
|
+ APP_DIR : Path
|
|
|
|
+
|
|
|
|
+ _vars_ = [
|
|
|
|
+ VarStr("PROJECT", required=True, help="Le nom du projet", is_meta=True, ask=True),
|
|
|
|
+ VarStr("PROJECT_VERSION", None, help="La version du projet", validate=NotEmpty,
|
|
|
|
+ is_meta=True, null=True, ask=True),
|
|
|
|
+ VarStr("DOCKER_TAG", None, is_meta=True, validate=NotEmpty,
|
|
|
|
+ help="Nom du tag de l'image docker. Par défaut: {env.PROJECT.lower()}-{PROJECT_VERSION}", ask=True),
|
|
|
|
+
|
|
|
|
+ VarStr("DOCKER_NAME", None, is_meta=True, validate=NotEmpty,
|
|
|
|
+ help="Nom du conteneur docker. Par défaut {env.PROJECT.lower()}", ask=True),
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ VarDict("ENV", {}, required=True, help="La liste des variable d'environnemnt à utiliser"),
|
|
|
|
+ VarDict("PORTS", {8101: 8000}, required=True,
|
|
|
|
+ help="Le mapping des ports. En clé les ports de l'hote et en valeur les port du container"),
|
|
|
|
+ VarDict("VOLUMES", {"./data": "/data"}, required=True,
|
|
|
|
+ help="Le mapping des ports. En clé les ports de l'hote et en valeur les port du container",
|
|
|
|
+ is_meta=True, null=True),
|
|
|
|
+ VarDict("COPY", {}, required=True, help="Dictionaire des fichier a copier: cle: fs hote valeur fs invite"),
|
|
|
|
+ VarPath("APP_DIR", "/data/data", required=True, help="Le dossier ou est lancé le projet", ask=True),
|
|
|
|
+
|
|
|
|
+ ]
|
|
_name_ = None
|
|
_name_ = None
|
|
|
|
+ _alias_ = []
|
|
|
|
|
|
|
|
|
|
class EnvException(MetadockerError):
|
|
class EnvException(MetadockerError):
|
|
@@ -156,19 +81,35 @@ class Env:
|
|
Env._current_env = self
|
|
Env._current_env = self
|
|
self.root = get_root_dir()
|
|
self.root = get_root_dir()
|
|
self.debug = debug
|
|
self.debug = debug
|
|
|
|
+ self.meta = None
|
|
|
|
+ self.docker : DockerBuilder
|
|
|
|
+ self.env = None
|
|
for k, v in kwargs.items():
|
|
for k, v in kwargs.items():
|
|
setattr(self, k, v)
|
|
setattr(self, k, v)
|
|
|
|
|
|
- def check(self):
|
|
|
|
- self.get_env()
|
|
|
|
|
|
|
|
- def get_meta(self):
|
|
|
|
|
|
+ def init(self):
|
|
|
|
+ self.meta = self.get_meta()
|
|
|
|
+ self.docker = DockerBuilder(
|
|
|
|
+ self.meta.PROJECT,
|
|
|
|
+ self.meta.PROJECT_VERSION,
|
|
|
|
+ self.meta.DOCKER_TAG,
|
|
|
|
+ self.meta.DOCKER_NAME,
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ def read(self):
|
|
|
|
+ self.init()
|
|
|
|
+ self.env = self.get_env()
|
|
|
|
+
|
|
|
|
+ def _validate_fields(self, filter=None):
|
|
data= EnvHolder()
|
|
data= EnvHolder()
|
|
errors = []
|
|
errors = []
|
|
for var in self._vars_:
|
|
for var in self._vars_:
|
|
- if not var.is_meta: continue
|
|
|
|
|
|
+ if filter and not filter(var): continue
|
|
try:
|
|
try:
|
|
value = var.validate(self)
|
|
value = var.validate(self)
|
|
|
|
+ except Var.ByPassException:
|
|
|
|
+ value = None
|
|
except Var.VarException as err:
|
|
except Var.VarException as err:
|
|
errors.append(err)
|
|
errors.append(err)
|
|
continue
|
|
continue
|
|
@@ -179,50 +120,40 @@ class Env:
|
|
|
|
|
|
for k,v in data.items():
|
|
for k,v in data.items():
|
|
setattr(data, k, v)
|
|
setattr(data, k, v)
|
|
|
|
+ setattr(self, k, v)
|
|
return data
|
|
return data
|
|
|
|
|
|
|
|
|
|
- def get_env(self):
|
|
|
|
- data= EnvHolder()
|
|
|
|
- errors = []
|
|
|
|
- for var in self._vars_:
|
|
|
|
- try:
|
|
|
|
- value = var.validate(self)
|
|
|
|
- except Var.VarException as err:
|
|
|
|
- errors.append(err)
|
|
|
|
- continue
|
|
|
|
- data[var.name] = value
|
|
|
|
-
|
|
|
|
- if errors:
|
|
|
|
- raise self.EnvException(errors)
|
|
|
|
|
|
+ def get_meta(self):
|
|
|
|
+ return self._validate_fields(lambda x: x.is_meta)
|
|
|
|
|
|
- for k,v in data.items():
|
|
|
|
- setattr(data, k, v)
|
|
|
|
- return data
|
|
|
|
|
|
+ def get_env(self):
|
|
|
|
+ return self._validate_fields()
|
|
|
|
|
|
- def generate_docker_file(self, docker : DockerBuilder, ):
|
|
|
|
|
|
+ def generate_docker_file(self ):
|
|
raise NotImplementedError()
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
- def init(self, docker : DockerBuilder):
|
|
|
|
- raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
+ def build_docker_file(self, output=None):
|
|
|
|
|
|
- def build_docker_file(self, docker : DockerBuilder, output=None):
|
|
|
|
- self.init(docker)
|
|
|
|
if not output:
|
|
if not output:
|
|
temp = tempfile.TemporaryDirectory()
|
|
temp = tempfile.TemporaryDirectory()
|
|
output = Path(temp.name) / "Dockerfile"
|
|
output = Path(temp.name) / "Dockerfile"
|
|
output = Path(output)
|
|
output = Path(output)
|
|
output.parent.mkdir(exist_ok=True, parents=True)
|
|
output.parent.mkdir(exist_ok=True, parents=True)
|
|
|
|
|
|
- self.generate_docker_file(docker)
|
|
|
|
- output.write_text(docker.get_file_content())
|
|
|
|
|
|
+ self.generate_docker_file()
|
|
|
|
+ output.write_text(self.docker.get_file_content())
|
|
|
|
|
|
- def create_empty_config(self):
|
|
|
|
- def _value(v):
|
|
|
|
|
|
+ def create_empty_config(self, interractive=True):
|
|
|
|
+ def _value(v, field):
|
|
|
|
+ if v is EmptyValue:
|
|
|
|
+ return f"# type in ({', '.join([x.__name__ for x in field.expected_types] or ['*'])})"
|
|
if v is None:
|
|
if v is None:
|
|
return "None"
|
|
return "None"
|
|
|
|
+ if isinstance(v, Path):
|
|
|
|
+ v = str(v)
|
|
if isinstance(v, (str, list, int, float, dict)):
|
|
if isinstance(v, (str, list, int, float, dict)):
|
|
if v == {}: return "{\n}"
|
|
if v == {}: return "{\n}"
|
|
if v == []: return "[\n]"
|
|
if v == []: return "[\n]"
|
|
@@ -232,6 +163,9 @@ class Env:
|
|
def _help(v):
|
|
def _help(v):
|
|
return v.replace("\n", "\n#")
|
|
return v.replace("\n", "\n#")
|
|
|
|
|
|
|
|
+ if interractive:
|
|
|
|
+ self.ask_for_data()
|
|
|
|
+
|
|
data = [
|
|
data = [
|
|
"#!/bin/env python3",
|
|
"#!/bin/env python3",
|
|
f"from metadocker.env import {self.__class__.__name__}",
|
|
f"from metadocker.env import {self.__class__.__name__}",
|
|
@@ -241,15 +175,24 @@ class Env:
|
|
for var in self._vars_:
|
|
for var in self._vars_:
|
|
if var.help:
|
|
if var.help:
|
|
data.append(f"# {var.help}")
|
|
data.append(f"# {var.help}")
|
|
- if var.required:
|
|
|
|
- data.append(f"env.{var.name}={_value(var.default_value)}")
|
|
|
|
|
|
+
|
|
|
|
+ value = _value(getattr(self, var.name, var.default_value), var)
|
|
|
|
+ if var.required or var.ask:
|
|
|
|
+ data.append(f"env.{var.name}={value}")
|
|
else:
|
|
else:
|
|
- data.append(f"# env.{var.name}={_value(var.default_value)}")
|
|
|
|
|
|
+ data.append(f"# env.{var.name}={value}")
|
|
data.append("")
|
|
data.append("")
|
|
data.append("# lancement ")
|
|
data.append("# lancement ")
|
|
data.append("env.main()")
|
|
data.append("env.main()")
|
|
return "\n".join(data)
|
|
return "\n".join(data)
|
|
|
|
|
|
def main(self, args=None):
|
|
def main(self, args=None):
|
|
|
|
+ self.init()
|
|
ArgsFromFile.main(self, args)
|
|
ArgsFromFile.main(self, args)
|
|
|
|
|
|
|
|
+
|
|
|
|
+ def ask_for_data(self):
|
|
|
|
+ for var in self._vars_:
|
|
|
|
+ if var.ask:
|
|
|
|
+ value = var.ask_value()
|
|
|
|
+ setattr(self, var.name, value)
|