meta: Renamed osdk -> cutekit + improved logging + better error handling.
This commit is contained in:
parent
00537aa34e
commit
f345f94471
1
.github/workflows/python-publish.yml
vendored
1
.github/workflows/python-publish.yml
vendored
|
@ -17,7 +17,6 @@ permissions:
|
|||
|
||||
jobs:
|
||||
deploy:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
27
README.md
27
README.md
|
@ -1,26 +1,35 @@
|
|||
# osdk
|
||||
|
||||
The operating system development kit
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<p align="center">
|
||||
<img src="logo.png" width="200" height="200">
|
||||
</p>
|
||||
<h1 align="center">CuteKit</h1>
|
||||
<p align="center">
|
||||
The Cute build system and package manager
|
||||
</p>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [osdk](#osdk)
|
||||
- [Table of contents](#table-of-contents)
|
||||
- [Macros](#macros)
|
||||
- [Table of contents](#table-of-contents)
|
||||
- [Macros](#macros)
|
||||
- [`@latest`](#latest)
|
||||
- [`@uname`](#uname)
|
||||
- [`@include`](#include)
|
||||
- [`@join`](#join)
|
||||
- [`@concat`](#concat)
|
||||
- [`@exec`](#exec)
|
||||
- [Manifest file format](#manifest-file-format)
|
||||
- [Manifest file format](#manifest-file-format)
|
||||
- [`id`](#id)
|
||||
- [`type`](#type)
|
||||
- [`description`](#description)
|
||||
- [`enabledIf`](#enabledif)
|
||||
- [`requires`](#requires)
|
||||
- [`provides`](#provides)
|
||||
- [Target file format](#target-file-format)
|
||||
- [Target file format](#target-file-format)
|
||||
- [`id`](#id-1)
|
||||
- [`type`](#type-1)
|
||||
- [`props`](#props)
|
||||
|
@ -197,7 +206,7 @@ Exemple:
|
|||
}
|
||||
```
|
||||
|
||||
Theses values are exposed the translation unit as `__osdk_{prop}__`.
|
||||
Theses values are exposed the translation unit as `__ck_{prop}__`.
|
||||
|
||||
### `tools`
|
||||
|
||||
|
|
50
cutekit/__init__.py
Normal file
50
cutekit/__init__.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
import sys
|
||||
import os
|
||||
import logging
|
||||
|
||||
from cutekit import const, project, vt100, plugins, cmds
|
||||
from cutekit.args import parse
|
||||
|
||||
def setupLogger(verbose: bool):
|
||||
if verbose:
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format=f"{vt100.CYAN}%(asctime)s{vt100.RESET} {vt100.YELLOW}%(levelname)s{vt100.RESET} %(name)s: %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
else:
|
||||
projectRoot = project.root()
|
||||
logFile = const.GLOBAL_LOG_FILE
|
||||
if projectRoot is not None:
|
||||
logFile = os.path.join(projectRoot, const.PROJECT_LOG_FILE)
|
||||
|
||||
# create the directory if it doesn't exist
|
||||
logDir = os.path.dirname(logFile)
|
||||
if not os.path.isdir(logDir):
|
||||
os.makedirs(logDir)
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
filename=logFile,
|
||||
filemode="w",
|
||||
format=f"%(asctime)s %(levelname)s %(name)s: %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
|
||||
def main() -> int:
|
||||
try:
|
||||
a = parse(sys.argv[1:])
|
||||
setupLogger(a.consumeOpt("verbose", False) == True)
|
||||
plugins.loadAll()
|
||||
cmds.exec(a)
|
||||
print()
|
||||
return 0
|
||||
except RuntimeError as e:
|
||||
logging.exception(e)
|
||||
cmds.error(str(e))
|
||||
cmds.usage()
|
||||
print()
|
||||
return 1
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
return 1
|
|
@ -2,10 +2,10 @@ import os
|
|||
import logging
|
||||
from typing import TextIO
|
||||
|
||||
from osdk.model import Props
|
||||
from osdk.ninja import Writer
|
||||
from osdk.context import ComponentInstance, Context, contextFor
|
||||
from osdk import shell, rules
|
||||
from cutekit.model import Props
|
||||
from cutekit.ninja import Writer
|
||||
from cutekit.context import ComponentInstance, Context, contextFor
|
||||
from cutekit import shell, rules
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -54,7 +54,7 @@ def gen(out: TextIO, context: Context):
|
|||
for obj in objects:
|
||||
r = rules.byFileIn(obj[0])
|
||||
if r is None:
|
||||
raise Exception(f"Unknown rule for file {obj[0]}")
|
||||
raise RuntimeError(f"Unknown rule for file {obj[0]}")
|
||||
t = target.tools[r.id]
|
||||
writer.build(obj[1], r.id, obj[0], order_only=t.files)
|
||||
|
||||
|
@ -73,10 +73,10 @@ def gen(out: TextIO, context: Context):
|
|||
reqInstance = context.componentByName(req)
|
||||
|
||||
if reqInstance is None:
|
||||
raise Exception(f"Component {req} not found")
|
||||
raise RuntimeError(f"Component {req} not found")
|
||||
|
||||
if not reqInstance.isLib():
|
||||
raise Exception(f"Component {req} is not a library")
|
||||
raise RuntimeError(f"Component {req} is not a library")
|
||||
|
||||
libraries.append(reqInstance.outfile())
|
||||
|
||||
|
@ -105,10 +105,10 @@ def build(componentSpec: str, targetSpec: str, props: Props = {}) -> ComponentIn
|
|||
instance = context.componentByName(componentSpec)
|
||||
|
||||
if instance is None:
|
||||
raise Exception(f"Component {componentSpec} not found")
|
||||
raise RuntimeError(f"Component {componentSpec} not found")
|
||||
|
||||
if not instance.enabled:
|
||||
raise Exception(
|
||||
raise RuntimeError(
|
||||
f"Component {componentSpec} is disabled: {instance.disableReason}")
|
||||
|
||||
shell.exec(f"ninja", "-v", "-f", ninjaPath, instance.outfile())
|
|
@ -3,17 +3,19 @@ import json
|
|||
import logging
|
||||
import tempfile
|
||||
import requests
|
||||
import sys
|
||||
|
||||
from typing import Callable, cast
|
||||
|
||||
from osdk import context, shell, const, vt100, builder, graph
|
||||
from osdk.args import Args
|
||||
from osdk.context import contextFor
|
||||
from cutekit import context, shell, const, vt100, builder, graph, project
|
||||
from cutekit.args import Args
|
||||
from cutekit.context import contextFor
|
||||
|
||||
Callback = Callable[[Args], None]
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Cmd:
|
||||
shortName: str | None
|
||||
longName: str
|
||||
|
@ -38,19 +40,21 @@ def append(cmd: Cmd):
|
|||
|
||||
|
||||
def runCmd(args: Args):
|
||||
project.chdir()
|
||||
|
||||
targetSpec = cast(str, args.consumeOpt(
|
||||
"target", "host-" + shell.uname().machine))
|
||||
|
||||
componentSpec = args.consumeArg()
|
||||
|
||||
if componentSpec is None:
|
||||
raise Exception("Component not specified")
|
||||
raise RuntimeError("Component not specified")
|
||||
|
||||
component = builder.build(componentSpec, targetSpec)
|
||||
|
||||
os.environ["OSDK_TARGET"] = component.context.target.id
|
||||
os.environ["OSDK_COMPONENT"] = component.id()
|
||||
os.environ["OSDK_BUILDDIR"] = component.context.builddir()
|
||||
os.environ["CK_TARGET"] = component.context.target.id
|
||||
os.environ["CK_COMPONENT"] = component.id()
|
||||
os.environ["CK_BUILDDIR"] = component.context.builddir()
|
||||
|
||||
shell.exec(component.outfile(), *args.args)
|
||||
|
||||
|
@ -59,6 +63,8 @@ cmds += [Cmd("r", "run", "Run the target", runCmd)]
|
|||
|
||||
|
||||
def testCmd(args: Args):
|
||||
project.chdir()
|
||||
|
||||
targetSpec = cast(str, args.consumeOpt(
|
||||
"target", "host-" + shell.uname().machine))
|
||||
builder.testAll(targetSpec)
|
||||
|
@ -68,19 +74,21 @@ cmds += [Cmd("t", "test", "Run all test targets", testCmd)]
|
|||
|
||||
|
||||
def debugCmd(args: Args):
|
||||
project.chdir()
|
||||
|
||||
targetSpec = cast(str, args.consumeOpt(
|
||||
"target", "host-" + shell.uname().machine))
|
||||
|
||||
componentSpec = args.consumeArg()
|
||||
|
||||
if componentSpec is None:
|
||||
raise Exception("Component not specified")
|
||||
raise RuntimeError("Component not specified")
|
||||
|
||||
component = builder.build(componentSpec, targetSpec)
|
||||
|
||||
os.environ["OSDK_TARGET"] = component.context.target.id
|
||||
os.environ["OSDK_COMPONENT"] = component.id()
|
||||
os.environ["OSDK_BUILDDIR"] = component.context.builddir()
|
||||
os.environ["CK_TARGET"] = component.context.target.id
|
||||
os.environ["CK_COMPONENT"] = component.id()
|
||||
os.environ["CK_BUILDDIR"] = component.context.builddir()
|
||||
|
||||
shell.exec("lldb", "-o", "run", component.outfile(), *args.args)
|
||||
|
||||
|
@ -89,6 +97,8 @@ cmds += [Cmd("d", "debug", "Debug the target", debugCmd)]
|
|||
|
||||
|
||||
def buildCmd(args: Args):
|
||||
project.chdir()
|
||||
|
||||
targetSpec = cast(str, args.consumeOpt(
|
||||
"target", "host-" + shell.uname().machine))
|
||||
|
||||
|
@ -104,6 +114,8 @@ cmds += [Cmd("b", "build", "Build the target", buildCmd)]
|
|||
|
||||
|
||||
def listCmd(args: Args):
|
||||
project.chdir()
|
||||
|
||||
components = context.loadAllComponents()
|
||||
targets = context.loadAllTargets()
|
||||
|
||||
|
@ -129,6 +141,7 @@ cmds += [Cmd("l", "list", "List the targets", listCmd)]
|
|||
|
||||
|
||||
def cleanCmd(args: Args):
|
||||
project.chdir()
|
||||
shell.rmrf(const.BUILD_DIR)
|
||||
|
||||
|
||||
|
@ -136,7 +149,8 @@ cmds += [Cmd("c", "clean", "Clean the build directory", cleanCmd)]
|
|||
|
||||
|
||||
def nukeCmd(args: Args):
|
||||
shell.rmrf(const.OSDK_DIR)
|
||||
project.chdir()
|
||||
shell.rmrf(const.PROJECT_CK_DIR)
|
||||
|
||||
|
||||
cmds += [Cmd("n", "nuke", "Clean the build directory and cache", nukeCmd)]
|
||||
|
@ -148,7 +162,7 @@ def helpCmd(args: Args):
|
|||
print()
|
||||
|
||||
vt100.title("Description")
|
||||
print(" Operating System Development Kit.")
|
||||
print(f" {const.DESCRIPTION}")
|
||||
|
||||
print()
|
||||
vt100.title("Commands")
|
||||
|
@ -161,19 +175,25 @@ def helpCmd(args: Args):
|
|||
f" {vt100.GREEN}{cmd.shortName or ' '}{vt100.RESET} {cmd.longName} - {cmd.helpText} {pluginText}")
|
||||
|
||||
print()
|
||||
vt100.title("Logging")
|
||||
print(f" Logs are stored in:")
|
||||
print(f" - {const.PROJECT_LOG_FILE}")
|
||||
print(f" - {const.GLOBAL_LOG_FILE}")
|
||||
|
||||
|
||||
cmds += [Cmd("h", "help", "Show this help message", helpCmd)]
|
||||
|
||||
|
||||
def versionCmd(args: Args):
|
||||
print(f"OSDK v{const.VERSION}\n")
|
||||
print(f"CuteKit v{const.VERSION_STR}\n")
|
||||
|
||||
|
||||
cmds += [Cmd("v", "version", "Show current version", versionCmd)]
|
||||
|
||||
|
||||
def graphCmd(args: Args):
|
||||
project.chdir()
|
||||
|
||||
targetSpec = cast(str, args.consumeOpt(
|
||||
"target", "host-" + shell.uname().machine))
|
||||
|
||||
|
@ -191,10 +211,12 @@ cmds += [Cmd("g", "graph", "Show dependency graph", graphCmd)]
|
|||
|
||||
|
||||
def installCmd(args: Args):
|
||||
project = context.loadProject(".")
|
||||
project.chdir()
|
||||
|
||||
for extSpec in project.extern:
|
||||
ext = project.extern[extSpec]
|
||||
pj = context.loadProject(".")
|
||||
|
||||
for extSpec in pj.extern:
|
||||
ext = pj.extern[extSpec]
|
||||
|
||||
extPath = os.path.join(const.EXTERN_DIR, extSpec)
|
||||
|
||||
|
@ -212,41 +234,54 @@ cmds += [Cmd("i", "install", "Install all the external packages", installCmd)]
|
|||
|
||||
def initCmd(args: Args):
|
||||
template = args.consumeArg()
|
||||
|
||||
if template is None:
|
||||
template = "default"
|
||||
|
||||
repo = const.DEFAULT_REPO_TEMPLATES if not "repo" in args.opts else args.opts["repo"]
|
||||
list = "list" in args.opts
|
||||
|
||||
if list:
|
||||
logger.info("Fetching registry...")
|
||||
r = requests.get(f'https://raw.githubusercontent.com/{repo}/main/registry.json')
|
||||
r = requests.get(
|
||||
f'https://raw.githubusercontent.com/{repo}/main/registry.json')
|
||||
|
||||
if r.status_code != 200:
|
||||
logger.error('Failed to fetch registry')
|
||||
exit(1)
|
||||
|
||||
print('\n'.join(f"* {entry['id']} - {entry['description']}" for entry in json.loads(r.text)))
|
||||
print('\n'.join(
|
||||
f"* {entry['id']} - {entry['description']}" for entry in json.loads(r.text)))
|
||||
else:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
shell.exec(*["git", "clone", "-n", "--depth=1", "--filter=tree:0", f"https://github.com/{repo}", os.path.join(tmp, "osdk-repo"), "-q"])
|
||||
shell.exec(*["git", "-C", os.path.join(tmp, "osdk-repo"), "sparse-checkout", "set", "--no-cone", template, "-q"])
|
||||
shell.exec(*["git", "-C", os.path.join(tmp, "osdk-repo"), "checkout", "-q"])
|
||||
shell.mv(os.path.join(tmp, "osdk-repo", template), os.path.join(".", template))
|
||||
shell.exec(*["git", "clone", "-n", "--depth=1",
|
||||
"--filter=tree:0", f"https://github.com/{repo}", tmp, "-q"])
|
||||
shell.exec(*["git", "-C", tmp, "sparse-checkout",
|
||||
"set", "--no-cone", template, "-q"])
|
||||
shell.exec(*["git", "-C", tmp, "checkout", "-q"])
|
||||
shell.mv(os.path.join(tmp, template), os.path.join(".", template))
|
||||
|
||||
cmds += [Cmd("I", "init", "Start a new project", initCmd)]
|
||||
|
||||
cmds += [Cmd("I", "init", "Initialize a new project", initCmd)]
|
||||
|
||||
|
||||
def usage():
|
||||
print(f"Usage: {const.ARGV0} <command> [args...]")
|
||||
|
||||
|
||||
def error(msg: str) -> None:
|
||||
print(f"{vt100.RED}Error:{vt100.RESET} {msg}\n", file=sys.stderr)
|
||||
|
||||
|
||||
def exec(args: Args):
|
||||
cmd = args.consumeArg()
|
||||
|
||||
if cmd is None:
|
||||
raise Exception("No command specified")
|
||||
raise RuntimeError("No command specified")
|
||||
|
||||
for c in cmds:
|
||||
if c.shortName == cmd or c.longName == cmd:
|
||||
c.callback(args)
|
||||
return
|
||||
|
||||
raise Exception(f"Unknown command {cmd}")
|
||||
raise RuntimeError(f"Unknown command {cmd}")
|
33
cutekit/compat.py
Normal file
33
cutekit/compat.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from typing import Any
|
||||
|
||||
|
||||
SUPPORTED_MANIFEST = [
|
||||
"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.target.v1",
|
||||
|
||||
]
|
||||
|
||||
OSDK_MANIFEST_NOT_SUPPORTED = "OSDK manifests are not supported by CuteKit. Please use CuteKit manifest instead"
|
||||
|
||||
UNSUPORTED_MANIFEST = {
|
||||
"https://schemas.cute.engineering/stable/osdk.manifest.component.v1": OSDK_MANIFEST_NOT_SUPPORTED,
|
||||
"https://schemas.cute.engineering/stable/osdk.manifest.project.v1": OSDK_MANIFEST_NOT_SUPPORTED,
|
||||
"https://schemas.cute.engineering/stable/osdk.manifest.target.v1": OSDK_MANIFEST_NOT_SUPPORTED,
|
||||
"https://schemas.cute.engineering/latest/osdk.manifest.component": OSDK_MANIFEST_NOT_SUPPORTED,
|
||||
"https://schemas.cute.engineering/latest/osdk.manifest.project": OSDK_MANIFEST_NOT_SUPPORTED,
|
||||
"https://schemas.cute.engineering/latest/osdk.manifest.target": OSDK_MANIFEST_NOT_SUPPORTED,
|
||||
}
|
||||
|
||||
|
||||
def ensureSupportedManifest(manifest: Any, path: str):
|
||||
if not "$schema" in manifest:
|
||||
raise RuntimeError(f"Missing $schema in {path}")
|
||||
|
||||
if manifest["$schema"] in UNSUPORTED_MANIFEST:
|
||||
raise RuntimeError(
|
||||
f"Unsupported manifest schema {manifest['$schema']} in {path}: {UNSUPORTED_MANIFEST[manifest['$schema']]}")
|
||||
|
||||
if not manifest["$schema"] in SUPPORTED_MANIFEST:
|
||||
raise RuntimeError(
|
||||
f"Unsupported manifest schema {manifest['$schema']} in {path}")
|
19
cutekit/const.py
Normal file
19
cutekit/const.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
VERSION = (0, 5, 0, "dev")
|
||||
VERSION_STR = f"{VERSION[0]}.{VERSION[1]}.{VERSION[2]}{'-' + VERSION[3] if VERSION[3] else ''}"
|
||||
MODULE_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
ARGV0 = os.path.basename(sys.argv[0])
|
||||
PROJECT_CK_DIR = ".cutekit"
|
||||
GLOBAL_CK_DIR = os.path.join(os.path.expanduser("~"), ".cutekit")
|
||||
BUILD_DIR = os.path.join(PROJECT_CK_DIR, "build")
|
||||
CACHE_DIR = os.path.join(PROJECT_CK_DIR, "cache")
|
||||
EXTERN_DIR = os.path.join(PROJECT_CK_DIR, "extern")
|
||||
SRC_DIR = "src"
|
||||
META_DIR = f"meta"
|
||||
TARGETS_DIR = os.path.join(META_DIR, "targets")
|
||||
DEFAULT_REPO_TEMPLATES = "cute-engineering/cutekit-templates"
|
||||
DESCRIPTION = "A build system and package manager for low-level software development"
|
||||
PROJECT_LOG_FILE = os.path.join(PROJECT_CK_DIR, "cutekit.log")
|
||||
GLOBAL_LOG_FILE = os.path.join(os.path.expanduser("~"), ".cutekit", "cutekit.log")
|
|
@ -4,8 +4,8 @@ from pathlib import Path
|
|||
import os
|
||||
import logging
|
||||
|
||||
from osdk.model import ProjectManifest, TargetManifest, ComponentManifest, Props, Type, Tool, Tools
|
||||
from osdk import const, shell, jexpr, utils, rules, mixins
|
||||
from cutekit.model import ProjectManifest, TargetManifest, ComponentManifest, Props, Type, Tool, Tools
|
||||
from cutekit import const, shell, jexpr, utils, rules, mixins
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -131,7 +131,7 @@ def loadTarget(id: str) -> TargetManifest:
|
|||
try:
|
||||
return next(filter(lambda t: t.id == id, loadAllTargets()))
|
||||
except StopIteration:
|
||||
raise Exception(f"Target '{id}' not found")
|
||||
raise RuntimeError(f"Target '{id}' not found")
|
||||
|
||||
|
||||
def loadAllComponents() -> list[ComponentManifest]:
|
||||
|
@ -181,7 +181,7 @@ def resolveDeps(componentSpec: str, components: list[ComponentManifest], target:
|
|||
return False, unresolvedReason, []
|
||||
|
||||
if resolved in stack:
|
||||
raise Exception(f"Dependency loop: {stack} -> {resolved}")
|
||||
raise RuntimeError(f"Dependency loop: {stack} -> {resolved}")
|
||||
|
||||
stack.append(resolved)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import os
|
||||
|
||||
from osdk.context import Context
|
||||
from osdk import vt100
|
||||
from cutekit.context import Context
|
||||
from cutekit import vt100
|
||||
|
||||
|
||||
def view(context: Context, scope: str | None = None, showExe: bool = True, showDisabled: bool = False):
|
|
@ -1,7 +1,8 @@
|
|||
from typing import Any, cast, Callable, Final
|
||||
import json
|
||||
|
||||
import osdk.shell as shell
|
||||
import cutekit.shell as shell
|
||||
from cutekit.compat import ensureSupportedManifest
|
||||
|
||||
Json = Any
|
||||
Builtin = Callable[..., Json]
|
||||
|
@ -32,7 +33,7 @@ def eval(jexpr: Json) -> Json:
|
|||
if funcName in BUILTINS:
|
||||
return BUILTINS[funcName](*eval(jexpr[1:]))
|
||||
|
||||
raise Exception(f"Unknown macro {funcName}")
|
||||
raise RuntimeError(f"Unknown macro {funcName}")
|
||||
else:
|
||||
return list(map(eval, jexpr))
|
||||
else:
|
||||
|
@ -44,8 +45,10 @@ def read(path: str) -> Json:
|
|||
with open(path, "r") as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
raise Exception(f"Failed to read {path}")
|
||||
raise RuntimeError(f"Failed to read {path}")
|
||||
|
||||
|
||||
def evalRead(path: str) -> Json:
|
||||
return eval(read(path))
|
||||
data = read(path)
|
||||
ensureSupportedManifest(data, path)
|
||||
return eval(data)
|
|
@ -1,5 +1,5 @@
|
|||
from typing import Callable
|
||||
from osdk.model import TargetManifest, Tools
|
||||
from cutekit.model import TargetManifest, Tools
|
||||
|
||||
Mixin = Callable[[TargetManifest, Tools], Tools]
|
||||
|
|
@ -3,7 +3,7 @@ from enum import Enum
|
|||
from typing import Any
|
||||
import logging
|
||||
|
||||
from osdk.jexpr import Json
|
||||
from cutekit.jexpr import Json
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -27,18 +27,18 @@ class Manifest:
|
|||
def __init__(self, json: Json = None, path: str = "", strict: bool = True, **kwargs: Any):
|
||||
if json is not None:
|
||||
if not "id" in json:
|
||||
raise ValueError("Missing id")
|
||||
raise RuntimeError("Missing id")
|
||||
|
||||
self.id = json["id"]
|
||||
|
||||
if not "type" in json and strict:
|
||||
raise ValueError("Missing type")
|
||||
raise RuntimeError("Missing type")
|
||||
|
||||
self.type = Type(json["type"])
|
||||
|
||||
self.path = path
|
||||
elif strict:
|
||||
raise ValueError("Missing json")
|
||||
raise RuntimeError("Missing json")
|
||||
|
||||
for key in kwargs:
|
||||
setattr(self, key, kwargs[key])
|
||||
|
@ -67,16 +67,16 @@ class Extern:
|
|||
def __init__(self, json: Json = None, strict: bool = True, **kwargs: Any):
|
||||
if json is not None:
|
||||
if not "git" in json and strict:
|
||||
raise ValueError("Missing git")
|
||||
raise RuntimeError("Missing git")
|
||||
|
||||
self.git = json["git"]
|
||||
|
||||
if not "tag" in json and strict:
|
||||
raise ValueError("Missing tag")
|
||||
raise RuntimeError("Missing tag")
|
||||
|
||||
self.tag = json["tag"]
|
||||
elif strict:
|
||||
raise ValueError("Missing json")
|
||||
raise RuntimeError("Missing json")
|
||||
|
||||
for key in kwargs:
|
||||
setattr(self, key, kwargs[key])
|
||||
|
@ -101,14 +101,14 @@ class ProjectManifest(Manifest):
|
|||
def __init__(self, json: Json = None, path: str = "", strict: bool = True, **kwargs: Any):
|
||||
if json is not None:
|
||||
if not "description" in json and strict:
|
||||
raise ValueError("Missing description")
|
||||
raise RuntimeError("Missing description")
|
||||
|
||||
self.description = json["description"]
|
||||
|
||||
self.extern = {k: Extern(v)
|
||||
for k, v in json.get("extern", {}).items()}
|
||||
elif strict:
|
||||
raise ValueError("Missing json")
|
||||
raise RuntimeError("Missing json")
|
||||
|
||||
super().__init__(json, path, strict, **kwargs)
|
||||
|
||||
|
@ -134,18 +134,18 @@ class Tool:
|
|||
def __init__(self, json: Json = None, strict: bool = True, **kwargs: Any):
|
||||
if json is not None:
|
||||
if not "cmd" in json and strict:
|
||||
raise ValueError("Missing cmd")
|
||||
raise RuntimeError("Missing cmd")
|
||||
|
||||
self.cmd = json.get("cmd", self.cmd)
|
||||
|
||||
if not "args" in json and strict:
|
||||
raise ValueError("Missing args")
|
||||
raise RuntimeError("Missing args")
|
||||
|
||||
self.args = json.get("args", [])
|
||||
|
||||
self.files = json.get("files", [])
|
||||
elif strict:
|
||||
raise ValueError("Missing json")
|
||||
raise RuntimeError("Missing json")
|
||||
|
||||
for key in kwargs:
|
||||
setattr(self, key, kwargs[key])
|
||||
|
@ -175,12 +175,12 @@ class TargetManifest(Manifest):
|
|||
def __init__(self, json: Json = None, path: str = "", strict: bool = True, **kwargs: Any):
|
||||
if json is not None:
|
||||
if not "props" in json and strict:
|
||||
raise ValueError("Missing props")
|
||||
raise RuntimeError("Missing props")
|
||||
|
||||
self.props = json["props"]
|
||||
|
||||
if not "tools" in json and strict:
|
||||
raise ValueError("Missing tools")
|
||||
raise RuntimeError("Missing tools")
|
||||
|
||||
self.tools = {k: Tool(v) for k, v in json["tools"].items()}
|
||||
|
||||
|
@ -211,9 +211,9 @@ class TargetManifest(Manifest):
|
|||
macrovalue = str(prop).lower().replace(" ", "_").replace("-", "_")
|
||||
if isinstance(prop, bool):
|
||||
if prop:
|
||||
defines += [f"-D__osdk_{macroname}__"]
|
||||
defines += [f"-D__ck_{macroname}__"]
|
||||
else:
|
||||
defines += [f"-D__osdk_{macroname}_{macrovalue}__"]
|
||||
defines += [f"-D__ck_{macroname}_{macrovalue}__"]
|
||||
|
||||
return defines
|
||||
|
|
@ -25,7 +25,7 @@ use Python.
|
|||
import textwrap
|
||||
from typing import TextIO, Union
|
||||
|
||||
from osdk.utils import asList
|
||||
from cutekit.utils import asList
|
||||
|
||||
|
||||
def escapePath(word: str) -> str:
|
|
@ -1,8 +1,9 @@
|
|||
import os
|
||||
import logging
|
||||
|
||||
from cutekit import shell, project
|
||||
|
||||
import importlib.util as importlib
|
||||
from osdk.shell import readdir
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -20,9 +21,17 @@ def load(path: str):
|
|||
|
||||
def loadAll():
|
||||
logger.info("Loading plugins...")
|
||||
for files in readdir(os.path.join("meta", "plugins")):
|
||||
|
||||
projectRoot = project.root()
|
||||
if projectRoot is None:
|
||||
logger.info("Not in project, skipping plugin loading")
|
||||
return
|
||||
|
||||
pluginDir = os.path.join(projectRoot, "meta/plugins")
|
||||
|
||||
for files in shell.readdir(pluginDir):
|
||||
if files.endswith(".py"):
|
||||
plugin = load(os.path.join("meta", "plugins", files))
|
||||
plugin = load(os.path.join(pluginDir, files))
|
||||
|
||||
if plugin:
|
||||
print(f"Loaded plugin {plugin.name}")
|
17
cutekit/project.py
Normal file
17
cutekit/project.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
import os
|
||||
|
||||
def root() -> str | None:
|
||||
cwd = os.getcwd()
|
||||
while cwd != "/":
|
||||
if os.path.isfile(os.path.join(cwd, "project.json")):
|
||||
return cwd
|
||||
cwd = os.path.dirname(cwd)
|
||||
return None
|
||||
|
||||
|
||||
def chdir() -> None:
|
||||
projectRoot = root()
|
||||
if projectRoot is None:
|
||||
raise RuntimeError("No project.json found in this directory or any parent directory")
|
||||
|
||||
os.chdir(projectRoot)
|
|
@ -10,7 +10,7 @@ import fnmatch
|
|||
import platform
|
||||
import logging
|
||||
|
||||
from osdk import const
|
||||
from cutekit import const
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -131,16 +131,16 @@ def exec(*args: str):
|
|||
proc = subprocess.run(args)
|
||||
|
||||
except FileNotFoundError:
|
||||
raise Exception(f"{args[0]}: Command not found")
|
||||
raise RuntimeError(f"{args[0]}: Command not found")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
raise Exception(f"{args[0]}: Interrupted")
|
||||
raise RuntimeError(f"{args[0]}: Interrupted")
|
||||
|
||||
if proc.returncode == -signal.SIGSEGV:
|
||||
raise Exception(f"{args[0]}: Segmentation fault")
|
||||
raise RuntimeError(f"{args[0]}: Segmentation fault")
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise Exception(
|
||||
raise RuntimeError(
|
||||
f"{args[0]}: Process exited with code {proc.returncode}")
|
||||
|
||||
return True
|
||||
|
@ -152,13 +152,13 @@ def popen(*args: str) -> str:
|
|||
try:
|
||||
proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=sys.stderr)
|
||||
except FileNotFoundError:
|
||||
raise Exception(f"{args[0]}: Command not found")
|
||||
raise RuntimeError(f"{args[0]}: Command not found")
|
||||
|
||||
if proc.returncode == -signal.SIGSEGV:
|
||||
raise Exception(f"{args[0]}: Segmentation fault")
|
||||
raise RuntimeError(f"{args[0]}: Segmentation fault")
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise Exception(
|
||||
raise RuntimeError(
|
||||
f"{args[0]}: Process exited with code {proc.returncode}")
|
||||
|
||||
return proc.stdout.decode('utf-8')
|
||||
|
@ -221,7 +221,7 @@ def latest(cmd: str) -> str:
|
|||
versions.append(f)
|
||||
|
||||
if len(versions) == 0:
|
||||
raise Exception(f"{cmd} not found")
|
||||
raise RuntimeError(f"{cmd} not found")
|
||||
|
||||
versions.sort()
|
||||
chosen = versions[-1]
|
|
@ -1,32 +0,0 @@
|
|||
import sys
|
||||
import logging
|
||||
|
||||
from os.path import isdir
|
||||
from osdk import const, shell
|
||||
from osdk.args import parse
|
||||
from osdk.cmds import exec, usage
|
||||
from osdk.plugins import loadAll
|
||||
import osdk.vt100 as vt100
|
||||
|
||||
|
||||
def main() -> int:
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format=f"{vt100.CYAN}%(asctime)s{vt100.RESET} {vt100.YELLOW}%(levelname)s{vt100.RESET} %(name)s: %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
a = parse(sys.argv[1:])
|
||||
|
||||
|
||||
try:
|
||||
loadAll()
|
||||
exec(a)
|
||||
return 0
|
||||
except Exception as e:
|
||||
logging.error(f"{vt100.RED}{e}{vt100.RESET}")
|
||||
print()
|
||||
|
||||
usage()
|
||||
print()
|
||||
|
||||
raise e
|
|
@ -1,14 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
VERSION = "0.4.1"
|
||||
MODULE_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
ARGV0 = os.path.basename(sys.argv[0])
|
||||
OSDK_DIR = ".osdk"
|
||||
BUILD_DIR = os.path.join(OSDK_DIR, "build")
|
||||
CACHE_DIR = os.path.join(OSDK_DIR, "cache")
|
||||
EXTERN_DIR = os.path.join(OSDK_DIR, "extern")
|
||||
SRC_DIR = "src"
|
||||
META_DIR = f"meta"
|
||||
TARGETS_DIR = os.path.join(META_DIR, "targets")
|
||||
DEFAULT_REPO_TEMPLATES = "cute-engineering/osdk-template"
|
13
setup.py
13
setup.py
|
@ -1,22 +1,23 @@
|
|||
from setuptools import setup
|
||||
from osdk.const import VERSION
|
||||
from cutekit.const import VERSION_STR, DESCRIPTION
|
||||
|
||||
setup(
|
||||
name="osdk",
|
||||
version=VERSION,
|
||||
name="cutekit",
|
||||
version=VERSION_STR,
|
||||
python_requires='>=3.10',
|
||||
description="Operating System Development Kit",
|
||||
description=DESCRIPTION,
|
||||
author="Cute Engineering",
|
||||
author_email="contact@cute.engineering",
|
||||
url="https://cute.engineering/",
|
||||
packages=["osdk"],
|
||||
packages=["cutekit"],
|
||||
install_requires=[
|
||||
"requests",
|
||||
"graphviz"
|
||||
],
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
"osdk = osdk:main",
|
||||
"ck = cutekit:main",
|
||||
"cutekit = cutekit:main",
|
||||
],
|
||||
},
|
||||
license="MIT",
|
||||
|
|
Loading…
Reference in a new issue