diff options
| author | Grail Finder <wohilas@gmail.com> | 2026-03-16 09:44:28 +0300 |
|---|---|---|
| committer | Grail Finder <wohilas@gmail.com> | 2026-03-16 09:44:28 +0300 |
| commit | 3d44686a517f65c6f5a985cfa864240b996fdb99 (patch) | |
| tree | 08263e3b97522bd04bb19f7a822d8894064c1930 /tools/chain.go | |
| parent | df04d8c21c4d256ade69f53bfe171f066db943cc (diff) | |
Feat (cli): test run and teardown
Diffstat (limited to 'tools/chain.go')
| -rw-r--r-- | tools/chain.go | 131 |
1 files changed, 105 insertions, 26 deletions
diff --git a/tools/chain.go b/tools/chain.go index 8a79eda..381cc1a 100644 --- a/tools/chain.go +++ b/tools/chain.go @@ -150,7 +150,7 @@ func execSingle(command, stdin string) (string, error) { name := parts[0] args := parts[1:] // Check if it's a built-in Go command - if result := execBuiltin(name, args, stdin); result != "" { + if result, isBuiltin := execBuiltin(name, args, stdin); isBuiltin { return result, nil } // Otherwise execute as system command @@ -201,21 +201,23 @@ func tokenize(input string) []string { } // execBuiltin executes a built-in command if it exists. -func execBuiltin(name string, args []string, stdin string) string { +// Returns (result, true) if it was a built-in (even if result is empty). +// Returns ("", false) if it's not a built-in command. +func execBuiltin(name string, args []string, stdin string) (string, bool) { switch name { case "echo": if stdin != "" { - return stdin + return stdin, true } - return strings.Join(args, " ") + return strings.Join(args, " "), true case "time": - return "2006-01-02 15:04:05 MST" + return "2006-01-02 15:04:05 MST", true case "cat": if len(args) == 0 { if stdin != "" { - return stdin + return stdin, true } - return "" + return "", true } path := args[0] abs := path @@ -224,14 +226,14 @@ func execBuiltin(name string, args []string, stdin string) string { } data, err := os.ReadFile(abs) if err != nil { - return fmt.Sprintf("[error] cat: %v", err) + return fmt.Sprintf("[error] cat: %v", err), true } - return string(data) + return string(data), true case "pwd": - return cfg.FilePickerDir + return cfg.FilePickerDir, true case "cd": if len(args) == 0 { - return "[error] usage: cd <dir>" + return "[error] usage: cd <dir>", true } dir := args[0] // Resolve relative to cfg.FilePickerDir @@ -242,16 +244,16 @@ func execBuiltin(name string, args []string, stdin string) string { abs = filepath.Clean(abs) info, err := os.Stat(abs) if err != nil { - return fmt.Sprintf("[error] cd: %v", err) + return fmt.Sprintf("[error] cd: %v", err), true } if !info.IsDir() { - return "[error] cd: not a directory: " + dir + return "[error] cd: not a directory: " + dir, true } cfg.FilePickerDir = abs - return "Changed directory to: " + cfg.FilePickerDir + return "Changed directory to: " + cfg.FilePickerDir, true case "mkdir": if len(args) == 0 { - return "[error] usage: mkdir [-p] <dir>" + return "[error] usage: mkdir [-p] <dir>", true } createParents := false var dirPath string @@ -263,7 +265,7 @@ func execBuiltin(name string, args []string, stdin string) string { } } if dirPath == "" { - return "[error] usage: mkdir [-p] <dir>" + return "[error] usage: mkdir [-p] <dir>", true } abs := dirPath if !filepath.IsAbs(dirPath) { @@ -277,12 +279,12 @@ func execBuiltin(name string, args []string, stdin string) string { mkdirFunc = os.Mkdir } if err := mkdirFunc(abs, 0o755); err != nil { - return fmt.Sprintf("[error] mkdir: %v", err) + return fmt.Sprintf("[error] mkdir: %v", err), true } if createParents { - return "Created " + dirPath + " (with parents)" + return "Created " + dirPath + " (with parents)", true } - return "Created " + dirPath + return "Created " + dirPath, true case "ls": dir := "." for _, a := range args { @@ -297,7 +299,7 @@ func execBuiltin(name string, args []string, stdin string) string { } entries, err := os.ReadDir(abs) if err != nil { - return fmt.Sprintf("[error] ls: %v", err) + return fmt.Sprintf("[error] ls: %v", err), true } var out strings.Builder for _, e := range entries { @@ -317,21 +319,98 @@ func execBuiltin(name string, args []string, stdin string) string { } } if out.Len() == 0 { - return "(empty directory)" + return "(empty directory)", true } - return strings.TrimRight(out.String(), "\n") + return strings.TrimRight(out.String(), "\n"), true case "go": // Allow all go subcommands if len(args) == 0 { - return "[error] usage: go <subcommand> [options]" + return "[error] usage: go <subcommand> [options]", true } cmd := exec.Command("go", args...) cmd.Dir = cfg.FilePickerDir output, err := cmd.CombinedOutput() if err != nil { - return fmt.Sprintf("[error] go %s: %v\n%s", args[0], err, string(output)) + return fmt.Sprintf("[error] go %s: %v\n%s", args[0], err, string(output)), true } - return string(output) + return string(output), true + case "cp": + if len(args) < 2 { + return "[error] usage: cp <source> <dest>", true + } + src := args[0] + dst := args[1] + if !filepath.IsAbs(src) { + src = filepath.Join(cfg.FilePickerDir, src) + } + if !filepath.IsAbs(dst) { + dst = filepath.Join(cfg.FilePickerDir, dst) + } + data, err := os.ReadFile(src) + if err != nil { + return fmt.Sprintf("[error] cp: %v", err), true + } + err = os.WriteFile(dst, data, 0644) + if err != nil { + return fmt.Sprintf("[error] cp: %v", err), true + } + return "Copied " + src + " to " + dst, true + case "mv": + if len(args) < 2 { + return "[error] usage: mv <source> <dest>", true + } + src := args[0] + dst := args[1] + if !filepath.IsAbs(src) { + src = filepath.Join(cfg.FilePickerDir, src) + } + if !filepath.IsAbs(dst) { + dst = filepath.Join(cfg.FilePickerDir, dst) + } + err := os.Rename(src, dst) + if err != nil { + return fmt.Sprintf("[error] mv: %v", err), true + } + return "Moved " + src + " to " + dst, true + case "rm": + if len(args) == 0 { + return "[error] usage: rm [-r] <file>", true + } + recursive := false + var target string + for _, a := range args { + if a == "-r" || a == "-rf" || a == "-fr" || a == "-recursive" { + recursive = true + } else if target == "" { + target = a + } + } + if target == "" { + return "[error] usage: rm [-r] <file>", true + } + abs := target + if !filepath.IsAbs(target) { + abs = filepath.Join(cfg.FilePickerDir, target) + } + info, err := os.Stat(abs) + if err != nil { + return fmt.Sprintf("[error] rm: %v", err), true + } + if info.IsDir() { + if recursive { + err = os.RemoveAll(abs) + if err != nil { + return fmt.Sprintf("[error] rm: %v", err), true + } + return "Removed " + abs, true + } + return "[error] rm: is a directory (use -r)", true + } + err = os.Remove(abs) + if err != nil { + return fmt.Sprintf("[error] rm: %v", err), true + } + return "Removed " + abs, true } - return "" + return "", false } |
