105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
// internal/templating/engine.go
|
|
package templating
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"text/template"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// LoadTemplate 从文件加载 YAML 模板
|
|
func LoadTemplate(path string) (*Template, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("无法读取模板文件 %s: %w", path, err)
|
|
}
|
|
var tmpl Template
|
|
if err := yaml.Unmarshal(data, &tmpl); err != nil {
|
|
return nil, fmt.Errorf("YAML 解析失败: %w", err)
|
|
}
|
|
return &tmpl, nil
|
|
}
|
|
|
|
// Render 渲染模板为具体操作
|
|
func (t *Template) Render(ctx Context) (map[string][]RenderedStep, error) {
|
|
result := make(map[string][]RenderedStep)
|
|
|
|
for stageName, steps := range t.Stages {
|
|
var renderedSteps []RenderedStep
|
|
for _, step := range steps {
|
|
// 处理 condition
|
|
if step.Condition != "" {
|
|
condTmpl, err := template.New("condition").Parse(step.Condition)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("条件模板语法错误: %w", err)
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := condTmpl.Execute(&buf, ctx); err != nil {
|
|
return nil, fmt.Errorf("执行条件模板失败: %w", err)
|
|
}
|
|
if buf.String() == "" {
|
|
continue // 条件不满足,跳过
|
|
}
|
|
}
|
|
|
|
// 渲染 content
|
|
contentTmpl, err := template.New("content").Parse(step.Content)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("内容模板语法错误: %w", err)
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := contentTmpl.Execute(&buf, ctx); err != nil {
|
|
return nil, fmt.Errorf("执行内容模板失败: %w", err)
|
|
}
|
|
|
|
renderedSteps = append(renderedSteps, RenderedStep{
|
|
Type: step.Type,
|
|
Path: step.Path,
|
|
Content: buf.String(),
|
|
})
|
|
}
|
|
result[stageName] = renderedSteps
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// RenderedStep 是渲染后的步骤
|
|
type RenderedStep struct {
|
|
Type string
|
|
Path string
|
|
Content string
|
|
}
|
|
|
|
// WriteFiles 将 file 类型步骤写入磁盘
|
|
func WriteFiles(steps []RenderedStep, rootDir string) error {
|
|
for _, s := range steps {
|
|
if s.Type != "file" {
|
|
continue
|
|
}
|
|
fullPath := s.Path
|
|
if !filepath.IsAbs(s.Path) {
|
|
fullPath = filepath.Join(rootDir, s.Path)
|
|
}
|
|
if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
|
|
return err
|
|
}
|
|
if err := os.WriteFile(fullPath, []byte(s.Content), 0644); err != nil {
|
|
return fmt.Errorf("写入文件 %s 失败: %w", fullPath, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// PrintScripts 打印 script 内容(安全起见,先不自动执行)
|
|
func PrintScripts(steps []RenderedStep) {
|
|
for _, s := range steps {
|
|
if s.Type == "script" {
|
|
fmt.Printf("# --- 脚本开始 ---\n%s\n# --- 脚本结束 ---\n", s.Content)
|
|
}
|
|
}
|
|
}
|