Use dataclasses for the model
This commit is contained in:
parent
b1415cce16
commit
8f4d19c98e
|
@ -1,3 +1,4 @@
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,10 +6,11 @@ SUPPORTED_MANIFEST = [
|
||||||
"https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
|
"https://schemas.cute.engineering/stable/cutekit.manifest.component.v1",
|
||||||
"https://schemas.cute.engineering/stable/cutekit.manifest.project.v1",
|
"https://schemas.cute.engineering/stable/cutekit.manifest.project.v1",
|
||||||
"https://schemas.cute.engineering/stable/cutekit.manifest.target.v1",
|
"https://schemas.cute.engineering/stable/cutekit.manifest.target.v1",
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
OSDK_MANIFEST_NOT_SUPPORTED = "OSDK manifests are not supported by CuteKit. Please use CuteKit manifest instead"
|
OSDK_MANIFEST_NOT_SUPPORTED = (
|
||||||
|
"OSDK manifests are not supported by CuteKit. Please use CuteKit manifest instead"
|
||||||
|
)
|
||||||
|
|
||||||
UNSUPORTED_MANIFEST = {
|
UNSUPORTED_MANIFEST = {
|
||||||
"https://schemas.cute.engineering/stable/osdk.manifest.component.v1": OSDK_MANIFEST_NOT_SUPPORTED,
|
"https://schemas.cute.engineering/stable/osdk.manifest.component.v1": OSDK_MANIFEST_NOT_SUPPORTED,
|
||||||
|
@ -20,14 +22,16 @@ UNSUPORTED_MANIFEST = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def ensureSupportedManifest(manifest: Any, path: str):
|
def ensureSupportedManifest(manifest: Any, path: Path):
|
||||||
if "$schema" not in manifest:
|
if "$schema" not in manifest:
|
||||||
raise RuntimeError(f"Missing $schema in {path}")
|
raise RuntimeError(f"Missing $schema in {path}")
|
||||||
|
|
||||||
if manifest["$schema"] in UNSUPORTED_MANIFEST:
|
if manifest["$schema"] in UNSUPORTED_MANIFEST:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"Unsupported manifest schema {manifest['$schema']} in {path}: {UNSUPORTED_MANIFEST[manifest['$schema']]}")
|
f"Unsupported manifest schema {manifest['$schema']} in {path}: {UNSUPORTED_MANIFEST[manifest['$schema']]}"
|
||||||
|
)
|
||||||
|
|
||||||
if manifest["$schema"] not in SUPPORTED_MANIFEST:
|
if manifest["$schema"] not in SUPPORTED_MANIFEST:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"Unsupported manifest schema {manifest['$schema']} in {path}")
|
f"Unsupported manifest schema {manifest['$schema']} in {path}"
|
||||||
|
)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
VERSION = (0, 5, 4)
|
VERSION = (0, 6, 0, "dev")
|
||||||
VERSION_STR = f"{VERSION[0]}.{VERSION[1]}.{VERSION[2]}{'-' + VERSION[3] if len(VERSION) >= 4 else ''}"
|
VERSION_STR = f"{VERSION[0]}.{VERSION[1]}.{VERSION[2]}{'-' + VERSION[3] if len(VERSION) >= 4 else ''}"
|
||||||
MODULE_DIR = os.path.dirname(os.path.realpath(__file__))
|
MODULE_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
ARGV0 = os.path.basename(sys.argv[0])
|
ARGV0 = os.path.basename(sys.argv[0])
|
||||||
|
|
|
@ -46,7 +46,7 @@ class ComponentInstance:
|
||||||
return self.manifest.id
|
return self.manifest.id
|
||||||
|
|
||||||
def isLib(self):
|
def isLib(self):
|
||||||
return self.manifest.type == model.Type.LIB
|
return self.manifest.type == model.Kind.LIB
|
||||||
|
|
||||||
def objdir(self) -> str:
|
def objdir(self) -> str:
|
||||||
return os.path.join(self.context.builddir(), f"{self.manifest.id}/obj")
|
return os.path.join(self.context.builddir(), f"{self.manifest.id}/obj")
|
||||||
|
@ -88,7 +88,7 @@ class ComponentInstance:
|
||||||
def cinclude(self) -> str:
|
def cinclude(self) -> str:
|
||||||
if "cpp-root-include" in self.manifest.props:
|
if "cpp-root-include" in self.manifest.props:
|
||||||
return self.manifest.dirname()
|
return self.manifest.dirname()
|
||||||
elif self.manifest.type == model.Type.LIB:
|
elif self.manifest.type == model.Kind.LIB:
|
||||||
return str(Path(self.manifest.dirname()).parent)
|
return str(Path(self.manifest.dirname()).parent)
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
@ -131,7 +131,7 @@ class Context(IContext):
|
||||||
|
|
||||||
def hashid(self) -> str:
|
def hashid(self) -> str:
|
||||||
return utils.hash(
|
return utils.hash(
|
||||||
(self.target.props, [self.tools[t].toJson() for t in self.tools])
|
(self.target.props, [self.tools[t].to_dict() for t in self.tools])
|
||||||
)[0:8]
|
)[0:8]
|
||||||
|
|
||||||
def builddir(self) -> str:
|
def builddir(self) -> str:
|
||||||
|
@ -154,14 +154,19 @@ def loadAllTargets() -> list[model.Target]:
|
||||||
ret = []
|
ret = []
|
||||||
for entry in paths:
|
for entry in paths:
|
||||||
files = shell.find(entry, ["*.json"])
|
files = shell.find(entry, ["*.json"])
|
||||||
ret += list(map(lambda path: model.Target(jexpr.evalRead(path), path), files))
|
ret += list(
|
||||||
|
map(
|
||||||
|
lambda path: model.Manifest.load(Path(path)).ensureType(model.Target),
|
||||||
|
files,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def loadProject(path: str) -> model.Project:
|
def loadProject(path: str) -> model.Project:
|
||||||
path = os.path.join(path, "project.json")
|
path = os.path.join(path, "project.json")
|
||||||
return model.Project(jexpr.evalRead(path), path)
|
return model.Manifest.load(Path(path)).ensureType(model.Project)
|
||||||
|
|
||||||
|
|
||||||
def loadTarget(id: str) -> model.Target:
|
def loadTarget(id: str) -> model.Target:
|
||||||
|
@ -175,7 +180,12 @@ def loadAllComponents() -> list[model.Component]:
|
||||||
files = shell.find(const.SRC_DIR, ["manifest.json"])
|
files = shell.find(const.SRC_DIR, ["manifest.json"])
|
||||||
files += shell.find(const.EXTERN_DIR, ["manifest.json"])
|
files += shell.find(const.EXTERN_DIR, ["manifest.json"])
|
||||||
|
|
||||||
return list(map(lambda path: model.Component(jexpr.evalRead(path), path), files))
|
return list(
|
||||||
|
map(
|
||||||
|
lambda path: model.Manifest.load(Path(path)).ensureType(model.Component),
|
||||||
|
files,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def filterDisabled(
|
def filterDisabled(
|
||||||
|
@ -242,7 +252,7 @@ def resolveDeps(
|
||||||
|
|
||||||
enabled, unresolvedReason, resolved = resolveInner(componentSpec)
|
enabled, unresolvedReason, resolved = resolveInner(componentSpec)
|
||||||
|
|
||||||
return enabled, unresolvedReason, resolved
|
return enabled, unresolvedReason, utils.uniq(resolved)
|
||||||
|
|
||||||
|
|
||||||
def instanciate(
|
def instanciate(
|
||||||
|
@ -250,7 +260,10 @@ def instanciate(
|
||||||
) -> Optional[ComponentInstance]:
|
) -> Optional[ComponentInstance]:
|
||||||
manifest = next(filter(lambda c: c.id == componentSpec, components))
|
manifest = next(filter(lambda c: c.id == componentSpec, components))
|
||||||
wildcards = set(chain(*map(lambda rule: rule.fileIn, rules.rules.values())))
|
wildcards = set(chain(*map(lambda rule: rule.fileIn, rules.rules.values())))
|
||||||
sources = shell.find(manifest.subdirs, list(wildcards), recusive=False)
|
dirs = [manifest.dirname()] + list(
|
||||||
|
map(lambda d: os.path.join(manifest.dirname(), d), manifest.subdirs)
|
||||||
|
)
|
||||||
|
sources = shell.find(dirs, list(wildcards), recusive=False)
|
||||||
|
|
||||||
res = shell.find(os.path.join(manifest.dirname(), "res"))
|
res = shell.find(os.path.join(manifest.dirname(), "res"))
|
||||||
|
|
||||||
|
@ -299,9 +312,7 @@ def contextFor(targetSpec: str, props: model.Props = {}) -> Context:
|
||||||
for toolSpec in target.tools:
|
for toolSpec in target.tools:
|
||||||
tool = target.tools[toolSpec]
|
tool = target.tools[toolSpec]
|
||||||
|
|
||||||
tools[toolSpec] = model.Tool(
|
tools[toolSpec] = model.Tool(cmd=tool.cmd, args=tool.args, files=tool.files)
|
||||||
strict=False, cmd=tool.cmd, args=tool.args, files=tool.files
|
|
||||||
)
|
|
||||||
|
|
||||||
tools[toolSpec].args += rules.rules[toolSpec].args
|
tools[toolSpec].args += rules.rules[toolSpec].args
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from typing import Any, cast, Callable, Final
|
from typing import Any, cast, Callable, Final
|
||||||
from . import shell, compat
|
from . import shell, compat
|
||||||
|
@ -9,8 +10,8 @@ Builtin = Callable[..., Json]
|
||||||
|
|
||||||
BUILTINS: Final[dict[str, Builtin]] = {
|
BUILTINS: Final[dict[str, Builtin]] = {
|
||||||
"uname": lambda arg, ctx: getattr(shell.uname(), arg).lower(),
|
"uname": lambda arg, ctx: getattr(shell.uname(), arg).lower(),
|
||||||
"include": lambda arg, ctx: evalRead(arg, compatibilityCheck=False),
|
"include": lambda arg, ctx: evalRead(arg),
|
||||||
"evalRead": lambda arg, ctx: evalRead(arg, compatibilityCheck=False),
|
"evalRead": lambda arg, ctx: evalRead(arg),
|
||||||
"join": lambda lhs, rhs, ctx: cast(
|
"join": lambda lhs, rhs, ctx: cast(
|
||||||
Json, {**lhs, **rhs} if isinstance(lhs, dict) else lhs + rhs
|
Json, {**lhs, **rhs} if isinstance(lhs, dict) else lhs + rhs
|
||||||
),
|
),
|
||||||
|
@ -27,7 +28,7 @@ BUILTINS: Final[dict[str, Builtin]] = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def eval(jexpr: Json, filePath: str) -> Json:
|
def eval(jexpr: Json, filePath: Path) -> Json:
|
||||||
if isinstance(jexpr, dict):
|
if isinstance(jexpr, dict):
|
||||||
result = {}
|
result = {}
|
||||||
for k in cast(dict[str, Json], jexpr):
|
for k in cast(dict[str, Json], jexpr):
|
||||||
|
@ -49,7 +50,7 @@ def eval(jexpr: Json, filePath: str) -> Json:
|
||||||
return jexpr
|
return jexpr
|
||||||
|
|
||||||
|
|
||||||
def read(path: str) -> Json:
|
def read(path: Path) -> Json:
|
||||||
try:
|
try:
|
||||||
with open(path, "r") as f:
|
with open(path, "r") as f:
|
||||||
return json.load(f)
|
return json.load(f)
|
||||||
|
@ -57,8 +58,6 @@ def read(path: str) -> Json:
|
||||||
raise RuntimeError(f"Failed to read {path}")
|
raise RuntimeError(f"Failed to read {path}")
|
||||||
|
|
||||||
|
|
||||||
def evalRead(path: str, compatibilityCheck: bool = True) -> Json:
|
def evalRead(path: Path) -> Json:
|
||||||
data = read(path)
|
data = read(path)
|
||||||
if compatibilityCheck:
|
|
||||||
compat.ensureSupportedManifest(data, path)
|
|
||||||
return eval(data, path)
|
return eval(data, path)
|
||||||
|
|
284
cutekit/model.py
284
cutekit/model.py
|
@ -1,18 +1,21 @@
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from enum import Enum
|
|
||||||
from typing import Any
|
|
||||||
from pathlib import Path
|
|
||||||
from . import jexpr
|
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Any, Type, cast
|
||||||
|
from pathlib import Path
|
||||||
|
from dataclasses_json import DataClassJsonMixin, config
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
from . import jexpr, compat, utils
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
Props = dict[str, Any]
|
Props = dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
class Type(Enum):
|
class Kind(Enum):
|
||||||
UNKNOWN = "unknown"
|
UNKNOWN = "unknown"
|
||||||
PROJECT = "project"
|
PROJECT = "project"
|
||||||
TARGET = "target"
|
TARGET = "target"
|
||||||
|
@ -20,115 +23,46 @@ class Type(Enum):
|
||||||
EXE = "exe"
|
EXE = "exe"
|
||||||
|
|
||||||
|
|
||||||
class Manifest:
|
@dataclass
|
||||||
id: str = ""
|
class Manifest(DataClassJsonMixin):
|
||||||
type: Type = Type.UNKNOWN
|
id: str
|
||||||
path: str = ""
|
type: Kind = field(default=Kind.UNKNOWN)
|
||||||
|
path: str = field(default="")
|
||||||
|
|
||||||
def __init__(
|
@staticmethod
|
||||||
self,
|
def parse(path: Path, data: dict[str, Any]) -> "Manifest":
|
||||||
json: jexpr.Json = None,
|
compat.ensureSupportedManifest(data, path)
|
||||||
path: str = "",
|
kind = Kind(data["type"])
|
||||||
strict: bool = True,
|
del data["$schema"]
|
||||||
**kwargs: Any,
|
obj = KINDS[kind].from_dict(data)
|
||||||
):
|
obj.path = str(path)
|
||||||
if json is not None:
|
return obj
|
||||||
if "id" not in json:
|
|
||||||
raise RuntimeError("Missing id")
|
|
||||||
|
|
||||||
self.id = json["id"]
|
@staticmethod
|
||||||
|
def load(path: Path) -> "Manifest":
|
||||||
if "type" not in json and strict:
|
return Manifest.parse(path, jexpr.evalRead(path))
|
||||||
raise RuntimeError("Missing type")
|
|
||||||
|
|
||||||
self.type = Type(json["type"])
|
|
||||||
|
|
||||||
self.path = path
|
|
||||||
elif strict:
|
|
||||||
raise RuntimeError("Missing json")
|
|
||||||
|
|
||||||
for key in kwargs:
|
|
||||||
setattr(self, key, kwargs[key])
|
|
||||||
|
|
||||||
def toJson(self) -> jexpr.Json:
|
|
||||||
return {"id": self.id, "type": self.type.value, "path": self.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:
|
def dirname(self) -> str:
|
||||||
return os.path.dirname(self.path)
|
return os.path.dirname(self.path)
|
||||||
|
|
||||||
|
def ensureType(self, t: Type[utils.T]) -> utils.T:
|
||||||
class Extern:
|
if not isinstance(self, t):
|
||||||
git: str = ""
|
raise RuntimeError(
|
||||||
tag: str = ""
|
f"{self.path} should be a {type.__name__} manifest but is a {self.__class__.__name__} manifest"
|
||||||
|
)
|
||||||
def __init__(self, json: jexpr.Json = None, strict: bool = True, **kwargs: Any):
|
return cast(utils.T, self)
|
||||||
if json is not None:
|
|
||||||
if "git" not in json and strict:
|
|
||||||
raise RuntimeError("Missing git")
|
|
||||||
|
|
||||||
self.git = json["git"]
|
|
||||||
|
|
||||||
if "tag" not in json and strict:
|
|
||||||
raise RuntimeError("Missing tag")
|
|
||||||
|
|
||||||
self.tag = json["tag"]
|
|
||||||
elif strict:
|
|
||||||
raise RuntimeError("Missing json")
|
|
||||||
|
|
||||||
for key in kwargs:
|
|
||||||
setattr(self, key, kwargs[key])
|
|
||||||
|
|
||||||
def toJson(self) -> jexpr.Json:
|
|
||||||
return {"git": self.git, "tag": self.tag}
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"Extern(git={self.git}, tag={self.tag})"
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"Extern({self.git})"
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Extern(DataClassJsonMixin):
|
||||||
|
git: str
|
||||||
|
tag: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
class Project(Manifest):
|
class Project(Manifest):
|
||||||
description: str = ""
|
description: str = field(default="(No description)")
|
||||||
extern: dict[str, Extern] = {}
|
extern: dict[str, Extern] = field(default_factory=dict)
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
json: jexpr.Json = None,
|
|
||||||
path: str = "",
|
|
||||||
strict: bool = True,
|
|
||||||
**kwargs: Any,
|
|
||||||
):
|
|
||||||
if json is not None:
|
|
||||||
if "description" not in json and strict:
|
|
||||||
raise RuntimeError("Missing description")
|
|
||||||
|
|
||||||
self.description = json["description"]
|
|
||||||
|
|
||||||
self.extern = {k: Extern(v) for k, v in json.get("extern", {}).items()}
|
|
||||||
elif strict:
|
|
||||||
raise RuntimeError("Missing json")
|
|
||||||
|
|
||||||
super().__init__(json, path, strict, **kwargs)
|
|
||||||
|
|
||||||
def toJson(self) -> jexpr.Json:
|
|
||||||
return {
|
|
||||||
**super().toJson(),
|
|
||||||
"description": self.description,
|
|
||||||
"extern": {k: v.toJson() for k, v in self.extern.items()},
|
|
||||||
}
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"ProjectManifest(id={self.id}, type={self.type}, path={self.path}, description={self.description}, extern={self.extern})"
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"ProjectManifest({self.id})"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def root() -> str | None:
|
def root() -> str | None:
|
||||||
|
@ -149,80 +83,21 @@ class Project(Manifest):
|
||||||
os.chdir(path)
|
os.chdir(path)
|
||||||
|
|
||||||
|
|
||||||
class Tool:
|
@dataclass
|
||||||
cmd: str = ""
|
class Tool(DataClassJsonMixin):
|
||||||
args: list[str] = []
|
cmd: str = field(default="")
|
||||||
files: list[str] = []
|
args: list[str] = field(default_factory=list)
|
||||||
|
files: list[str] = field(default_factory=list)
|
||||||
def __init__(self, json: jexpr.Json = None, strict: bool = True, **kwargs: Any):
|
|
||||||
if json is not None:
|
|
||||||
if "cmd" not in json and strict:
|
|
||||||
raise RuntimeError("Missing cmd")
|
|
||||||
|
|
||||||
self.cmd = json.get("cmd", self.cmd)
|
|
||||||
|
|
||||||
if "args" not in json and strict:
|
|
||||||
raise RuntimeError("Missing args")
|
|
||||||
|
|
||||||
self.args = json.get("args", [])
|
|
||||||
|
|
||||||
self.files = json.get("files", [])
|
|
||||||
elif strict:
|
|
||||||
raise RuntimeError("Missing json")
|
|
||||||
|
|
||||||
for key in kwargs:
|
|
||||||
setattr(self, key, kwargs[key])
|
|
||||||
|
|
||||||
def toJson(self) -> jexpr.Json:
|
|
||||||
return {"cmd": self.cmd, "args": self.args, "files": self.files}
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"Tool(cmd={self.cmd}, args={self.args}, files={self.files})"
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"Tool({self.cmd})"
|
|
||||||
|
|
||||||
|
|
||||||
Tools = dict[str, Tool]
|
Tools = dict[str, Tool]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
class Target(Manifest):
|
class Target(Manifest):
|
||||||
props: Props
|
props: Props = field(default_factory=dict)
|
||||||
tools: Tools
|
tools: Tools = field(default_factory=dict)
|
||||||
routing: dict[str, str]
|
routing: dict[str, str] = field(default_factory=dict)
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
json: jexpr.Json = None,
|
|
||||||
path: str = "",
|
|
||||||
strict: bool = True,
|
|
||||||
**kwargs: Any,
|
|
||||||
):
|
|
||||||
if json is not None:
|
|
||||||
if "props" not in json and strict:
|
|
||||||
raise RuntimeError("Missing props")
|
|
||||||
|
|
||||||
self.props = json["props"]
|
|
||||||
|
|
||||||
if "tools" not in json and strict:
|
|
||||||
raise RuntimeError("Missing tools")
|
|
||||||
|
|
||||||
self.tools = {k: Tool(v) for k, v in json["tools"].items()}
|
|
||||||
|
|
||||||
self.routing = json.get("routing", {})
|
|
||||||
|
|
||||||
super().__init__(json, path, strict, **kwargs)
|
|
||||||
|
|
||||||
def toJson(self) -> jexpr.Json:
|
|
||||||
return {
|
|
||||||
**super().toJson(),
|
|
||||||
"props": self.props,
|
|
||||||
"tools": {k: v.toJson() for k, v in self.tools.items()},
|
|
||||||
"routing": self.routing,
|
|
||||||
}
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"TargetManifest({self.id})"
|
|
||||||
|
|
||||||
def route(self, componentSpec: str):
|
def route(self, componentSpec: str):
|
||||||
return (
|
return (
|
||||||
|
@ -250,54 +125,15 @@ class Target(Manifest):
|
||||||
return defines
|
return defines
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
class Component(Manifest):
|
class Component(Manifest):
|
||||||
decription: str = "(No description)"
|
decription: str = field(default="(No description)")
|
||||||
props: Props = {}
|
props: Props = field(default_factory=dict)
|
||||||
tools: Tools = {}
|
tools: Tools = field(default_factory=dict)
|
||||||
enableIf: dict[str, list[Any]] = {}
|
enableIf: dict[str, list[Any]] = field(default_factory=dict)
|
||||||
requires: list[str] = []
|
requires: list[str] = field(default_factory=list)
|
||||||
provides: list[str] = []
|
provides: list[str] = field(default_factory=list)
|
||||||
subdirs: list[str] = []
|
subdirs: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
json: jexpr.Json = None,
|
|
||||||
path: str = "",
|
|
||||||
strict: bool = True,
|
|
||||||
**kwargs: Any,
|
|
||||||
):
|
|
||||||
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.subdirs = list(
|
|
||||||
map(
|
|
||||||
lambda x: os.path.join(os.path.dirname(path), x),
|
|
||||||
json.get("subdirs", [""]),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(json, path, strict, **kwargs)
|
|
||||||
|
|
||||||
def toJson(self) -> jexpr.Json:
|
|
||||||
return {
|
|
||||||
**super().toJson(),
|
|
||||||
"description": self.decription,
|
|
||||||
"props": self.props,
|
|
||||||
"tools": {k: v.toJson() for k, v in self.tools.items()},
|
|
||||||
"enableIf": self.enableIf,
|
|
||||||
"requires": self.requires,
|
|
||||||
"provides": self.provides,
|
|
||||||
"subdirs": self.subdirs,
|
|
||||||
}
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"ComponentManifest({self.id})"
|
|
||||||
|
|
||||||
def isEnabled(self, target: Target) -> tuple[bool, str]:
|
def isEnabled(self, target: Target) -> tuple[bool, str]:
|
||||||
for k, v in self.enableIf.items():
|
for k, v in self.enableIf.items():
|
||||||
|
@ -316,3 +152,11 @@ class Component(Manifest):
|
||||||
)
|
)
|
||||||
|
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
|
|
||||||
|
KINDS: dict[Kind, Type[Manifest]] = {
|
||||||
|
Kind.PROJECT: Project,
|
||||||
|
Kind.TARGET: Target,
|
||||||
|
Kind.LIB: Component,
|
||||||
|
Kind.EXE: Component,
|
||||||
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@ from typing import Any, TypeVar, cast, Optional, Union
|
||||||
import json
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
def uniq(l: list[str]) -> list[str]:
|
def uniq(l: list[T]) -> list[T]:
|
||||||
result: list[str] = []
|
result: list[T] = []
|
||||||
for i in l:
|
for i in l:
|
||||||
if i in result:
|
if i in result:
|
||||||
result.remove(i)
|
result.remove(i)
|
||||||
|
@ -15,7 +15,9 @@ def uniq(l: list[str]) -> list[str]:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def hash(obj: Any, keys: list[str] = [], cls: Optional[type[json.JSONEncoder]] = None) -> str:
|
def hash(
|
||||||
|
obj: Any, keys: list[str] = [], cls: Optional[type[json.JSONEncoder]] = None
|
||||||
|
) -> str:
|
||||||
toHash = {}
|
toHash = {}
|
||||||
if len(keys) == 0:
|
if len(keys) == 0:
|
||||||
toHash = obj
|
toHash = obj
|
||||||
|
@ -28,7 +30,7 @@ def hash(obj: Any, keys: list[str] = [], cls: Optional[type[json.JSONEncoder]] =
|
||||||
|
|
||||||
|
|
||||||
def camelCase(s: str) -> str:
|
def camelCase(s: str) -> str:
|
||||||
s = ''.join(x for x in s.title() if x != '_' and x != '-')
|
s = "".join(x for x in s.title() if x != "_" and x != "-")
|
||||||
s = s[0].lower() + s[1:]
|
s = s[0].lower() + s[1:]
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
@ -60,4 +62,6 @@ def asList(i: Optional[Union[T, list[T]]]) -> list[T]:
|
||||||
|
|
||||||
|
|
||||||
def isNewer(path1: str, path2: str) -> bool:
|
def isNewer(path1: str, path2: str) -> bool:
|
||||||
return not os.path.exists(path2) or os.path.getmtime(path1) > os.path.getmtime(path2)
|
return not os.path.exists(path2) or os.path.getmtime(path1) > os.path.getmtime(
|
||||||
|
path2
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in a new issue