Files
slicer-service/api/internal/cli/cli.go
Sotig 0c40983293 ui
2026-05-29 21:16:10 +03:00

126 lines
2.9 KiB
Go

package cli
import (
"context"
"errors"
"io"
"os/exec"
"regexp"
"strings"
)
var re = regexp.MustCompile(`\w|\%|^(\+|,|\.|:|\/|\\|=|_|-|[a-z]|[A-Z]|[0-9]|\s)+$`)
func validateCliArgument(arg string) bool {
return re.Match([]byte(arg))
}
func validateCliArguments(args []string) bool {
for _, p := range args {
if !validateCliArgument(p) {
return false
}
}
return true
}
func execNoCheck(ctx context.Context, command string, args []string) (string, string, error) {
cmd := exec.CommandContext(ctx, command, args...)
cmdStr := cmd.String()
pStdout, err := cmd.StdoutPipe()
if err != nil {
return "", cmdStr, err
}
pStderr, err := cmd.StderrPipe()
if err != nil {
return "", cmdStr, err
}
err = cmd.Start()
if err != nil {
return "", cmdStr, err
}
stdout, _ := io.ReadAll(pStdout)
stderr, _ := io.ReadAll(pStderr)
err = cmd.Wait()
if err != nil {
return "", cmdStr, errors.New(err.Error() + " | " + string(stderr) + " | " + string(stdout))
}
return string(stdout), cmdStr, nil
}
type Pipe struct {
Command string
SuffixSymbol string
Args []string
}
func (p *Pipe) IsSanatory() bool {
return validateCliArguments(p.Args) && validateCliArgument(p.Command)
}
func (p *Pipe) Execute(ctx context.Context) (string, string, error) {
if !p.IsSanatory() {
return "", "", errors.New("failed to execute cli command: " + p.Command + " " + strings.Join(p.Args, " ") + " some arguments are not allowed")
} else {
return execNoCheck(ctx, p.Command, p.Args)
}
}
// ExecuteCombined runs the command and returns combined stdout+stderr output.
// Useful when a tool writes useful output to either stream.
func (p *Pipe) ExecuteCombined(ctx context.Context) (string, string, error) {
if !p.IsSanatory() {
return "", "", errors.New("failed to execute cli command: " + p.Command + " " + strings.Join(p.Args, " ") + " some arguments are not allowed")
}
cmd := exec.CommandContext(ctx, p.Command, p.Args...)
cmdStr := cmd.String()
out, err := cmd.CombinedOutput()
if err != nil {
return "", cmdStr, errors.New(err.Error() + " | " + string(out))
}
return string(out), cmdStr, nil
}
func ExecuteCLIPipeLine(ctx context.Context, pipes []Pipe) (string, string, error) {
pipeLen := len(pipes)
if pipeLen == 0 {
return "", "", errors.New("failed to execute cli command: no pipes provided")
}
argLen := 0
for _, p := range pipes {
if !p.IsSanatory() {
return "", "", errors.New("failed to execute cli command: " + p.Command + " " + strings.Join(p.Args, " ") + " some arguments are not allowed")
}
argLen += len(p.Args) + 1
}
command := "/bin/sh"
var args []string = []string{}
args = append(args, "-c")
pipeLen -= 1
cmdArg := ""
for i, p := range pipes {
cmdArg += p.Command + " " + strings.Join(p.Args, " ")
if i != pipeLen {
if p.SuffixSymbol != "" {
cmdArg += " " + p.SuffixSymbol + " "
} else {
cmdArg += " | "
}
}
}
args = append(args, cmdArg)
return execNoCheck(ctx, command, args)
}