package classify
|
|
import (
|
"encoding/json"
|
"fmt"
|
"os"
|
"os/exec"
|
"path/filepath"
|
"strings"
|
)
|
|
// Migration 单个迁移项
|
type Migration struct {
|
Source string `json:"source"`
|
Target string `json:"target"`
|
}
|
|
// MigrationPlan 迁移计划
|
type MigrationPlan struct {
|
Total int `json:"total"`
|
Migrations []Migration `json:"migrations"`
|
}
|
|
// LoadClassification 加载分类结果
|
func LoadClassification(vaultPath, filename string) (*ClassificationResult, error) {
|
path := filepath.Join(vaultPath, filename)
|
data, err := os.ReadFile(path)
|
if err != nil {
|
return nil, fmt.Errorf("读取文件失败: %w", err)
|
}
|
|
var result ClassificationResult
|
if err := json.Unmarshal(data, &result); err != nil {
|
return nil, fmt.Errorf("解析 JSON 失败: %w", err)
|
}
|
|
return &result, nil
|
}
|
|
// GenerateMigrationPlan 生成迁移计划
|
func GenerateMigrationPlan(vaultPath string, classification *ClassificationResult) (*MigrationPlan, error) {
|
plan := &MigrationPlan{
|
Total: len(classification.Items),
|
Migrations: []Migration{},
|
}
|
|
// 跟踪已使用的目标路径
|
usedTargets := make(map[string]bool)
|
|
for _, item := range classification.Items {
|
// 根据 platform 和 device 生成目标路径
|
targetDir := getTargetDir(item.Platform, item.Device)
|
baseName := filepath.Base(item.Path)
|
targetPath := filepath.Join(targetDir, baseName)
|
|
// 如果目标路径已使用,添加数字后缀直到找到唯一路径
|
counter := 1
|
for usedTargets[targetPath] {
|
counter++
|
ext := filepath.Ext(baseName)
|
nameWithoutExt := strings.TrimSuffix(baseName, ext)
|
targetPath = filepath.Join(targetDir, fmt.Sprintf("%s_%d%s", nameWithoutExt, counter, ext))
|
}
|
usedTargets[targetPath] = true
|
|
plan.Migrations = append(plan.Migrations, Migration{
|
Source: item.Path,
|
Target: targetPath,
|
})
|
}
|
|
return plan, nil
|
}
|
|
// getTargetDir 根据平台和设备获取目标目录
|
func getTargetDir(platform, device string) string {
|
// 平台目录映射(支持中文和英文标识符)
|
platformDir := map[string]string{
|
// 英文标识符
|
"elc": "电子秤平台",
|
"ops": "运营管理平台",
|
"both": "共有硬件",
|
"third_party": "第三方平台",
|
"general": "通用",
|
// 中文标识符
|
"电子秤平台": "电子秤平台",
|
"运营管理平台": "运营管理平台",
|
"共有": "共有硬件",
|
"第三方平台": "第三方平台",
|
"通用": "通用",
|
}
|
|
// 设备目录映射(支持中文和英文标识符)
|
deviceDir := map[string]string{
|
// 英文标识符
|
"scale": "电子秤",
|
"gun": "智能枪",
|
"valve": "智能阀",
|
"box": "艾信盒子",
|
"app_safety": "安全用气App",
|
"app_delivery": "易配送App",
|
"app_assistant": "艾信助手App",
|
"app_lpg": "艾信LPG小程序",
|
"app_shipping": "艾信发货小程序",
|
"none": "通用",
|
// 中文标识符
|
"电子秤": "电子秤",
|
"智能枪": "智能枪",
|
"智能阀": "智能阀",
|
"艾信盒子": "艾信盒子",
|
"安全用气App": "安全用气App",
|
"易配送App": "易配送App",
|
"艾信助手App": "艾信助手App",
|
"艾信LPG小程序": "艾信LPG小程序",
|
"艾信发货小程序": "艾信发货小程序",
|
"无": "通用",
|
"综合": "通用",
|
}
|
|
pDir := platformDir[platform]
|
if pDir == "" {
|
pDir = "通用"
|
}
|
|
dDir := deviceDir[device]
|
if dDir == "" {
|
dDir = "通用"
|
}
|
|
return filepath.Join(pDir, dDir)
|
}
|
|
// SaveMigrationPlan 保存迁移计划
|
func SaveMigrationPlan(vaultPath string, plan *MigrationPlan) error {
|
path := filepath.Join(vaultPath, "migration-plan.json")
|
data, err := json.MarshalIndent(plan, "", " ")
|
if err != nil {
|
return err
|
}
|
|
return os.WriteFile(path, data, 0644)
|
}
|
|
// ExecuteMigration 执行迁移
|
func ExecuteMigration(vaultPath string, plan *MigrationPlan) error {
|
for i, migration := range plan.Migrations {
|
fmt.Printf("[%d/%d] 移动 %s -> %s\n", i+1, len(plan.Migrations), migration.Source, migration.Target)
|
|
sourcePath := filepath.Join(vaultPath, migration.Source)
|
targetPath := filepath.Join(vaultPath, migration.Target)
|
|
// 检查源文件是否存在
|
if _, err := os.Stat(sourcePath); os.IsNotExist(err) {
|
fmt.Printf(" 跳过(源文件不存在)\n")
|
continue
|
}
|
|
// 创建目标目录
|
targetDir := filepath.Dir(targetPath)
|
if err := os.MkdirAll(targetDir, 0755); err != nil {
|
return fmt.Errorf("创建目录失败: %w", err)
|
}
|
|
// 使用 git mv 保留历史
|
cmd := exec.Command("git", "mv", sourcePath, targetPath)
|
cmd.Dir = vaultPath
|
if output, err := cmd.CombinedOutput(); err != nil {
|
return fmt.Errorf("git mv 失败: %w\n%s", err, output)
|
}
|
}
|
|
return nil
|
}
|