fix: shell call bin
This commit is contained in:
@@ -3,16 +3,12 @@ package tasks
|
|||||||
import (
|
import (
|
||||||
"baihu/internal/constant"
|
"baihu/internal/constant"
|
||||||
"baihu/internal/logger"
|
"baihu/internal/logger"
|
||||||
"baihu/internal/models"
|
|
||||||
"baihu/internal/utils"
|
"baihu/internal/utils"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -232,119 +228,6 @@ func (es *ExecutorService) executeTaskInternal(taskID int) *ExecutionResult {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeNormalTask 执行普通任务
|
|
||||||
func (es *ExecutorService) executeNormalTask(task *models.Task) *ExecutionResult {
|
|
||||||
// 演示模式下使用 echo 替换实际命令
|
|
||||||
if constant.DemoMode {
|
|
||||||
return es.ExecuteCommandWithOptions("echo '[演示模式] 任务执行已跳过,实际命令不会运行'", time.Minute, nil, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载环境变量
|
|
||||||
envVars := es.envService.GetEnvVarsByIDs(task.Envs)
|
|
||||||
|
|
||||||
// 确定工作目录
|
|
||||||
workDir := task.WorkDir
|
|
||||||
if workDir == "" {
|
|
||||||
workDir = constant.ScriptsWorkDir
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用任务配置的超时时间
|
|
||||||
timeout := task.Timeout
|
|
||||||
if timeout <= 0 {
|
|
||||||
timeout = constant.DefaultTaskTimeout
|
|
||||||
}
|
|
||||||
return es.ExecuteCommandWithOptions(task.Command, time.Duration(timeout)*time.Minute, envVars, workDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
// executeRepoTask 执行仓库同步任务(调用 sync.py)
|
|
||||||
func (es *ExecutorService) executeRepoTask(task *models.Task) *ExecutionResult {
|
|
||||||
// 演示模式下使用 echo 替换实际命令
|
|
||||||
if constant.DemoMode {
|
|
||||||
return es.ExecuteCommandWithOptions("echo '[演示模式] 仓库同步已跳过,实际命令不会运行'", time.Minute, nil, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
result := &ExecutionResult{
|
|
||||||
Success: false,
|
|
||||||
Start: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析仓库配置
|
|
||||||
var config models.RepoConfig
|
|
||||||
if err := json.Unmarshal([]byte(task.Config), &config); err != nil {
|
|
||||||
result.End = time.Now()
|
|
||||||
result.Error = "解析仓库配置失败: " + err.Error()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理目标路径:为空则使用 scripts 目录,相对路径则基于 scripts 目录
|
|
||||||
targetPath := config.TargetPath
|
|
||||||
if targetPath == "" {
|
|
||||||
targetPath = constant.ScriptsWorkDir
|
|
||||||
} else if !filepath.IsAbs(targetPath) {
|
|
||||||
targetPath = filepath.Join(constant.ScriptsWorkDir, targetPath)
|
|
||||||
}
|
|
||||||
// 转换为绝对路径
|
|
||||||
absTargetPath, err := filepath.Abs(targetPath)
|
|
||||||
if err != nil {
|
|
||||||
absTargetPath = targetPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建 sync.py 命令参数
|
|
||||||
args := []string{
|
|
||||||
"/opt/sync.py",
|
|
||||||
"--source-type", config.SourceType,
|
|
||||||
"--source-url", config.SourceURL,
|
|
||||||
"--target-path", absTargetPath,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Git 分支
|
|
||||||
if config.Branch != "" {
|
|
||||||
args = append(args, "--branch", config.Branch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 稀疏路径
|
|
||||||
if config.SparsePath != "" {
|
|
||||||
args = append(args, "--path", config.SparsePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 单文件模式
|
|
||||||
if config.SingleFile {
|
|
||||||
args = append(args, "--single-file")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 代理设置
|
|
||||||
if config.Proxy != "" && config.Proxy != "none" {
|
|
||||||
args = append(args, "--proxy", config.Proxy)
|
|
||||||
if config.Proxy == "custom" && config.ProxyURL != "" {
|
|
||||||
args = append(args, "--proxy-url", config.ProxyURL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 认证 Token
|
|
||||||
if config.AuthToken != "" {
|
|
||||||
args = append(args, "--auth-token", config.AuthToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建命令
|
|
||||||
command := "python3 " + strings.Join(args, " ")
|
|
||||||
|
|
||||||
// 使用任务配置的超时时间
|
|
||||||
timeout := task.Timeout
|
|
||||||
if timeout <= 0 {
|
|
||||||
timeout = constant.DefaultTaskTimeout
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行命令
|
|
||||||
execResult := es.ExecuteCommandWithOptions(command, time.Duration(timeout)*time.Minute, nil, "/opt")
|
|
||||||
|
|
||||||
result.End = time.Now()
|
|
||||||
result.Output = execResult.Output
|
|
||||||
result.Success = execResult.Success
|
|
||||||
result.Error = execResult.Error
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRunningCount 获取正在运行的任务数量
|
// GetRunningCount 获取正在运行的任务数量
|
||||||
func (es *ExecutorService) GetRunningCount() int {
|
func (es *ExecutorService) GetRunningCount() int {
|
||||||
es.mu.RLock()
|
es.mu.RLock()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"baihu/internal/utils"
|
"baihu/internal/utils"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -92,6 +93,11 @@ func (s *TaskExecutionService) executeLocal(req *TaskExecutionRequest) error {
|
|||||||
task := req.Task
|
task := req.Task
|
||||||
logger.Infof("[TaskExecution] 本地执行任务 #%d: %s", task.ID, task.Name)
|
logger.Infof("[TaskExecution] 本地执行任务 #%d: %s", task.ID, task.Name)
|
||||||
|
|
||||||
|
// 检查任务类型,仓库任务需要特殊处理
|
||||||
|
if task.Type == "repo" {
|
||||||
|
return s.executeRepoTask(req)
|
||||||
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
// 准备命令
|
// 准备命令
|
||||||
@@ -308,3 +314,112 @@ func (s *TaskExecutionService) ProcessAgentResult(agentResult *models.AgentTaskR
|
|||||||
func (s *TaskExecutionService) GetScriptPath(scriptName string) string {
|
func (s *TaskExecutionService) GetScriptPath(scriptName string) string {
|
||||||
return filepath.Join("data", "scripts", scriptName)
|
return filepath.Join("data", "scripts", scriptName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// executeRepoTask 执行仓库同步任务(调用 sync.py)
|
||||||
|
func (s *TaskExecutionService) executeRepoTask(req *TaskExecutionRequest) error {
|
||||||
|
task := req.Task
|
||||||
|
logger.Infof("[TaskExecution] 执行仓库同步任务 #%d: %s", task.ID, task.Name)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
// 解析仓库配置
|
||||||
|
var config models.RepoConfig
|
||||||
|
if err := json.Unmarshal([]byte(task.Config), &config); err != nil {
|
||||||
|
return s.handleExecutionError(task.ID, "", start, fmt.Errorf("解析仓库配置失败: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理目标路径:为空则使用 scripts 目录,相对路径则基于 scripts 目录
|
||||||
|
targetPath := config.TargetPath
|
||||||
|
if targetPath == "" {
|
||||||
|
targetPath = constant.ScriptsWorkDir
|
||||||
|
} else if !filepath.IsAbs(targetPath) {
|
||||||
|
targetPath = filepath.Join(constant.ScriptsWorkDir, targetPath)
|
||||||
|
}
|
||||||
|
// 转换为绝对路径
|
||||||
|
absTargetPath, err := filepath.Abs(targetPath)
|
||||||
|
if err != nil {
|
||||||
|
absTargetPath = targetPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建 sync.py 命令参数
|
||||||
|
args := []string{
|
||||||
|
"/opt/sync.py",
|
||||||
|
"--source-type", config.SourceType,
|
||||||
|
"--source-url", config.SourceURL,
|
||||||
|
"--target-path", absTargetPath,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Git 分支
|
||||||
|
if config.Branch != "" {
|
||||||
|
args = append(args, "--branch", config.Branch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 稀疏路径
|
||||||
|
if config.SparsePath != "" {
|
||||||
|
args = append(args, "--path", config.SparsePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单文件模式
|
||||||
|
if config.SingleFile {
|
||||||
|
args = append(args, "--single-file")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代理设置
|
||||||
|
if config.Proxy != "" && config.Proxy != "none" {
|
||||||
|
args = append(args, "--proxy", config.Proxy)
|
||||||
|
if config.Proxy == "custom" && config.ProxyURL != "" {
|
||||||
|
args = append(args, "--proxy-url", config.ProxyURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 认证 Token
|
||||||
|
if config.AuthToken != "" {
|
||||||
|
args = append(args, "--auth-token", config.AuthToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 准备命令
|
||||||
|
ctx, cancel := s.createContext(task.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// 直接使用 python3 和参数列表,而不是拼接成字符串
|
||||||
|
cmd := exec.CommandContext(ctx, "python3", args...)
|
||||||
|
cmd.Dir = "/opt"
|
||||||
|
|
||||||
|
// 执行命令
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
|
||||||
|
execErr := cmd.Run()
|
||||||
|
end := time.Now()
|
||||||
|
|
||||||
|
// 构建命令字符串用于日志记录
|
||||||
|
commandStr := "python3 " + strings.Join(args, " ")
|
||||||
|
|
||||||
|
// 构建结果
|
||||||
|
result := &TaskExecutionResult{
|
||||||
|
TaskID: task.ID,
|
||||||
|
AgentID: nil,
|
||||||
|
Command: commandStr,
|
||||||
|
Output: stdout.String(),
|
||||||
|
Start: start,
|
||||||
|
End: end,
|
||||||
|
Duration: end.Sub(start).Milliseconds(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if execErr != nil {
|
||||||
|
result.Status = "failed"
|
||||||
|
result.Output += "\n[ERROR]\n" + stderr.String() + "\n" + execErr.Error()
|
||||||
|
if exitErr, ok := execErr.(*exec.ExitError); ok {
|
||||||
|
result.ExitCode = exitErr.ExitCode()
|
||||||
|
} else {
|
||||||
|
result.ExitCode = 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.Status = "success"
|
||||||
|
result.ExitCode = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理执行结果
|
||||||
|
return s.processExecutionResult(result)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user