diff --git a/kiwi_scp/_constants.py b/kiwi_scp/_constants.py index cd12c09..62a46f9 100644 --- a/kiwi_scp/_constants.py +++ b/kiwi_scp/_constants.py @@ -1,6 +1,18 @@ # system import os +############# +# REGEX PARTS + +# regex part for a number with no leading zeroes +_RE_NUMBER: str = r"[0-9]|[1-9][0-9]*" + +# regex for a semantic version string +RE_SEMVER = rf"^{_RE_NUMBER}(?:\.{_RE_NUMBER}(?:\.{_RE_NUMBER})?)?$" + +# regex for a lowercase variable name +RE_VARNAME = r"^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])$" + ############# # ENVIRONMENT diff --git a/kiwi_scp/config.py b/kiwi_scp/config.py index b276fa6..ea5ba12 100644 --- a/kiwi_scp/config.py +++ b/kiwi_scp/config.py @@ -1,48 +1,67 @@ -import re +from ipaddress import IPv4Network +from pathlib import Path from typing import Optional, Dict, List import pydantic +from ._constants import RE_SEMVER, RE_VARNAME + class _Storage(pydantic.BaseModel): """a storage subsection""" - directory: str + directory: Path class _Project(pydantic.BaseModel): """a project subsection""" - name: str + name: pydantic.constr( + regex=RE_VARNAME + ) enabled: bool = True - storage: Optional[_Storage] + override_storage: Optional[_Storage] @pydantic.root_validator(pre=True) @classmethod - def check_grammar(cls, values): - if isinstance(values, dict): - if "name" in values: - return values + def unify_project(cls, values): + """parse different project notations""" - elif len(values) == 1: - name, enabled = list(values.items())[0] - return {"name": name, "enabled": True if enabled is None else enabled} + if "name" in values: + # default format + return values - elif isinstance(values, str): - return {"name": values} + elif len(values) == 1: + # short format: + # - : + + name, enabled = list(values.items())[0] + return { + "name": name, + "enabled": True if enabled is None else enabled + } + + else: + # undefined format + raise ValueError class _Network(pydantic.BaseModel): """a network subsection""" - name: str - cidr: str + name: pydantic.constr( + to_lower=True, + regex=RE_VARNAME + ) + cidr: IPv4Network class Config(pydantic.BaseModel): """represents a kiwi.yml""" - version: str + version: pydantic.constr( + regex=RE_SEMVER + ) shells: Optional[List[str]] environment: Optional[Dict[str, Optional[str]]] @@ -50,30 +69,51 @@ class Config(pydantic.BaseModel): storage: _Storage network: _Network - @pydantic.validator("version") - @classmethod - def check_version(cls, value: str) -> str: - if not re.match(r"^[0-9]+(\.[0-9]+(\.[0-9]+)?)?$", value): - raise ValueError - - return value - @pydantic.validator("environment", pre=True) @classmethod - def unify_env(cls, value) -> Optional[Dict[str, Optional[str]]]: - if isinstance(value, dict): + def unify_environment(cls, value) -> Optional[Dict[str, Optional[str]]]: + """parse different environment notations""" + + def parse_str(var_val: str) -> (str, Optional[str]): + """parse a "=" string""" + + idx = var_val.find("=") + if idx == -1: + # don't split, just define the variable + return var_val, None + else: + # split string, set variable to value + return var_val[:idx], var_val[idx + 1:] + + if value is None: + # empty environment + return None + + elif isinstance(value, dict): + # native dict format return value + elif isinstance(value, list): + # list format (multiple strings) + result: Dict[str, Optional[str]] = {} for item in value: - idx = item.find("=") - if idx == -1: - key, value = item, None - else: - key, value = item[:idx], item[idx + 1:] - + key, value = parse_str(item) result[key] = value return result + + elif isinstance(value, str): + # string format (single variable): + # "=" + + key, value = parse_str(value) + return {key: value} + + elif isinstance(value, int): + # integer format (just define single oddly named variable) + return {str(value): None} + else: - return None + # undefined format + raise ValueError diff --git a/kiwi_scp/data/etc/kiwi_default.yml b/kiwi_scp/data/etc/kiwi_default.yml index 44766a7..bb8335f 100644 --- a/kiwi_scp/data/etc/kiwi_default.yml +++ b/kiwi_scp/data/etc/kiwi_default.yml @@ -4,7 +4,7 @@ shells: projects: - name: admin enabled: true - - test: + - Test: - test2: false storage: directory: /var/local/kiwi