feat/add-database #8
7 changed files with 267 additions and 35 deletions
|
@ -18,7 +18,7 @@ func New() (*App, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
db.AutoMigrate(&models.Task{}, &models.GitRepoAltRepoTask{})
|
db.AutoMigrate(&models.Task{}, &models.GitRepoAltRepoTask{}, &models.RPMFile{})
|
||||||
|
|
||||||
db.FirstOrCreate(&models.ALTRepo{
|
db.FirstOrCreate(&models.ALTRepo{
|
||||||
Name: "Sisyphus",
|
Name: "Sisyphus",
|
||||||
|
|
|
@ -14,7 +14,7 @@ type CreateTaskDTO struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateTaskResponse struct {
|
type CreateTaskResponse struct {
|
||||||
TaskID int `json:"taskID"`
|
TaskID uint `json:"taskID"`
|
||||||
Status models.TaskStatus `json:"status"`
|
Status models.TaskStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,19 +7,23 @@ import (
|
||||||
type ALTRepo struct {
|
type ALTRepo struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
|
|
||||||
ID int
|
|
||||||
Name string `gorm:"uniqueIndex"`
|
Name string `gorm:"uniqueIndex"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GitRepo struct {
|
type GitRepo struct {
|
||||||
ID int
|
gorm.Model
|
||||||
|
|
||||||
Name string `gorm:"uniqueIndex"`
|
Name string `gorm:"uniqueIndex"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RPMFile struct {
|
type RPMFile struct {
|
||||||
|
gorm.Model
|
||||||
|
|
||||||
TaskID int
|
TaskID int
|
||||||
Name string
|
Task Task
|
||||||
Arch string
|
|
||||||
|
Name string
|
||||||
|
Arch string
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskStatus int
|
type TaskStatus int
|
||||||
|
@ -45,27 +49,29 @@ const (
|
||||||
type Task struct {
|
type Task struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
|
|
||||||
ID int
|
|
||||||
Status TaskStatus
|
Status TaskStatus
|
||||||
Type TaskType
|
Type TaskType
|
||||||
|
|
||||||
RepoID int
|
RepoID uint
|
||||||
Repo GitRepo
|
Repo *GitRepo
|
||||||
ALTRepoID int
|
ALTRepoID uint
|
||||||
ALTRepo ALTRepo
|
ALTRepo ALTRepo
|
||||||
|
|
||||||
Files []RPMFile
|
FilesRemoved bool
|
||||||
|
Files []RPMFile
|
||||||
}
|
}
|
||||||
|
|
||||||
type GitRepoAltRepoTask struct {
|
type GitRepoAltRepoTask struct {
|
||||||
gorm.Model
|
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"`
|
LastTaskID uint
|
||||||
Repo GitRepo
|
LastTask *Task
|
||||||
ALTRepoID int `gorm:"uniqueIndex:idx_gr_ar_gitaltrepotask"`
|
|
||||||
ALTRepo ALTRepo
|
CurrentTaskID uint
|
||||||
TaskID int
|
CurrentTask Task
|
||||||
Task 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/app"
|
||||||
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/controllers/taskcontroller"
|
"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/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"
|
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/services/taskservice"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,6 +29,9 @@ func (r *Router) Setup() *chi.Mux {
|
||||||
r.app,
|
r.app,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
repoService := reposervice.New(r.app)
|
||||||
|
repoService.ForceUpdate()
|
||||||
|
|
||||||
taskController := taskcontroller.New(
|
taskController := taskcontroller.New(
|
||||||
r.app,
|
r.app,
|
||||||
taskService,
|
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
|
package taskservice
|
||||||
|
|
||||||
import (
|
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/app"
|
||||||
|
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
app *app.App
|
app *app.App
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskUploadInput struct {
|
|
||||||
TaskID string
|
|
||||||
Repo string
|
|
||||||
|
|
||||||
Files []*multipart.FileHeader
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(app *app.App) *Service {
|
func New(app *app.App) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
app: app,
|
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"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
@ -14,6 +15,13 @@ import (
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TaskUploadInput struct {
|
||||||
|
TaskID string
|
||||||
|
Repo string
|
||||||
|
|
||||||
|
Files []*multipart.FileHeader
|
||||||
|
}
|
||||||
|
|
||||||
func getRPMArchitecture(filePath string) (string, error) {
|
func getRPMArchitecture(filePath string) (string, error) {
|
||||||
cmd := exec.Command("rpm", "-qp", "--queryformat", "%{ARCH}", filePath)
|
cmd := exec.Command("rpm", "-qp", "--queryformat", "%{ARCH}", filePath)
|
||||||
|
|
||||||
|
@ -34,11 +42,12 @@ func (s *Service) Upload(input *TaskUploadInput) error {
|
||||||
files := input.Files
|
files := input.Files
|
||||||
|
|
||||||
task := models.Task{}
|
task := models.Task{}
|
||||||
result := s.app.Db.Where(
|
result := s.app.Db.Preload("Repo").Where(
|
||||||
"id = ?", taskID,
|
"id = ?", taskID,
|
||||||
).Where(
|
|
||||||
"status = ?", models.StatusPending,
|
|
||||||
).First(&task)
|
).First(&task)
|
||||||
|
/*.Where(
|
||||||
|
"status = ?", models.StatusPending,
|
||||||
|
)*/
|
||||||
|
|
||||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
return result.Error
|
return result.Error
|
||||||
|
@ -47,8 +56,6 @@ func (s *Service) Upload(input *TaskUploadInput) error {
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%v", task.Status)
|
|
||||||
|
|
||||||
localPath := path.Join(input.TaskID)
|
localPath := path.Join(input.TaskID)
|
||||||
taskFolderPath := path.Join(s.app.Config.UploadDir, "tasks", localPath)
|
taskFolderPath := path.Join(s.app.Config.UploadDir, "tasks", localPath)
|
||||||
os.MkdirAll(taskFolderPath, os.ModePerm)
|
os.MkdirAll(taskFolderPath, os.ModePerm)
|
||||||
|
@ -91,7 +98,15 @@ func (s *Service) Upload(input *TaskUploadInput) error {
|
||||||
return err
|
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
|
task.Status = models.StatusCompleted
|
||||||
if err := s.app.Db.Save(&task).Error; err != nil {
|
s.onTaskComplete(&task)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue