diff --git a/internal/luabridge/old-luabridge.go b/internal/luabridge/old-luabridge.go deleted file mode 100644 index 0fec21c..0000000 --- a/internal/luabridge/old-luabridge.go +++ /dev/null @@ -1,308 +0,0 @@ -// luabridge.go - интеграция Lua как скриптового языка в fush shell -// Предоставляет API для вызова команд shell из Lua скриптов -// Регистрирует функции exec, pipe, ls, cd, pwd в окружении Lua -// Позволяет создавать сложные скрипты для автоматизации задач - -package luabridge - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - "sync/atomic" - - lua "github.com/yuin/gopher-lua" -) - -// ShellInterface определяет интерфейс для взаимодействия с shell -type ShellInterface interface { - GetEnv(key string) string - SetEnv(key, value string) -} - -// Bridge управляет выполнением Lua скриптов -type Bridge struct { - scriptsDir string - shell ShellInterface - state *lua.LState - closed atomic.Bool -} - -// New создает новый Lua мост -func New(scriptsDir string, shell ShellInterface) *Bridge { - b := &Bridge{ - scriptsDir: scriptsDir, - shell: shell, - } - - // Создаем Lua состояние - b.state = lua.NewState() - - // Регистрируем функции для Lua - b.registerFunctions() - - return b -} - -// registerFunctions регистрирует функции для Lua -func (b *Bridge) registerFunctions() { - // Регистрируем функцию print - b.state.SetGlobal("print", b.state.NewFunction(func(L *lua.LState) int { - args := make([]interface{}, L.GetTop()) - for i := 1; i <= L.GetTop(); i++ { - args[i-1] = L.Get(i) - } - fmt.Println(args...) - return 0 - })) - - // Регистрируем функцию getenv - b.state.SetGlobal("getenv", b.state.NewFunction(func(L *lua.LState) int { - key := L.CheckString(1) - value := b.shell.GetEnv(key) - L.Push(lua.LString(value)) - return 1 - })) - - // Регистрируем функцию setenv - b.state.SetGlobal("setenv", b.state.NewFunction(func(L *lua.LState) int { - key := L.CheckString(1) - value := L.CheckString(2) - b.shell.SetEnv(key, value) - return 0 - })) - - // Регистрируем функцию exec для выполнения команд из Lua - b.state.SetGlobal("exec", b.state.NewFunction(func(L *lua.LState) int { - cmd := L.CheckString(1) - args := make([]string, 0) - - // Собираем аргументы - for i := 2; i <= L.GetTop(); i++ { - args = append(args, L.CheckString(i)) - } - - // Выполняем команду - externalCmd := exec.Command(cmd, args...) - externalCmd.Stdout = os.Stdout - externalCmd.Stderr = os.Stderr - - err := externalCmd.Run() - if err != nil { - L.Push(lua.LBool(false)) - L.Push(lua.LString(err.Error())) - return 2 - } - - L.Push(lua.LBool(true)) - return 1 - })) - - // Регистрируем функцию exec_output для получения вывода команды - b.state.SetGlobal("exec_output", b.state.NewFunction(func(L *lua.LState) int { - cmd := L.CheckString(1) - args := make([]string, 0) - - for i := 2; i <= L.GetTop(); i++ { - args = append(args, L.CheckString(i)) - } - - externalCmd := exec.Command(cmd, args...) - output, err := externalCmd.Output() - if err != nil { - L.Push(lua.LNil) - L.Push(lua.LString(err.Error())) - return 2 - } - - L.Push(lua.LString(string(output))) - return 1 - })) - - // Регистрируем функцию pipe для выполнения команд с пайпом - b.state.SetGlobal("pipe", b.state.NewFunction(func(L *lua.LState) int { - cmd1 := L.CheckString(1) - cmd2 := L.CheckString(2) - - // Разбиваем команды на части - parts1 := strings.Fields(cmd1) - parts2 := strings.Fields(cmd2) - - if len(parts1) == 0 || len(parts2) == 0 { - L.Push(lua.LBool(false)) - L.Push(lua.LString("пустая команда")) - return 2 - } - - // Создаем команды - cmd1Exec := exec.Command(parts1[0], parts1[1:]...) - cmd2Exec := exec.Command(parts2[0], parts2[1:]...) - - // Создаем пайп - stdout, err := cmd1Exec.StdoutPipe() - if err != nil { - L.Push(lua.LBool(false)) - L.Push(lua.LString(err.Error())) - return 2 - } - - cmd2Exec.Stdin = stdout - cmd2Exec.Stdout = os.Stdout - cmd2Exec.Stderr = os.Stderr - - // Запускаем команды - if err := cmd1Exec.Start(); err != nil { - L.Push(lua.LBool(false)) - L.Push(lua.LString(err.Error())) - return 2 - } - - if err := cmd2Exec.Start(); err != nil { - L.Push(lua.LBool(false)) - L.Push(lua.LString(err.Error())) - return 2 - } - - // Ожидаем завершения - cmd1Exec.Wait() - cmd2Exec.Wait() - - L.Push(lua.LBool(true)) - return 1 - })) - - // Регистрируем функцию ls - b.state.SetGlobal("ls", b.state.NewFunction(func(L *lua.LState) int { - path := "." - if L.GetTop() > 0 { - path = L.CheckString(1) - } - - dir, err := os.Open(path) - if err != nil { - L.Push(lua.LNil) - L.Push(lua.LString(err.Error())) - return 2 - } - defer dir.Close() - - files, err := dir.Readdir(-1) - if err != nil { - L.Push(lua.LNil) - L.Push(lua.LString(err.Error())) - return 2 - } - - // Создаем таблицу с результатами - tbl := L.NewTable() - for _, file := range files { - tbl.Append(lua.LString(file.Name())) - } - - L.Push(tbl) - return 1 - })) - - // Регистрируем функцию cd - b.state.SetGlobal("cd", b.state.NewFunction(func(L *lua.LState) int { - path := L.GetTop() > 0 - if !path { - path = true - // Передаем true, но нужен путь - _ = path - } - // Простая реализация cd через shell - dir := b.shell.GetEnv("HOME") - if L.GetTop() > 0 { - dir = L.CheckString(1) - } - - if err := os.Chdir(dir); err != nil { - L.Push(lua.LBool(false)) - L.Push(lua.LString(err.Error())) - return 2 - } - - L.Push(lua.LBool(true)) - return 1 - })) - - // Регистрируем функцию pwd - b.state.SetGlobal("pwd", b.state.NewFunction(func(L *lua.LState) int { - dir, err := os.Getwd() - if err != nil { - L.Push(lua.LNil) - L.Push(lua.LString(err.Error())) - return 2 - } - - L.Push(lua.LString(dir)) - return 1 - })) -} - -// ExecuteScript выполняет Lua скрипт -func (b *Bridge) ExecuteScript(name string, args []string) error { - if b.closed.Load() { - return fmt.Errorf("мост закрыт") - } - - // Формируем путь к скрипту - scriptPath := filepath.Join(b.scriptsDir, name+".lua") - - // Проверяем существование файла - if _, err := os.Stat(scriptPath); os.IsNotExist(err) { - return err - } - - // Загружаем и выполняем скрипт - if err := b.state.DoFile(scriptPath); err != nil { - return err - } - - // Вызываем функцию main если она существует - if fn := b.state.GetGlobal("main"); fn.Type() == lua.LTFunction { - // Преобразуем аргументы в Lua значения - luaArgs := make([]lua.LValue, len(args)) - for i, arg := range args { - luaArgs[i] = lua.LString(arg) - } - - if err := b.state.CallByParam(lua.P{ - Fn: fn, - NRet: 0, - Protect: true, - }, luaArgs...); err != nil { - return err - } - } - - return nil -} - -// ExecuteString выполняет Lua код из строки -func (b *Bridge) ExecuteString(code string) error { - if b.closed.Load() { - return fmt.Errorf("мост закрыт") - } - - return b.state.DoString(code) -} - -// GetState возвращает Lua состояние -func (b *Bridge) GetState() *lua.LState { - return b.state -} - -// Close закрывает Lua состояние -func (b *Bridge) Close() { - if b.closed.Load() { - return - } - b.closed.Store(true) - if b.state != nil { - b.state.Close() - } -}