Files
code-utils/platform/command.go
2026-08-11 19:07:05 +08:00

78 lines
2.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package platform
import (
"bytes"
"context"
"errors"
"os/exec"
"strconv"
"strings"
"unicode/utf16"
)
// CommandError 保存后台命令失败时的原始诊断信息。
// 服务层会把这些输出映射成稳定错误码,界面再按当前语言展示友好提示。
type CommandError struct {
Command string
Args []string
ExitCode int
Output string
}
func (e *CommandError) Error() string {
if strings.TrimSpace(e.Output) != "" {
return strings.TrimSpace(e.Output)
}
if e.ExitCode != 0 {
return e.Command + " exited with code " + strconv.Itoa(e.ExitCode)
}
return e.Command + " failed"
}
// RunHidden 在后台执行命令并合并 stdout/stderr。
// Windows 下由平台文件设置 HideWindow 和 CREATE_NO_WINDOW避免 Git/WSL 查询弹出终端窗口。
func RunHidden(ctx context.Context, name string, args ...string) (string, error) {
cmd := exec.CommandContext(ctx, name, args...)
configureHidden(cmd)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
e := cmd.Run()
out := strings.TrimSpace(strings.ReplaceAll(decodeOutput(stdout.Bytes()), "\x00", ""))
errOut := strings.TrimSpace(strings.ReplaceAll(decodeOutput(stderr.Bytes()), "\x00", ""))
if e != nil {
if out == "" {
out = errOut
} else if errOut != "" {
out += "\n" + errOut
}
if out == "" {
out = e.Error()
}
exitCode := -1
var exit *exec.ExitError
if errors.As(e, &exit) {
exitCode = exit.ExitCode()
}
return "", &CommandError{Command: name, Args: args, ExitCode: exitCode, Output: out}
}
return out, nil
}
// DecodeWSLList 兼容部分 Windows 版本返回的 UTF-16LE 发行版列表。
func DecodeWSLList(b []byte) string { return decodeOutput(b) }
func decodeOutput(b []byte) string {
if len(b) >= 2 && (b[1] == 0 || b[0] == 0xff && b[1] == 0xfe) {
if len(b)%2 != 0 {
b = b[:len(b)-1]
}
u := make([]uint16, 0, len(b)/2)
for i := 0; i+1 < len(b); i += 2 {
u = append(u, uint16(b[i])|uint16(b[i+1])<<8)
}
return strings.TrimPrefix(string(utf16.Decode(u)), "\ufeff")
}
return string(b)
}