cutekit/osdk/model.py

217 lines
5.6 KiB
Python
Raw Normal View History

import os
from enum import Enum
from typing import Any
from json import JSONEncoder
2023-02-06 10:14:32 +00:00
from osdk.jexpr import Json
from osdk.logger import Logger
2023-02-06 10:14:32 +00:00
from osdk import const, utils
logger = Logger("model")
Props = dict[str, Any]
class Type(Enum):
TARGET = "target"
LIB = "lib"
EXE = "exe"
class Manifest:
id: str
type: Type
path: str = ""
def __init__(self, json: Json, path: str):
if not "id" in json:
raise ValueError("Missing id")
self.id = json["id"]
if not "type" in json:
raise ValueError("Missing type")
self.type = Type(json["type"])
self.path = path
def __str__(self):
return f"Manifest(id={self.id}, type={self.type}, path={self.path})"
def __repr__(self):
return f"Manifest({id})"
def dirname(self) -> str:
return os.path.dirname(self.path)
class Tool:
cmd: str
args: list[str]
files: list[str] = []
def __init__(self, json: Json):
if not "cmd" in json:
raise ValueError("Missing cmd")
self.cmd = json["cmd"]
if not "args" in json:
raise ValueError("Missing args")
self.args = json["args"]
self.files = json.get("files", [])
def __str__(self):
return f"Tool(cmd={self.cmd}, args={self.args})"
class TargetManifest(Manifest):
props: Props
tools: dict[str, Tool]
routing: dict[str, str]
def __init__(self, json: Json, path: str):
super().__init__(json, path)
if not "props" in json:
raise ValueError("Missing props")
self.props = json["props"]
if not "tools" in json:
raise ValueError("Missing tools")
self.tools = {k: Tool(v) for k, v in json["tools"].items()}
self.routing = json.get("routing", {})
def __str__(self):
return f"TargetManifest(" + \
"id={self.id}, " + \
"type={self.type}, " + \
"props={self.props}, " + \
"tools={self.tools}, " + \
"path={self.path}" + \
")"
def __repr__(self):
return f"TargetManifest({self.id})"
def route(self, componentSpec: str):
return self.routing[componentSpec] if componentSpec in self.routing else componentSpec
def hashid(self) -> str:
return utils.hash((self.props, self.tools), cls=ModelEncoder)
def builddir(self) -> str:
return f"{const.BUILD_DIR}/{self.id}-{self.hashid()[:8]}"
2023-02-02 22:05:45 +00:00
def patch(self, toolSpec: str, args: list[str]):
self.tools[toolSpec].args += args
2023-02-06 10:14:32 +00:00
def cdefs(self) -> list[str]:
defines: list[str] = []
for key in self.props:
macroname = key.lower().replace("-", "_")
prop = self.props[key]
macrovalue = str(prop).lower().replace(" ", "_").replace("-", "_")
if isinstance(prop, bool):
if prop:
defines += [f"-D__osdk_{macroname}__"]
else:
defines += [f"-D__osdk_{macroname}_{macrovalue}__"]
return defines
class ComponentManifest(Manifest):
decription: str
props: Props
enableIf: dict[str, list[Any]]
requires: list[str]
provides: list[str]
def __init__(self, json: Json, path: str):
super().__init__(json, path)
self.decription = json.get("description", "(No description)")
self.props = json.get("props", {})
self.enableIf = json.get("enableIf", {})
self.requires = json.get("requires", [])
self.provides = json.get("provides", [])
def __str__(self):
return f"ComponentManifest(" + \
"id={self.id}, " + \
"type={self.type}, " + \
"description={self.decription}, " + \
"requires={self.requires}, " + \
"provides={self.provides}, " + \
"injects={self.injects}, " + \
"deps={self.deps}, " + \
"path={self.path})"
def __repr__(self):
return f"ComponentManifest({self.id})"
def isEnabled(self, target: TargetManifest):
for k, v in self.enableIf.items():
2023-01-31 20:09:28 +00:00
if not k in target.props:
logger.log(
f"Component {self.id} disabled by missing {k} in target")
return False
2023-01-31 20:09:28 +00:00
if not target.props[k] in v:
logger.log(
f"Component {self.id} disabled by {k}={target.props[k]} not in {v}")
return False
return True
class ModelEncoder(JSONEncoder):
2023-02-06 10:14:32 +00:00
def default(self, o: Any):
if isinstance(o, Manifest):
return {
"id": o.id,
"type": o.type.value,
"path": o.path
}
if isinstance(o, Type):
return o.value
if isinstance(o, Tool):
return {
"cmd": o.cmd,
"args": o.args,
"files": o.files
}
if isinstance(o, TargetManifest):
return {
"id": o.id,
"type": o.type.value,
"props": o.props,
"tools": o.tools,
"routing": o.routing,
"path": o.path
}
if isinstance(o, ComponentManifest):
return {
"id": o.id,
"type": o.type.value,
"description": o.decription,
"props": o.props,
"enableIf": o.enableIf,
"requires": o.requires,
"provides": o.provides,
"path": o.path
}
return super().default(o)