| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- package shell
- import (
- "path/filepath"
- "strings"
- "syscall"
- )
- type Executor struct {
- cwd string // 当前所在目录
- pg *processGroup // 当前执行进程
- }
- func NewExecutor() *Executor {
- return &Executor{cwd: "/"}
- }
- func (e *Executor) Exec(p ExecuteParams) (*ExecuteResult, error) {
- if isCD(p.Cmd) {
- dir, err := resolveCD(e.cwd, p.Cmd)
- if err != nil {
- return &ExecuteResult{
- Stderr: err.Error() + "\n",
- ExitCode: 1,
- }, nil
- }
- e.cwd = dir
- return &ExecuteResult{ExitCode: 0}, nil
- }
- if strings.TrimSpace(p.Cmd) == "pwd" {
- return &ExecuteResult{
- Stdout: e.cwd + "\n",
- ExitCode: 0,
- }, nil
- }
- p.Dir = e.cwd
- defer func() {
- e.pg = nil // 命令结束
- }()
- result, err := executeInternal(p, func(pg *processGroup) { e.pg = pg })
- if result != nil {
- result.Cwd = e.cwd
- }
- return result, err
- }
- func isCD(cmd string) bool {
- s := strings.TrimSpace(cmd)
- return s == "cd" || strings.HasPrefix(s, "cd ")
- }
- func resolveCD(cwd, cmd string) (string, error) {
- fields := strings.Fields(cmd)
- if len(fields) == 1 { // 只有"cd", 没有参数
- return "/", nil
- }
- path := fields[1]
- if filepath.IsAbs(path) { // 绝对路径
- return filepath.Clean(path), nil
- }
- return filepath.Clean(filepath.Join(cwd, path)), nil // 相对路径
- }
- func (e *Executor) Interrupt() error {
- if e.pg == nil {
- return nil
- }
- return syscall.Kill(-e.pg.pgid, syscall.SIGINT) // 等价于 Ctrl+C
- }
|