Files
argus-go/rear/internal/utils/tool_manager.go
T
2025-06-17 07:12:11 +08:00

159 lines
3.2 KiB
Go

package utils
import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"sync"
"time"
)
// 全局变量存储工具路径
var (
ImageMagickPath string
ExifToolPath string
toolsInitOnce sync.Once
toolsInitErr error
)
// Config 初始化配置
type Config struct {
// 工具路径(如果为空,会自动检测)
ImageMagickPath string
ExifToolPath string
}
// Initialize 初始化工具路径(可选调用,如果不调用会在第一次使用时自动初始化)
func Initialize(config *Config) error {
if config == nil {
config = &Config{}
}
toolsInitOnce.Do(func() {
ImageMagickPath = config.ImageMagickPath
ExifToolPath = config.ExifToolPath
toolsInitErr = detectTools()
})
return toolsInitErr
}
// detectTools 检测工具路径
func detectTools() error {
// 获取可执行文件所在目录
execPath, err := os.Executable()
if err != nil {
return fmt.Errorf("failed to get executable path: %w", err)
}
execDir := filepath.Dir(execPath)
// 检测 ImageMagick
if ImageMagickPath == "" {
ImageMagickPath = findTool("convert", execDir)
if ImageMagickPath == "" {
ImageMagickPath = findTool("magick", execDir)
}
}
if ImageMagickPath == "" {
return fmt.Errorf("ImageMagick not found")
}
// 检测 ExifTool
if ExifToolPath == "" {
ExifToolPath = findTool("exiftool", execDir)
}
if ExifToolPath == "" {
return fmt.Errorf("ExifTool not found")
}
return nil
}
// findTool 查找工具
func findTool(name string, execDir string) string {
// Windows 下添加 .exe 后缀
if runtime.GOOS == "windows" {
name = name + ".exe"
}
// 查找顺序:
// 1. 执行文件同目录
// 2. 执行文件同目录的 bin 子目录
// 3. 执行文件同目录的 tools 子目录
// 4. 系统 PATH
searchPaths := []string{
filepath.Join(execDir, name),
filepath.Join(execDir, "bin", name),
filepath.Join(execDir, "tools", name),
}
for _, path := range searchPaths {
if _, err := os.Stat(path); err == nil {
return path
}
}
// 尝试从 PATH 中查找
if path, err := exec.LookPath(name); err == nil {
return path
}
return ""
}
// EnsureInitialized 确保工具已初始化
func EnsureInitialized() error {
if toolsInitErr == nil && ImageMagickPath == "" && ExifToolPath == "" {
return Initialize(nil)
}
return toolsInitErr
}
// CommandResult 命令执行结果
type CommandResult struct {
Stdout []byte
Stderr []byte
ExitCode int
Duration time.Duration
}
// ExecuteCommand 执行命令的通用函数
func ExecuteCommand(ctx context.Context, program string, args ...string) (*CommandResult, error) {
// 创建命令
cmd := exec.CommandContext(ctx, program, args...)
// 准备输出缓冲区
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
// 记录开始时间
start := time.Now()
// 执行命令
err := cmd.Run()
duration := time.Since(start)
result := &CommandResult{
Stdout: stdout.Bytes(),
Stderr: stderr.Bytes(),
Duration: duration,
}
// 获取退出码
if exitErr, ok := err.(*exec.ExitError); ok {
result.ExitCode = exitErr.ExitCode()
} else if err == nil {
result.ExitCode = 0
} else {
result.ExitCode = -1
}
return result, err
}