216 lines
5.6 KiB
Python
216 lines
5.6 KiB
Python
import os
|
|
from enum import Enum
|
|
from typing import Any
|
|
from json import JSONEncoder
|
|
|
|
from osdk.jexpr import Json
|
|
from osdk.logger import Logger
|
|
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]}"
|
|
|
|
def patch(self, toolSpec: str, args: list[str]):
|
|
self.tools[toolSpec].args += args
|
|
|
|
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():
|
|
if not k in target.props:
|
|
logger.log(
|
|
f"Component {self.id} disabled by missing {k} in target")
|
|
return False
|
|
|
|
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):
|
|
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)
|