feat: add repo creation
This commit is contained in:
parent
0fedac8e93
commit
26c751ccb7
7 changed files with 267 additions and 35 deletions
|
@ -18,7 +18,7 @@ func New() (*App, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
db.AutoMigrate(&models.Task{}, &models.GitRepoAltRepoTask{})
|
||||
db.AutoMigrate(&models.Task{}, &models.GitRepoAltRepoTask{}, &models.RPMFile{})
|
||||
|
||||
db.FirstOrCreate(&models.ALTRepo{
|
||||
Name: "Sisyphus",
|
||||
|
|
|
@ -14,7 +14,7 @@ type CreateTaskDTO struct {
|
|||
}
|
||||
|
||||
type CreateTaskResponse struct {
|
||||
TaskID int `json:"taskID"`
|
||||
TaskID uint `json:"taskID"`
|
||||
Status models.TaskStatus `json:"status"`
|
||||
}
|
||||
|
||||
|
|
|
@ -7,17 +7,21 @@ import (
|
|||
type ALTRepo struct {
|
||||
gorm.Model
|
||||
|
||||
ID int
|
||||
Name string `gorm:"uniqueIndex"`
|
||||
}
|
||||
|
||||
type GitRepo struct {
|
||||
ID int
|
||||
gorm.Model
|
||||
|
||||
Name string `gorm:"uniqueIndex"`
|
||||
}
|
||||
|
||||
type RPMFile struct {
|
||||
gorm.Model
|
||||
|
||||
TaskID int
|
||||
Task Task
|
||||
|
||||
Name string
|
||||
Arch string
|
||||
}
|
||||
|
@ -45,27 +49,29 @@ const (
|
|||
type Task struct {
|
||||
gorm.Model
|
||||
|
||||
ID int
|
||||
Status TaskStatus
|
||||
Type TaskType
|
||||
|
||||
RepoID int
|
||||
Repo GitRepo
|
||||
ALTRepoID int
|
||||
RepoID uint
|
||||
Repo *GitRepo
|
||||
ALTRepoID uint
|
||||
ALTRepo ALTRepo
|
||||
|
||||
FilesRemoved bool
|
||||
Files []RPMFile
|
||||
}
|
||||
|
||||
type GitRepoAltRepoTask struct {
|
||||
gorm.Model
|
||||
|
||||
ID int
|
||||
RepoID uint `gorm:"uniqueIndex:idx_gr_ar_gitaltrepotask"`
|
||||
Repo *GitRepo
|
||||
ALTRepoID uint `gorm:"uniqueIndex:idx_gr_ar_gitaltrepotask"`
|
||||
ALTRepo *ALTRepo
|
||||
|
||||
RepoID int `gorm:"uniqueIndex:idx_gr_ar_gitaltrepotask"`
|
||||
Repo GitRepo
|
||||
ALTRepoID int `gorm:"uniqueIndex:idx_gr_ar_gitaltrepotask"`
|
||||
ALTRepo ALTRepo
|
||||
TaskID int
|
||||
Task Task
|
||||
LastTaskID uint
|
||||
LastTask *Task
|
||||
|
||||
CurrentTaskID uint
|
||||
CurrentTask Task
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/app"
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/controllers/taskcontroller"
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/middlewares"
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/services/reposervice"
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/services/taskservice"
|
||||
)
|
||||
|
||||
|
@ -28,6 +29,9 @@ func (r *Router) Setup() *chi.Mux {
|
|||
r.app,
|
||||
)
|
||||
|
||||
repoService := reposervice.New(r.app)
|
||||
repoService.ForceUpdate()
|
||||
|
||||
taskController := taskcontroller.New(
|
||||
r.app,
|
||||
taskService,
|
||||
|
|
134
internal/services/reposervice/service.go
Normal file
134
internal/services/reposervice/service.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
package reposervice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/app"
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
app *app.App
|
||||
}
|
||||
|
||||
func New(app *app.App) *Service {
|
||||
return &Service{
|
||||
app: app,
|
||||
}
|
||||
}
|
||||
|
||||
func createSymlink(target, link string) error {
|
||||
if _, err := os.Lstat(link); err == nil {
|
||||
if err := os.Remove(link); err != nil {
|
||||
return fmt.Errorf("failed to remove existing file or symlink: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Symlink(target, link); err != nil {
|
||||
return fmt.Errorf("failed to create symlink: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runGenbasedir(repoDir, arch, repoName string) {
|
||||
cmd := exec.Command("genbasedir", "--bloat", "--progress", fmt.Sprintf("--topdir=%s", repoDir), arch, repoName)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to run genbasedir for %s: %v\n", arch, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Successfully ran genbasedir for %s\n", arch)
|
||||
}
|
||||
|
||||
func createRepoDirs(repoDir, repoName, arch string) {
|
||||
// Create the 'base' directory
|
||||
baseDir := path.Join(repoDir, arch, "base")
|
||||
err := os.MkdirAll(baseDir, os.ModePerm)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to create directory %s: %v\n", baseDir, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Create the 'RPMS.<REPO_NAME>' directory
|
||||
rpmsDir := path.Join(repoDir, arch, fmt.Sprintf("RPMS.%s", repoName))
|
||||
err = os.MkdirAll(rpmsDir, os.ModePerm)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to create directory %s: %v\n", rpmsDir, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) ForceUpdate() {
|
||||
var tasks []models.Task
|
||||
altRepo := models.ALTRepo{
|
||||
Name: "Sisyphus",
|
||||
}
|
||||
|
||||
s.app.Db.
|
||||
Where(&altRepo).
|
||||
First(&altRepo)
|
||||
|
||||
s.app.Db.Debug().
|
||||
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)
|
||||
|
||||
repoPath := path.Join(s.app.Config.UploadDir, "future_repo", "Sisyphus")
|
||||
|
||||
os.MkdirAll(
|
||||
repoPath,
|
||||
os.ModePerm,
|
||||
)
|
||||
|
||||
repoName := "aides"
|
||||
architectures := []string{"x86_64", "noarch"}
|
||||
|
||||
for _, arch := range architectures {
|
||||
createRepoDirs(repoPath, repoName, arch)
|
||||
}
|
||||
|
||||
for _, el := range tasks {
|
||||
fmt.Println(el.Files)
|
||||
|
||||
taskPath := path.Join(
|
||||
s.app.Config.UploadDir, "tasks", strconv.FormatUint(uint64(el.ID), 10),
|
||||
)
|
||||
|
||||
for _, fileInfo := range el.Files {
|
||||
localFilePath := path.Join(
|
||||
strconv.FormatUint(uint64(el.ID), 10), fileInfo.Name,
|
||||
)
|
||||
symLink := path.Join(s.app.Config.UploadDir, "future_repo", "Sisyphus", fileInfo.Arch, "RPMS.aides", fileInfo.Name)
|
||||
targetPath := path.Join("../../../../tasks/", localFilePath)
|
||||
createSymlink(targetPath, symLink)
|
||||
|
||||
fmt.Println(path.Join(taskPath, fileInfo.Name))
|
||||
}
|
||||
}
|
||||
|
||||
for _, arch := range architectures {
|
||||
runGenbasedir(repoPath, arch, repoName)
|
||||
}
|
||||
|
||||
s.app.Db.Debug().
|
||||
Model(&models.GitRepoAltRepoTask{}).
|
||||
Where(&models.GitRepoAltRepoTask{
|
||||
ALTRepoID: altRepo.ID,
|
||||
}).
|
||||
Update(
|
||||
"current_task_id", gorm.Expr("last_task_id"),
|
||||
)
|
||||
}
|
|
@ -1,24 +1,99 @@
|
|||
package taskservice
|
||||
|
||||
import (
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/app"
|
||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/models"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
app *app.App
|
||||
}
|
||||
|
||||
type TaskUploadInput struct {
|
||||
TaskID string
|
||||
Repo string
|
||||
|
||||
Files []*multipart.FileHeader
|
||||
}
|
||||
|
||||
func New(app *app.App) *Service {
|
||||
return &Service{
|
||||
app: app,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) onTaskComplete(task *models.Task) error {
|
||||
if err := s.app.Db.Save(&task).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
grart := models.GitRepoAltRepoTask{
|
||||
ALTRepoID: 1,
|
||||
Repo: task.Repo,
|
||||
}
|
||||
s.app.Db.Debug().Where(
|
||||
&grart,
|
||||
).FirstOrCreate(&grart)
|
||||
|
||||
grart.LastTaskID = task.ID
|
||||
|
||||
if err := s.app.Db.Save(&grart).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.tasksCleanup(&grart, 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) tasksCleanup(r *models.GitRepoAltRepoTask, N int) {
|
||||
excludedTaskIDs := []uint{}
|
||||
if r.CurrentTaskID != 0 {
|
||||
excludedTaskIDs = append(excludedTaskIDs, r.CurrentTaskID)
|
||||
}
|
||||
if r.LastTaskID != 0 {
|
||||
excludedTaskIDs = append(excludedTaskIDs, r.LastTaskID)
|
||||
}
|
||||
|
||||
var lastNTaskIDs []uint
|
||||
s.app.Db.
|
||||
Debug().
|
||||
Table("tasks").
|
||||
Select("id").
|
||||
Where("repo_id = ?", r.ID).
|
||||
Where("status = ?", models.StatusCompleted).
|
||||
Where("id NOT IN ?", excludedTaskIDs).
|
||||
Order("created_at DESC").
|
||||
Limit(N).
|
||||
Pluck("id", &lastNTaskIDs)
|
||||
|
||||
excludedTaskIDs = append(excludedTaskIDs, lastNTaskIDs...)
|
||||
|
||||
var taskIDsToDelete []int
|
||||
s.app.Db.
|
||||
Debug().
|
||||
Model(&models.Task{}).
|
||||
Select("id").
|
||||
Where("repo_id = ?", r.RepoID).
|
||||
Where("files_removed = ?", false).
|
||||
Where("id NOT IN ?", excludedTaskIDs).
|
||||
Pluck("id", &taskIDsToDelete)
|
||||
|
||||
if len(taskIDsToDelete) > 0 {
|
||||
s.app.Db.
|
||||
Debug().
|
||||
Model(&models.Task{}).
|
||||
Where("id IN ?", taskIDsToDelete).
|
||||
Update("files_removed", true)
|
||||
|
||||
for _, id := range taskIDsToDelete {
|
||||
s.removeTaskFiles(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) removeTaskFiles(taskId int) {
|
||||
taskFolderPath := path.Join(
|
||||
s.app.Config.UploadDir,
|
||||
"tasks",
|
||||
strconv.Itoa(taskId),
|
||||
)
|
||||
os.RemoveAll(taskFolderPath)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
@ -14,6 +15,13 @@ import (
|
|||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TaskUploadInput struct {
|
||||
TaskID string
|
||||
Repo string
|
||||
|
||||
Files []*multipart.FileHeader
|
||||
}
|
||||
|
||||
func getRPMArchitecture(filePath string) (string, error) {
|
||||
cmd := exec.Command("rpm", "-qp", "--queryformat", "%{ARCH}", filePath)
|
||||
|
||||
|
@ -34,11 +42,12 @@ func (s *Service) Upload(input *TaskUploadInput) error {
|
|||
files := input.Files
|
||||
|
||||
task := models.Task{}
|
||||
result := s.app.Db.Where(
|
||||
result := s.app.Db.Preload("Repo").Where(
|
||||
"id = ?", taskID,
|
||||
).Where(
|
||||
"status = ?", models.StatusPending,
|
||||
).First(&task)
|
||||
/*.Where(
|
||||
"status = ?", models.StatusPending,
|
||||
)*/
|
||||
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
return result.Error
|
||||
|
@ -47,8 +56,6 @@ func (s *Service) Upload(input *TaskUploadInput) error {
|
|||
return result.Error
|
||||
}
|
||||
|
||||
fmt.Printf("%v", task.Status)
|
||||
|
||||
localPath := path.Join(input.TaskID)
|
||||
taskFolderPath := path.Join(s.app.Config.UploadDir, "tasks", localPath)
|
||||
os.MkdirAll(taskFolderPath, os.ModePerm)
|
||||
|
@ -91,7 +98,15 @@ func (s *Service) Upload(input *TaskUploadInput) error {
|
|||
return err
|
||||
}
|
||||
|
||||
fmt.Println(arch)
|
||||
f := models.RPMFile{
|
||||
Name: fileHeader.Filename,
|
||||
Arch: arch,
|
||||
Task: task,
|
||||
}
|
||||
|
||||
if err := s.app.Db.Save(&f).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Символическая ссылка
|
||||
/*
|
||||
|
@ -106,9 +121,7 @@ func (s *Service) Upload(input *TaskUploadInput) error {
|
|||
}
|
||||
|
||||
task.Status = models.StatusCompleted
|
||||
if err := s.app.Db.Save(&task).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
s.onTaskComplete(&task)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue