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 }