Added many tools
This commit is contained in:
188
tools/cmake.py
188
tools/cmake.py
@@ -0,0 +1,188 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from pathlib import Path
|
||||
|
||||
from core.tools.base import BaseTool, ToolContext
|
||||
from core.tools.registry import registry
|
||||
from core.safety import safety
|
||||
from core.events import bus
|
||||
from core.subprocess import run_command
|
||||
|
||||
|
||||
class CMakeTool(BaseTool):
|
||||
name = "cmake"
|
||||
description = "CMake build system operations (configure, build, generate, clean)"
|
||||
|
||||
# =========================================================
|
||||
# EXECUTE ROUTER
|
||||
# =========================================================
|
||||
|
||||
def execute(self, payload: dict[str, Any], ctx: ToolContext):
|
||||
action = str(payload.get("action", "")).strip()
|
||||
|
||||
bus.log(
|
||||
"CMAKE",
|
||||
"cmake_execute",
|
||||
"INFO",
|
||||
{"action": action}
|
||||
)
|
||||
|
||||
match action:
|
||||
case "configure":
|
||||
return self.configure(payload)
|
||||
|
||||
case "build":
|
||||
return self.build(payload)
|
||||
|
||||
case "clean":
|
||||
return self.clean(payload)
|
||||
|
||||
case "generate":
|
||||
return self.generate(payload)
|
||||
|
||||
case _:
|
||||
raise ValueError(f"Unknown cmake action: {action}")
|
||||
|
||||
# =========================================================
|
||||
# HELPERS
|
||||
# =========================================================
|
||||
|
||||
def _path(self, value: str) -> Path:
|
||||
return safety.validate_path(value)
|
||||
|
||||
# =========================================================
|
||||
# CONFIGURE
|
||||
# =========================================================
|
||||
|
||||
def configure(self, payload: dict[str, Any]):
|
||||
source_dir = payload.get("source_dir", ".")
|
||||
build_dir = payload.get("build_dir", "build")
|
||||
generator = payload.get("generator") # optional
|
||||
build_type = payload.get("build_type", "Release")
|
||||
|
||||
if not isinstance(source_dir, str):
|
||||
raise ValueError("source_dir must be string")
|
||||
if not isinstance(build_dir, str):
|
||||
raise ValueError("build_dir must be string")
|
||||
|
||||
src = self._path(source_dir)
|
||||
bld = self._path(build_dir)
|
||||
|
||||
bld.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
cmd = [
|
||||
"cmake",
|
||||
"-S", str(src),
|
||||
"-B", str(bld),
|
||||
f"-DCMAKE_BUILD_TYPE={build_type}"
|
||||
]
|
||||
|
||||
if generator:
|
||||
if not isinstance(generator, str):
|
||||
raise ValueError("generator must be string")
|
||||
cmd.extend(["-G", generator])
|
||||
|
||||
result = run_command(cmd=cmd)
|
||||
|
||||
return {
|
||||
"action": "configure",
|
||||
"source_dir": str(src),
|
||||
"build_dir": str(bld),
|
||||
"status": "success" if result.get("return_code") == 0 else "error",
|
||||
"stdout": result.get("stdout", ""),
|
||||
"stderr": result.get("stderr", "")
|
||||
}
|
||||
|
||||
# =========================================================
|
||||
# BUILD
|
||||
# =========================================================
|
||||
|
||||
def build(self, payload: dict[str, Any]):
|
||||
build_dir = payload.get("build_dir", "build")
|
||||
target = payload.get("target") # optional
|
||||
jobs = payload.get("jobs", 0)
|
||||
|
||||
if not isinstance(build_dir, str):
|
||||
raise ValueError("build_dir must be string")
|
||||
|
||||
bld = self._path(build_dir)
|
||||
|
||||
cmd = ["cmake", "--build", str(bld)]
|
||||
|
||||
if target:
|
||||
if not isinstance(target, str):
|
||||
raise ValueError("target must be string")
|
||||
cmd.extend(["--target", target])
|
||||
|
||||
if isinstance(jobs, int) and jobs > 0:
|
||||
cmd.extend(["--parallel", str(jobs)])
|
||||
|
||||
result = run_command(cmd=cmd)
|
||||
|
||||
return {
|
||||
"action": "build",
|
||||
"build_dir": str(bld),
|
||||
"target": target,
|
||||
"status": "success" if result.get("return_code") == 0 else "error",
|
||||
"stdout": result.get("stdout", ""),
|
||||
"stderr": result.get("stderr", "")
|
||||
}
|
||||
|
||||
# =========================================================
|
||||
# GENERATE (alias convenience)
|
||||
# =========================================================
|
||||
|
||||
def generate(self, payload: dict[str, Any]):
|
||||
# CMake modern workflow usually doesn't need this separately,
|
||||
# but kept for explicit "generate-only" workflows.
|
||||
return self.configure(payload)
|
||||
|
||||
# =========================================================
|
||||
# CLEAN
|
||||
# =========================================================
|
||||
|
||||
def clean(self, payload: dict[str, Any]):
|
||||
build_dir = payload.get("build_dir", "build")
|
||||
|
||||
if not isinstance(build_dir, str):
|
||||
raise ValueError("build_dir must be string")
|
||||
|
||||
bld = self._path(build_dir)
|
||||
|
||||
if not bld.exists():
|
||||
return {
|
||||
"action": "clean",
|
||||
"status": "skipped",
|
||||
"message": "build directory does not exist"
|
||||
}
|
||||
|
||||
# safe clean: only remove cache artifacts, not full directory unless requested
|
||||
cache_file = bld / "CMakeCache.txt"
|
||||
|
||||
removed = []
|
||||
|
||||
if cache_file.exists():
|
||||
cache_file.unlink()
|
||||
removed.append("CMakeCache.txt")
|
||||
|
||||
# optional: remove CMakeFiles
|
||||
cmake_files = bld / "CMakeFiles"
|
||||
if cmake_files.exists():
|
||||
import shutil
|
||||
shutil.rmtree(cmake_files)
|
||||
removed.append("CMakeFiles/")
|
||||
|
||||
return {
|
||||
"action": "clean",
|
||||
"build_dir": str(bld),
|
||||
"removed": removed,
|
||||
"status": "ok"
|
||||
}
|
||||
|
||||
|
||||
# =========================================================
|
||||
# REGISTER
|
||||
# =========================================================
|
||||
|
||||
registry.register(CMakeTool())
|
||||
Reference in New Issue
Block a user
