Inject tools from components.
This commit is contained in:
parent
6c8fdb8521
commit
09d8b65cfe
|
@ -39,7 +39,7 @@ def gen(out: TextIO, context: Context):
|
|||
writer.separator("Components")
|
||||
|
||||
for instance in context.instances:
|
||||
objects = instance.objsfiles()
|
||||
objects = instance.objsfiles(context)
|
||||
writer.comment(f"Component: {instance.manifest.id}")
|
||||
writer.comment(f"Resolved: {', '.join(instance.resolved)}")
|
||||
|
||||
|
@ -53,7 +53,7 @@ def gen(out: TextIO, context: Context):
|
|||
writer.newline()
|
||||
|
||||
if instance.isLib():
|
||||
writer.build(instance.libfile(), "ar",
|
||||
writer.build(instance.libfile(context), "ar",
|
||||
list(map(lambda o: o[1], objects)))
|
||||
else:
|
||||
libraries: list[str] = []
|
||||
|
@ -67,9 +67,9 @@ def gen(out: TextIO, context: Context):
|
|||
if not reqInstance.isLib():
|
||||
raise Exception(f"Component {req} is not a library")
|
||||
|
||||
libraries.append(reqInstance.outfile())
|
||||
libraries.append(reqInstance.outfile(context))
|
||||
|
||||
writer.build(instance.binfile(), "ld",
|
||||
writer.build(instance.binfile(context), "ld",
|
||||
list(map(lambda o: o[1], objects)) + libraries)
|
||||
|
||||
writer.newline()
|
||||
|
@ -79,32 +79,47 @@ def build(componentSpec: str, targetSpec: str, props: Props = {}) -> str:
|
|||
context = contextFor(targetSpec, props)
|
||||
target = context.target
|
||||
|
||||
shell.mkdir(target.builddir())
|
||||
ninjaPath = f"{target.builddir()}/build.ninja"
|
||||
shell.mkdir(context.builddir())
|
||||
ninjaPath = f"{context.builddir()}/build.ninja"
|
||||
|
||||
with open(ninjaPath, "w") as f:
|
||||
gen(f, context)
|
||||
|
||||
component = context.componentByName(componentSpec)
|
||||
instance = context.componentByName(componentSpec)
|
||||
|
||||
if component is None:
|
||||
if instance is None:
|
||||
raise Exception(f"Component {componentSpec} not found")
|
||||
|
||||
shell.exec(f"ninja", "-v", "-f", ninjaPath, component.outfile())
|
||||
shell.exec(f"ninja", "-v", "-f", ninjaPath, instance.outfile(context))
|
||||
|
||||
return component.outfile()
|
||||
return instance.outfile(context)
|
||||
|
||||
|
||||
def buildAll(targetSpec: str, props: Props = {}) -> str:
|
||||
class Paths:
|
||||
bin: str
|
||||
lib: str
|
||||
obj: str
|
||||
|
||||
def __init__(self, bin: str, lib: str, obj: str):
|
||||
self.bin = bin
|
||||
self.lib = lib
|
||||
self.obj = obj
|
||||
|
||||
|
||||
def buildAll(targetSpec: str, props: Props = {}) -> Paths:
|
||||
context = contextFor(targetSpec, props)
|
||||
target = context.target
|
||||
|
||||
shell.mkdir(target.builddir())
|
||||
ninjaPath = f"{target.builddir()}/build.ninja"
|
||||
shell.mkdir(context.builddir())
|
||||
ninjaPath = f"{context.builddir()}/build.ninja"
|
||||
|
||||
with open(ninjaPath, "w") as f:
|
||||
gen(f, context)
|
||||
|
||||
shell.exec(f"ninja", "-v", "-f", ninjaPath)
|
||||
|
||||
return target.builddir()
|
||||
return Paths(
|
||||
context.builddir() + "/bin",
|
||||
context.builddir() + "/lib",
|
||||
context.builddir() + "/obj",
|
||||
)
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
from typing import cast
|
||||
from typing import cast, Protocol
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
from osdk.model import TargetManifest, ComponentManifest, Props, Type
|
||||
from osdk.model import TargetManifest, ComponentManifest, Props, Type, Tool
|
||||
from osdk.logger import Logger
|
||||
from osdk import const, shell, jexpr, utils
|
||||
from osdk import const, shell, jexpr, utils, rules
|
||||
|
||||
logger = Logger("context")
|
||||
|
||||
|
||||
class IContext(Protocol):
|
||||
def builddir(self) -> str:
|
||||
...
|
||||
|
||||
|
||||
class ComponentInstance:
|
||||
target: TargetManifest
|
||||
manifest: ComponentManifest
|
||||
sources: list[str] = []
|
||||
resolved: list[str] = []
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
target: TargetManifest,
|
||||
manifest: ComponentManifest,
|
||||
sources: list[str],
|
||||
resolved: list[str]):
|
||||
self.target = target
|
||||
self.manifest = manifest
|
||||
self.sources = sources
|
||||
self.resolved = resolved
|
||||
|
@ -29,26 +31,27 @@ class ComponentInstance:
|
|||
def isLib(self):
|
||||
return self.manifest.type == Type.LIB
|
||||
|
||||
def binfile(self) -> str:
|
||||
return f"{self.target.builddir()}/bin/{self.manifest.id}.out"
|
||||
def binfile(self, context: IContext) -> str:
|
||||
return f"{context.builddir()}/bin/{self.manifest.id}.out"
|
||||
|
||||
def objdir(self) -> str:
|
||||
return f"{self.target.builddir()}/obj/{self.manifest.id}"
|
||||
def objdir(self, context: IContext) -> str:
|
||||
return f"{context.builddir()}/obj/{self.manifest.id}"
|
||||
|
||||
def objsfiles(self) -> list[tuple[str, str]]:
|
||||
def objsfiles(self, context: IContext) -> list[tuple[str, str]]:
|
||||
return list(
|
||||
map(
|
||||
lambda s: (
|
||||
s, f"{self.objdir()}/{s.replace(self.manifest.dirname() + '/', '')}.o"),
|
||||
s, f"{self.objdir(context)}/{s.replace(self.manifest.dirname() + '/', '')}.o"),
|
||||
self.sources))
|
||||
|
||||
def libfile(self) -> str:
|
||||
return f"{self.target.builddir()}/lib/{self.manifest.id}.a"
|
||||
def libfile(self, context: IContext) -> str:
|
||||
return f"{context.builddir()}/lib/{self.manifest.id}.a"
|
||||
|
||||
def outfile(self) -> str:
|
||||
def outfile(self, context: IContext) -> str:
|
||||
if self.isLib():
|
||||
return self.libfile()
|
||||
return self.binfile()
|
||||
return self.libfile(context)
|
||||
else:
|
||||
return self.binfile(context)
|
||||
|
||||
def cinclude(self) -> str:
|
||||
if "cpp-root-include" in self.manifest.props:
|
||||
|
@ -57,13 +60,15 @@ class ComponentInstance:
|
|||
return str(Path(self.manifest.dirname()).parent)
|
||||
|
||||
|
||||
class Context:
|
||||
class Context(IContext):
|
||||
target: TargetManifest
|
||||
instances: list[ComponentInstance] = []
|
||||
instances: list[ComponentInstance]
|
||||
tools: dict[str, Tool]
|
||||
|
||||
def __init__(self, target: TargetManifest, instances: list[ComponentInstance]):
|
||||
def __init__(self, target: TargetManifest, instances: list[ComponentInstance], tools: dict[str, Tool]):
|
||||
self.target = target
|
||||
self.instances = instances
|
||||
self.tools = tools
|
||||
|
||||
def componentByName(self, name: str) -> ComponentInstance | None:
|
||||
result = list(filter(lambda x: x.manifest.id == name, self.instances))
|
||||
|
@ -79,8 +84,11 @@ class Context:
|
|||
def cdefs(self) -> list[str]:
|
||||
return self.target.cdefs()
|
||||
|
||||
def hashid(self) -> str:
|
||||
return utils.hash((self.target.props, str(self.tools)))[0:8]
|
||||
|
||||
def builddir(self) -> str:
|
||||
return self.target.builddir()
|
||||
return f"{const.BUILD_DIR}/{self.target.id}-{self.hashid()[:8]}"
|
||||
|
||||
|
||||
def loadAllTargets() -> list[TargetManifest]:
|
||||
|
@ -172,7 +180,7 @@ def instanciate(componentSpec: str, components: list[ComponentManifest], target:
|
|||
if not enabled:
|
||||
return None
|
||||
|
||||
return ComponentInstance(target, manifest, sources, resolved[1:])
|
||||
return ComponentInstance(manifest, sources, resolved[1:])
|
||||
|
||||
|
||||
def contextFor(targetSpec: str, props: Props) -> Context:
|
||||
|
@ -180,6 +188,24 @@ def contextFor(targetSpec: str, props: Props) -> Context:
|
|||
|
||||
target = loadTarget(targetSpec)
|
||||
components = loadAllComponents()
|
||||
tools: dict[str, Tool] = {}
|
||||
|
||||
for toolSpec in target.tools:
|
||||
tool = target.tools[toolSpec]
|
||||
|
||||
tools[toolSpec] = Tool(
|
||||
strict=False,
|
||||
cmd=tool.cmd,
|
||||
args=tool.args,
|
||||
files=tool.files)
|
||||
|
||||
tools[toolSpec].args += rules.rules[toolSpec].args
|
||||
|
||||
for component in components:
|
||||
for toolSpec in component.tools:
|
||||
tool = component.tools[toolSpec]
|
||||
|
||||
tools[toolSpec].args += tool.args
|
||||
|
||||
components = filterDisabled(components, target)
|
||||
instances = cast(list[ComponentInstance], list(filter(lambda e: e != None, map(lambda c: instanciate(
|
||||
|
@ -187,5 +213,6 @@ def contextFor(targetSpec: str, props: Props) -> Context:
|
|||
|
||||
return Context(
|
||||
target,
|
||||
instances
|
||||
instances,
|
||||
tools,
|
||||
)
|
||||
|
|
180
osdk/model.py
180
osdk/model.py
|
@ -14,28 +14,35 @@ Props = dict[str, Any]
|
|||
|
||||
|
||||
class Type(Enum):
|
||||
UNKNOWN = "unknown"
|
||||
TARGET = "target"
|
||||
LIB = "lib"
|
||||
EXE = "exe"
|
||||
|
||||
|
||||
class Manifest:
|
||||
id: str
|
||||
type: Type
|
||||
id: str = ""
|
||||
type: Type = Type.UNKNOWN
|
||||
path: str = ""
|
||||
|
||||
def __init__(self, json: Json, path: str):
|
||||
if not "id" in json:
|
||||
raise ValueError("Missing id")
|
||||
def __init__(self, json: Json = None, path: str = "", strict=True, **kwargs):
|
||||
if json is not None:
|
||||
if not "id" in json:
|
||||
raise ValueError("Missing id")
|
||||
|
||||
self.id = json["id"]
|
||||
self.id = json["id"]
|
||||
|
||||
if not "type" in json:
|
||||
raise ValueError("Missing type")
|
||||
if not "type" in json and strict:
|
||||
raise ValueError("Missing type")
|
||||
|
||||
self.type = Type(json["type"])
|
||||
self.type = Type(json["type"])
|
||||
|
||||
self.path = path
|
||||
self.path = path
|
||||
elif strict:
|
||||
raise ValueError("Missing json")
|
||||
|
||||
for key in kwargs:
|
||||
setattr(self, key, kwargs[key])
|
||||
|
||||
def __str__(self):
|
||||
return f"Manifest(id={self.id}, type={self.type}, path={self.path})"
|
||||
|
@ -48,23 +55,34 @@ class Manifest:
|
|||
|
||||
|
||||
class Tool:
|
||||
cmd: str
|
||||
args: list[str]
|
||||
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"]
|
||||
def __init__(self, json: Json = None, strict=True, **kwargs):
|
||||
if json is not None:
|
||||
if not "cmd" in json and strict:
|
||||
raise ValueError("Missing cmd")
|
||||
|
||||
if not "args" in json:
|
||||
raise ValueError("Missing args")
|
||||
self.args = json["args"]
|
||||
self.cmd = json.get("cmd", self.cmd)
|
||||
|
||||
self.files = json.get("files", [])
|
||||
if not "args" in json and strict:
|
||||
raise ValueError("Missing args")
|
||||
|
||||
self.args = json.get("args", [])
|
||||
|
||||
self.files = json.get("files", [])
|
||||
elif strict:
|
||||
raise ValueError("Missing json")
|
||||
|
||||
for key in kwargs:
|
||||
setattr(self, key, kwargs[key])
|
||||
|
||||
def __str__(self):
|
||||
return f"Tool(cmd={self.cmd}, args={self.args})"
|
||||
return f"Tool(cmd={self.cmd}, args={self.args}, files={self.files})"
|
||||
|
||||
def __repr__(self):
|
||||
return f"Tool({self.cmd})"
|
||||
|
||||
|
||||
class TargetManifest(Manifest):
|
||||
|
@ -72,29 +90,21 @@ class TargetManifest(Manifest):
|
|||
tools: dict[str, Tool]
|
||||
routing: dict[str, str]
|
||||
|
||||
def __init__(self, json: Json, path: str):
|
||||
super().__init__(json, path)
|
||||
def __init__(self, json: Json = None, path: str = "", strict=True, **kwargs):
|
||||
if json is not None:
|
||||
if not "props" in json and strict:
|
||||
raise ValueError("Missing props")
|
||||
|
||||
if not "props" in json:
|
||||
raise ValueError("Missing props")
|
||||
self.props = json["props"]
|
||||
|
||||
self.props = json["props"]
|
||||
if not "tools" in json and strict:
|
||||
raise ValueError("Missing tools")
|
||||
|
||||
if not "tools" in json:
|
||||
raise ValueError("Missing tools")
|
||||
self.tools = {k: Tool(v) for k, v in json["tools"].items()}
|
||||
|
||||
self.tools = {k: Tool(v) for k, v in json["tools"].items()}
|
||||
self.routing = json.get("routing", {})
|
||||
|
||||
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}" + \
|
||||
")"
|
||||
super().__init__(json, path, strict, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"TargetManifest({self.id})"
|
||||
|
@ -102,15 +112,6 @@ class TargetManifest(Manifest):
|
|||
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] = []
|
||||
|
||||
|
@ -128,31 +129,24 @@ class TargetManifest(Manifest):
|
|||
|
||||
|
||||
class ComponentManifest(Manifest):
|
||||
decription: str
|
||||
props: Props
|
||||
enableIf: dict[str, list[Any]]
|
||||
requires: list[str]
|
||||
provides: list[str]
|
||||
decription: str = "(No description)"
|
||||
props: Props = {}
|
||||
tools: dict[str, Tool] = {}
|
||||
enableIf: dict[str, list[Any]] = {}
|
||||
requires: list[str] = []
|
||||
provides: list[str] = []
|
||||
|
||||
def __init__(self, json: Json, path: str):
|
||||
super().__init__(json, path)
|
||||
def __init__(self, json: Json = None, path: str = "", strict=True, **kwargs):
|
||||
if json is not None:
|
||||
self.decription = json.get("description", self.decription)
|
||||
self.props = json.get("props", self.props)
|
||||
self.tools = {k: Tool(v, strict=False)
|
||||
for k, v in json.get("tools", {}).items()}
|
||||
self.enableIf = json.get("enableIf", self.enableIf)
|
||||
self.requires = json.get("requires", self.requires)
|
||||
self.provides = json.get("provides", self.provides)
|
||||
|
||||
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})"
|
||||
super().__init__(json, path, strict, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"ComponentManifest({self.id})"
|
||||
|
@ -170,47 +164,3 @@ class ComponentManifest(Manifest):
|
|||
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)
|
||||
|
|
Loading…
Reference in a new issue