Add build command and configuration loading for project compilation

- Introduced `cmd_build` function to handle project compilation.
- Added `load_config` function to load project configuration from Nutfile.
- Implemented `prepare_build_directory` and `compile` functions in a new compiler module.
- Updated `is_nut_workspace` function to accept a default path argument.
This commit is contained in:
Chipperfluff 2026-04-03 17:54:14 +02:00
parent e37ee1af6c
commit 0a71a35b44
4 changed files with 89 additions and 1 deletions

View File

@ -1,5 +1,9 @@
from .cli import CLI from .cli import CLI
from .config import load_config
from .commands.setup import is_nut_workspace, find_template_conflicts, copy_template_files from .commands.setup import is_nut_workspace, find_template_conflicts, copy_template_files
from .commands.compiler import compile
def help_text(): def help_text():
return [ return [
@ -27,8 +31,26 @@ def main() -> int:
help="Directory to initialize (default: current directory)", help="Directory to initialize (default: current directory)",
).handle(cmd_init) ).handle(cmd_init)
cli.command(
"build",
help="Compile the project",
description=(
"Compile the project according to the configuration in the Nutfile. "
),
).handle(cmd_build)
return cli.run() return cli.run()
def cmd_build(args, flags) -> int:
if not is_nut_workspace():
print("Error: No Nutfile found. Please run 'nut init' to create a workspace.")
return 1
config = load_config()
compile(config)
return 0
def cmd_init(args, flags) -> int: def cmd_init(args, flags) -> int:
dest_dir = args[0] dest_dir = args[0]
force = flags["force"] force = flags["force"]

35
nut/commands/compiler.py Normal file
View File

@ -0,0 +1,35 @@
from nut.config import Config
from nut.paths import get_templates_path
from os import remove, makedirs, rmdir, listdir
import shutil
def prepare_build_directory(path: str) -> None:
if path.exists(path):
if not path.isdir(path):
raise RuntimeError(f"Build path exists but is not a directory: {path}")
for item in listdir(path):
item_path = path.join(path, item)
if path.isdir(item_path):
rmdir(item_path)
else:
remove(item_path)
else:
makedirs(path)
builtins_path = get_templates_path() / "builtins"
if not path.exists(builtins_path):
raise RuntimeError(f"Builtins path does not exist: {builtins_path}, this should not happen, installation may be corrupted")
shutil.copytree(
builtins_path,
path.join(path, "builtins"),
dirs_exist_ok=True
)
def compile(config: Config) -> None:
print("Compiling the project...")
prepare_build_directory(config.buildFolder or "build")
print("Compilation completed successfully.")

View File

@ -43,5 +43,5 @@ def copy_template_files(dest_dir: str, force: bool = False, checked: bool = Fals
dirs_exist_ok=True dirs_exist_ok=True
) )
def is_nut_workspace(path: str) -> bool: def is_nut_workspace(path: str = ".") -> bool:
return os.path.isfile(os.path.join(path, "Nutfile")) return os.path.isfile(os.path.join(path, "Nutfile"))

31
nut/config.py Normal file
View File

@ -0,0 +1,31 @@
from .utils import read_yaml
class Node:
def __init__(self, data):
for key, value in data.items():
if isinstance(value, dict):
value = Node(value)
elif isinstance(value, list):
value = [
Node(item) if isinstance(item, dict) else item
for item in value
]
setattr(self, key, value)
def __repr__(self):
return f"<Node {self.__dict__}>"
class Config:
def __init__(self, path: str):
self.path = path
self.raw = read_yaml(path)
self.root = Node(self.raw)
def __getattr__(self, item):
if not hasattr(self.root, item):
return None
return getattr(self.root, item)
def load_config():
return Config("Nutfile")