60 lines
1.1 KiB
Go
60 lines
1.1 KiB
Go
|
|
package executor
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"os/exec"
|
||
|
|
"strings"
|
||
|
|
"syscall"
|
||
|
|
)
|
||
|
|
|
||
|
|
func Execute(command string) error {
|
||
|
|
parts := parseCommand(command)
|
||
|
|
if len(parts) == 0 {
|
||
|
|
return fmt.Errorf("empty command")
|
||
|
|
}
|
||
|
|
|
||
|
|
cmd := exec.Command(parts[0], parts[1:]...)
|
||
|
|
cmd.Stdin = os.Stdin
|
||
|
|
cmd.Stdout = os.Stdout
|
||
|
|
cmd.Stderr = os.Stderr
|
||
|
|
|
||
|
|
if err := cmd.Run(); err != nil {
|
||
|
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
||
|
|
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
|
||
|
|
os.Exit(status.ExitStatus())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return fmt.Errorf("command failed: %w", err)
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func parseCommand(command string) []string {
|
||
|
|
var parts []string
|
||
|
|
var current strings.Builder
|
||
|
|
var inSingleQuote, inDoubleQuote bool
|
||
|
|
|
||
|
|
for _, r := range command {
|
||
|
|
switch {
|
||
|
|
case r == '\'' && !inDoubleQuote:
|
||
|
|
inSingleQuote = !inSingleQuote
|
||
|
|
case r == '"' && !inSingleQuote:
|
||
|
|
inDoubleQuote = !inDoubleQuote
|
||
|
|
case r == ' ' && !inSingleQuote && !inDoubleQuote:
|
||
|
|
if current.Len() > 0 {
|
||
|
|
parts = append(parts, current.String())
|
||
|
|
current.Reset()
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
current.WriteRune(r)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if current.Len() > 0 {
|
||
|
|
parts = append(parts, current.String())
|
||
|
|
}
|
||
|
|
|
||
|
|
return parts
|
||
|
|
}
|