167 lines
4.6 KiB
Python
167 lines
4.6 KiB
Python
|
import os
|
||
|
import json
|
||
|
import copy
|
||
|
|
||
|
import utils
|
||
|
|
||
|
|
||
|
def loadJsons(basedir: str) -> dict:
|
||
|
result = {}
|
||
|
for root, dirs, files in os.walk(basedir):
|
||
|
for filename in files:
|
||
|
if filename == 'manifest.json':
|
||
|
filename = os.path.join(root, filename)
|
||
|
try:
|
||
|
with open(filename) as f:
|
||
|
manifest = json.load(f)
|
||
|
manifest["dir"] = os.path.dirname(filename)
|
||
|
result[manifest["id"]] = manifest
|
||
|
except Exception as e:
|
||
|
raise utils.CliException(
|
||
|
f"Failed to load manifest {filename}: {e}")
|
||
|
|
||
|
return result
|
||
|
|
||
|
|
||
|
def filter(manifests: dict, env: dict) -> dict:
|
||
|
result = {}
|
||
|
for id in manifests:
|
||
|
manifest = manifests[id]
|
||
|
accepted = True
|
||
|
|
||
|
if "requires" in manifest:
|
||
|
for req in manifest["requires"]:
|
||
|
if not env[req] in manifest["requires"][req]:
|
||
|
accepted = False
|
||
|
break
|
||
|
|
||
|
if accepted:
|
||
|
result[id] = manifest
|
||
|
|
||
|
return result
|
||
|
|
||
|
|
||
|
def doInjects(manifests: dict) -> dict:
|
||
|
manifests = copy.deepcopy(manifests)
|
||
|
for key in manifests:
|
||
|
item = manifests[key]
|
||
|
if "inject" in item:
|
||
|
for inject in item["inject"]:
|
||
|
if inject in manifests:
|
||
|
manifests[inject]["deps"].append(key)
|
||
|
return manifests
|
||
|
|
||
|
|
||
|
def resolveDeps(manifests: dict) -> dict:
|
||
|
manifests = copy.deepcopy(manifests)
|
||
|
|
||
|
def resolve(key: str, stack: list[str] = []) -> list[str]:
|
||
|
result: list[str] = []
|
||
|
if key in stack:
|
||
|
raise utils.CliException("Circular dependency detected: " +
|
||
|
str(stack) + " -> " + key)
|
||
|
|
||
|
if not key in manifests:
|
||
|
raise utils.CliException("Unknown dependency: " + key)
|
||
|
|
||
|
if "deps" in manifests[key]:
|
||
|
stack.append(key)
|
||
|
result.extend(manifests[key]["deps"])
|
||
|
for dep in manifests[key]["deps"]:
|
||
|
result += resolve(dep, stack)
|
||
|
stack.pop()
|
||
|
return result
|
||
|
|
||
|
for key in manifests:
|
||
|
manifests[key]["deps"] = utils.stripDups(resolve(key))
|
||
|
|
||
|
return manifests
|
||
|
|
||
|
|
||
|
def findFiles(manifests: dict) -> dict:
|
||
|
manifests = copy.deepcopy(manifests)
|
||
|
|
||
|
for key in manifests:
|
||
|
item = manifests[key]
|
||
|
path = manifests[key]["dir"]
|
||
|
testsPath = os.path.join(path, "tests")
|
||
|
assetsPath = os.path.join(path, "assets")
|
||
|
|
||
|
item["tests"] = utils.findFiles(testsPath, [".c", ".cpp"])
|
||
|
item["srcs"] = utils.findFiles(path, [".c", ".cpp", ".s"])
|
||
|
item["assets"] = utils.findFiles(assetsPath)
|
||
|
|
||
|
return manifests
|
||
|
|
||
|
|
||
|
def prepareTests(manifests: dict) -> dict:
|
||
|
if not "tests" in manifests:
|
||
|
return manifests
|
||
|
manifests = copy.deepcopy(manifests)
|
||
|
tests = manifests["tests"]
|
||
|
|
||
|
for key in manifests:
|
||
|
item = manifests[key]
|
||
|
if "tests" in item and len(item["tests"]) > 0:
|
||
|
tests["deps"] += [item["id"]]
|
||
|
tests["srcs"] += item["tests"]
|
||
|
|
||
|
return manifests
|
||
|
|
||
|
|
||
|
def prepareInOut(manifests: dict, env: dict) -> dict:
|
||
|
manifests = copy.deepcopy(manifests)
|
||
|
for key in manifests:
|
||
|
item = manifests[key]
|
||
|
basedir = os.path.dirname(item["dir"])
|
||
|
|
||
|
item["objs"] = [(x.replace(basedir, env["objdir"] + "/") + ".o", x)
|
||
|
for x in item["srcs"]]
|
||
|
|
||
|
if item["type"] == "lib":
|
||
|
item["out"] = env["bindir"] + "/" + key + ".a"
|
||
|
elif item["type"] == "exe":
|
||
|
item["out"] = env["bindir"] + "/" + key
|
||
|
else:
|
||
|
raise utils.CliException("Unknown type: " + item["type"])
|
||
|
|
||
|
for key in manifests:
|
||
|
item = manifests[key]
|
||
|
item["libs"] = [manifests[x]["out"]
|
||
|
for x in item["deps"] if manifests[x]["type"] == "lib"]
|
||
|
return manifests
|
||
|
|
||
|
|
||
|
def cincludes(manifests: dict) -> str:
|
||
|
include_paths = []
|
||
|
|
||
|
for key in manifests:
|
||
|
item = manifests[key]
|
||
|
if "root-include" in item:
|
||
|
include_paths.append(item["dir"])
|
||
|
|
||
|
if len(include_paths) == 0:
|
||
|
return ""
|
||
|
|
||
|
return " -I" + " -I".join(include_paths)
|
||
|
|
||
|
|
||
|
cache: dict = {}
|
||
|
|
||
|
|
||
|
def loadAll(basedir: str, env: dict) -> dict:
|
||
|
cacheKey = basedir + ":" + env["id"]
|
||
|
if cacheKey in cache:
|
||
|
return cache[cacheKey]
|
||
|
|
||
|
manifests = loadJsons(basedir)
|
||
|
manifests = filter(manifests, env)
|
||
|
manifests = doInjects(manifests)
|
||
|
manifests = resolveDeps(manifests)
|
||
|
manifests = findFiles(manifests)
|
||
|
manifests = prepareTests(manifests)
|
||
|
manifests = prepareInOut(manifests, env)
|
||
|
|
||
|
cache[cacheKey] = manifests
|
||
|
return manifests
|