Files
homeagent-sdk/tools/plugindev/cmd_debug.go

176 lines
4.5 KiB
Go

package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/JianFeeeee/homeagent-sdk/tools/plugindev/yaegi"
)
// tmplLuaDebug is the temporary Lua debug script template
const tmplLuaDebug = `-- HomeAgent Lua Plugin Debug
-- Generated by plugindev debug --lua
sdk = require("sdk")
local ok, plugin = pcall(dofile, "main.lua")
if not ok then
print("[debug] ERROR loading main.lua: " .. tostring(plugin))
os.exit(1)
end
if type(plugin) == "table" then
print("[debug] Plugin: " .. tostring(plugin.name or "unnamed"))
if plugin.start then
print("[debug] Calling plugin.start(sdk) ...")
local ok, err = pcall(plugin.start, sdk)
if ok then
print("[debug] plugin.start() OK")
else
print("[debug] plugin:start() ERROR: " .. tostring(err))
end
end
end
print("")
print("=== Interactive REPL ===")
print("sdk, plugin globals are available")
local function repl()
while true do
io.write("> ")
io.flush()
local line = io.read()
if line == nil or line == "exit" or line == "quit" then break end
if line == "help" then
print(" help - this help")
print(" exit/quit - exit debug")
print(" sdk - SDK API table")
print(" plugin - loaded plugin table")
else
local fn, err = (loadstring or load)(line)
if fn then
local ok, result = pcall(fn)
if ok and result ~= nil then print(tostring(result)) end
if not ok then print("Error: " .. tostring(result)) end
else
print("Error: " .. tostring(err))
end
end
end
end
repl()
`
type DebugConfig struct {
Dir string
Replaces []string
}
func cmdDebug(args []string) {
cfg := DebugConfig{Dir: "."}
for i := 0; i < len(args); i++ {
switch args[i] {
case "--replace", "-R":
if i+1 < len(args) {
cfg.Replaces = append(cfg.Replaces, args[i+1]); i++
}
default:
if !strings.HasPrefix(args[i], "-") {
cfg.Dir = args[i]
}
}
}
dir := cfg.Dir
luaPath := filepath.Join(dir, "main.lua")
sdkPath := filepath.Join(dir, "sdk.lua")
hasGo := false
entries, _ := os.ReadDir(dir)
for _, e := range entries {
if !e.IsDir() && strings.HasSuffix(e.Name(), ".go") && !strings.HasSuffix(e.Name(), "_test.go") {
hasGo = true
break
}
}
// Merge plg.json replaces with CLI --replace overrides
var replaces []string
if plg, err := readPlgJSON(filepath.Join(dir, "plg.json")); err == nil {
replaces = plg.ReplacesToSlice()
}
replaces = append(replaces, cfg.Replaces...)
if _, err := os.Stat(luaPath); err == nil {
debugLua(dir, sdkPath, luaPath)
} else if hasGo {
debugGo(dir, replaces)
} else {
fmt.Println("error: no main.lua or .go files found in", dir)
os.Exit(1)
}
}
func debugLua(dir, sdkPath, luaPath string) {
// check lua interpreter
luaBin, err := exec.LookPath("lua")
if err != nil {
fmt.Println("error: lua interpreter not found in PATH")
fmt.Println(" install Lua 5.1+ or use plugindev build to compile your plugin")
os.Exit(1)
}
fmt.Printf("[debug] Lua interpreter: %s\n", luaBin)
fmt.Printf("[debug] Plugin dir: %s\n", dir)
// check if sdk.lua exists
if _, err := os.Stat(sdkPath); os.IsNotExist(err) {
fmt.Println("warning: sdk.lua not found, debug SDK mock will not be available")
}
// write temporary debug script
debugScript := filepath.Join(dir, "_debug.lua")
if err := os.WriteFile(debugScript, []byte(tmplLuaDebug), 0644); err != nil {
fmt.Printf("error: write debug script: %v\n", err)
os.Exit(1)
}
defer os.Remove(debugScript)
cmd := exec.Command(luaBin, filepath.Base(debugScript))
cmd.Dir = dir
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
fmt.Println("[debug] Starting Lua debug session...")
fmt.Println()
if err := cmd.Run(); err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
os.Exit(exitErr.ExitCode())
}
fmt.Printf("[debug] error: %v\n", err)
os.Exit(1)
}
}
func debugGo(dir string, replaces []string) {
debug, err := yaegi.NewYaegiDebugger(dir, replaces)
if err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
}
fmt.Printf("[debug] Plugin dir: %s\n", dir)
if err := debug.LoadPlugin(); err != nil {
fmt.Printf("[debug] load plugin: %v\n", err)
os.Exit(1)
}
if err := debug.StartREPL(); err != nil {
fmt.Printf("[debug] repl error: %v\n", err)
os.Exit(1)
}
}
var _ = strings.TrimSpace