package reposervice import ( "os" "path" "strconv" "gorm.io/gorm" "code.aides.space/aides-infra/aides-repo-api/internal/logger" "code.aides.space/aides-infra/aides-repo-api/internal/models" ) type Config interface { GetUploadDir() string } type Service struct { db *gorm.DB config Config } func New(db *gorm.DB, cfg Config) *Service { return &Service{ db: db, config: cfg, } } func (s *Service) futureRepoPathPrefix() string { return path.Join( s.config.GetUploadDir(), ".future_repo", ) } func (s *Service) currentRepoPathPrefix() string { return path.Join( s.config.GetUploadDir(), "repo", ) } func (s *Service) oldRepoPathPrefix() string { return path.Join( s.config.GetUploadDir(), ".old_repo", ) } func (s *Service) prepareForUpdate() error { err := os.MkdirAll(s.futureRepoPathPrefix(), os.ModePerm) if err != nil { return err } err = os.MkdirAll(s.oldRepoPathPrefix(), os.ModePerm) if err != nil { return err } err = os.MkdirAll(s.currentRepoPathPrefix(), os.ModePerm) if err != nil { return err } return nil } func (s *Service) cleanUpAfterUpdate() { os.RemoveAll(s.futureRepoPathPrefix()) os.RemoveAll(s.oldRepoPathPrefix()) } func (s *Service) Update(force bool) error { const REPO_NAME = "aides" const DISTRO_ID = "altlinux" architectures := []string{ "x86_64", "noarch", } repos := []string{ "Sisyphus", } log := logger.GetLogger() log.Info("Start repo update") preparedForUpdate := false for _, r := range repos { var tasks []models.Task altRepo := models.ALTRepo{ Name: r, } if err := s.db. Where(&altRepo). First(&altRepo).Error; err != nil { return err } var exists bool if err := s.db. Model(&models.GitRepoAltRepoTask{}). Select("1"). Where("alt_repo_id = ?", altRepo.ID). Where("last_task_id != current_task_id OR current_task_id IS NULL"). Limit(1). Scan(&exists).Error; err != nil { return err } if !force && !exists { log.Info( "No updates found for ALTRepo, skipping.", map[string]interface{}{ "repo": altRepo.Name, }) continue } if !preparedForUpdate { if err := s.prepareForUpdate(); err != nil { return err } defer s.cleanUpAfterUpdate() } preparedForUpdate = true s.db. Model(&models.GitRepoAltRepoTask{}). Select("tasks.*"). Joins("JOIN tasks ON tasks.id = git_repo_alt_repo_tasks.last_task_id"). Where(&models.GitRepoAltRepoTask{ ALTRepoID: altRepo.ID, }). Preload("Files"). Find(&tasks) futureRepoPath := path.Join( s.futureRepoPathPrefix(), DISTRO_ID, altRepo.Name, ) err := os.MkdirAll( futureRepoPath, os.ModePerm, ) if err != nil { return err } for _, arch := range architectures { err = createRepoDirs(futureRepoPath, REPO_NAME, arch) if err != nil { return err } } for _, el := range tasks { for _, fileInfo := range el.Files { localFilePath := path.Join( strconv.FormatUint(uint64(el.ID), 10), fileInfo.Filename, ) symLink := path.Join( futureRepoPath, fileInfo.Arch, "RPMS.aides", fileInfo.Filename, ) targetPath := path.Join("../../../../../tasks/", localFilePath) err := createSymlink(targetPath, symLink) if err != nil { return err } } } for _, arch := range architectures { err = runGenbasedir(futureRepoPath, arch, REPO_NAME) if err != nil { return err } } s.db. Model(&models.GitRepoAltRepoTask{}). Where(&models.GitRepoAltRepoTask{ ALTRepoID: altRepo.ID, }). Update( "current_task_id", gorm.Expr("last_task_id"), ) currentRepoPath := path.Join( s.currentRepoPathPrefix(), DISTRO_ID, altRepo.Name, ) oldRepoPath := path.Join( s.oldRepoPathPrefix(), DISTRO_ID, altRepo.Name, ) if err := renameIfExists( currentRepoPath, oldRepoPath, ); err != nil { return err } if err := renameIfExists( futureRepoPath, currentRepoPath, ); err != nil { return err } } log.Info("Successful repo update") return nil }