feat: regenerate dependent versions after deletion

- Add RegenerateFullPackage function to rebuild single version's full package
- Add RegenerateDependentVersions function to handle cascade regeneration
- Call regeneration after deleting versions
- Each version maintains its own full package independently

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-01 12:10:30 +08:00
parent 551f4f1576
commit a17938c000
2 changed files with 100 additions and 0 deletions
@@ -8,6 +8,9 @@ import (
"os"
"path/filepath"
"time"
"verification-platform-backend/internal/database"
"verification-platform-backend/internal/model"
)
// MergePatchWithFullPackage 合并补丁包和全量包,生成新的全量包
@@ -70,6 +73,98 @@ func MergePatchWithFullPackage(fullPackagePath, patchPath string, appID, userID
return "/" + filepath.ToSlash(newFilePath), fileInfo.Size(), hash, nil
}
// RegenerateFullPackage 重新生成指定版本的完整包
// 用于版本删除后的回退
func RegenerateFullPackage(versionID uint) error {
var version model.Version
if err := database.DB.First(&version, versionID).Error; err != nil {
return fmt.Errorf("version not found: %v", err)
}
// 全量包:完整包就是自己
if version.UpdateType == "full" {
version.FullPackagePath = version.FilePath
version.FullPackageSize = version.FileSize
version.FullPackageHash = version.FileHash
} else if version.UpdateType == "patch" {
// 补丁包:需要找到新的基础版本
if version.BaseVersionID == nil {
return fmt.Errorf("patch version has no base version")
}
var baseVersion model.Version
if err := database.DB.First(&baseVersion, *version.BaseVersionID).Error; err != nil {
return fmt.Errorf("base version not found: %v", err)
}
// 确保基础版本有完整包
if baseVersion.FullPackagePath == "" {
if err := RegenerateFullPackage(baseVersion.ID); err != nil {
return fmt.Errorf("failed to regenerate base version: %v", err)
}
// 重新加载基础版本
database.DB.First(&baseVersion, *version.BaseVersionID)
}
// 合并生成新的完整包
fullPkgPath, fullPkgSize, fullPkgHash, err := MergePatchWithFullPackage(
baseVersion.FullPackagePath,
version.FilePath,
version.ApplicationID,
0, // userID 不重要,用于生成文件名
)
if err != nil {
return fmt.Errorf("failed to merge: %v", err)
}
version.FullPackagePath = fullPkgPath
version.FullPackageSize = fullPkgSize
version.FullPackageHash = fullPkgHash
}
// 保存更新
return database.DB.Model(&version).Updates(map[string]interface{}{
"full_package_path": version.FullPackagePath,
"full_package_size": version.FullPackageSize,
"full_package_hash": version.FullPackageHash,
}).Error
}
// RegenerateDependentVersions 重新生成所有依赖指定版本的后续版本
// 在删除版本时调用
func RegenerateDependentVersions(deletedVersionID uint) error {
// 找到所有以被删除版本为基础版本的版本
var dependentVersions []model.Version
if err := database.DB.Where("base_version_id = ?", deletedVersionID).Find(&dependentVersions).Error; err != nil {
return err
}
for _, dv := range dependentVersions {
log.Printf("[INFO] Regenerating dependent version %d after deletion of %d\n", dv.ID, deletedVersionID)
// 重新找到该应用最新的全量包作为新的基础
var newBaseVersion model.Version
if err := database.DB.Where("application_id = ? AND update_type = ? AND id != ? AND id < ?",
dv.ApplicationID, "full", dv.ID, dv.ID).
Order("id DESC").First(&newBaseVersion).Error; err == nil {
// 更新基础版本ID
dv.BaseVersionID = &newBaseVersion.ID
database.DB.Model(&dv).Update("base_version_id", newBaseVersion.ID)
}
// 重新生成完整包
if err := RegenerateFullPackage(dv.ID); err != nil {
log.Printf("[ERROR] Failed to regenerate version %d: %v\n", dv.ID, err)
continue
}
// 递归处理依赖这个版本的后续版本
RegenerateDependentVersions(dv.ID)
}
return nil
}
// extractZip 解压zip文件到指定目录
func extractZip(zipPath, destDir string) error {
r, err := zip.OpenReader(zipPath)
@@ -571,6 +571,11 @@ func handleBatchDeleteVersions(c *gin.Context) {
return
}
// 删除后重新生成依赖这些版本的后续版本
for _, id := range req.IDs {
RegenerateDependentVersions(id)
}
response.Success(c, nil)
}