aides-repo-api/internal/services/taskservice/upload.go
Maxim Slipenko 939f14eb86
Some checks failed
Format and Lint / format-check (push) Failing after 4s
Format and Lint / test (push) Successful in 53s
fix: reduce memory usage
2025-01-08 15:30:48 +03:00

169 lines
3.4 KiB
Go

package taskservice
import (
"errors"
"fmt"
"io"
"mime/multipart"
"os"
"path"
"strconv"
"strings"
"github.com/cavaliergopher/rpm"
"gorm.io/gorm"
"code.aides.space/aides-infra/aides-repo-api/internal/logger"
"code.aides.space/aides-infra/aides-repo-api/internal/models"
)
type TaskUploadInput struct {
TaskID string
Files []*multipart.FileHeader
}
func (s *Service) Upload(input *TaskUploadInput) error {
log := logger.GetLogger()
taskID, err := strconv.Atoi(input.TaskID)
if err != nil {
return err
}
files := input.Files
task := models.Task{}
result := s.db.
Preload("Repo").
Where("id = ?", taskID).
First(&task).
Where("status = ?", models.StatusPending)
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return result.Error
}
if result.Error != nil {
return result.Error
}
currentTask := &models.Task{}
result = s.db.
Model(&models.GitRepoAltRepoTask{}).
Select("tasks.*").
Joins("JOIN tasks ON tasks.id = git_repo_alt_repo_tasks.current_task_id").
Where(&models.GitRepoAltRepoTask{
ALTRepoID: task.ALTRepoID,
RepoID: task.RepoID,
}).
Preload("Files").
Limit(1).
Find(currentTask)
if result.Error != nil {
return result.Error
}
log.Debug("", map[string]interface{}{
"val": currentTask,
})
localPath := path.Join(input.TaskID)
taskFolderPath := path.Join(s.config.GetUploadDir(), "tasks", localPath)
err = os.MkdirAll(taskFolderPath, os.ModePerm)
if err != nil {
return err
}
shouldCleanTask := true
defer func() {
if shouldCleanTask {
os.RemoveAll(taskFolderPath)
}
}()
rpmFiles := []models.RPMFile{}
for _, fileHeader := range files {
file, err := fileHeader.Open()
if err != nil {
return fmt.Errorf("can't open fileHeader %w", err)
}
if !strings.HasSuffix(fileHeader.Filename, ".rpm") {
return fmt.Errorf("invalid file type: only .rpm files are allowed")
}
// Полный путь для файла
filePath := path.Join(taskFolderPath, fileHeader.Filename)
// Удаляем файл если такой уже существует
if _, err := os.Stat(filePath); err == nil {
err = os.Remove(filePath)
if err != nil {
return err
}
}
// Сохранение файла на сервере
outFile, err := os.Create(filePath)
if err != nil {
return err
}
_, err = io.Copy(outFile, file)
if err != nil {
return err
}
outFile.Close()
file.Close()
pkg, err := rpm.Open(filePath)
if err != nil {
return err
}
f := models.RPMFile{
Filename: fileHeader.Filename,
Name: pkg.Name(),
Arch: pkg.Architecture(),
Version: pkg.Version(),
Release: pkg.Release(),
Epoch: pkg.Epoch(),
Task: task,
}
rpmFiles = append(rpmFiles, f)
}
if currentTask.ID != 0 {
groupedByName := make(map[string][]*models.RPMFile)
for _, file := range rpmFiles {
groupedByName[file.Name] = append(groupedByName[file.Name], &file)
}
for _, file := range currentTask.Files {
groupedByName[file.Name] = append(groupedByName[file.Name], &file)
}
for name, group := range groupedByName {
if len(group) > 1 {
result := rpm.Compare(
&WrapperRpmVersion{group[0]},
&WrapperRpmVersion{group[1]},
)
if result < 1 {
return &TooOldError{
Name: name,
}
}
}
}
}
result = s.db.Create(&rpmFiles)
if result.Error != nil {
return result.Error
}
task.Status = models.StatusCompleted
shouldCleanTask = false
return s.onTaskComplete(&task)
}