refactor
Some checks failed
Format and Lint / format-check (push) Has been cancelled

This commit is contained in:
Максим Слипенко 2024-12-24 22:40:37 +03:00
parent db49ea2c51
commit 6693ceabcc
8 changed files with 275 additions and 167 deletions

View file

@ -1,4 +1,3 @@
.git
app.db app.db
uploads uploads
Dockerfile Dockerfile

View file

@ -5,7 +5,10 @@ WORKDIR /app
COPY go.mod go.sum ./ COPY go.mod go.sum ./
RUN go mod download RUN go mod download
COPY . . COPY . .
RUN make release
ARG APP_VERSION
RUN make build
FROM registry.altlinux.org/sisyphus/alt:20241211 FROM registry.altlinux.org/sisyphus/alt:20241211

View file

@ -1,7 +1,10 @@
GIT_VERSION = $(shell git describe --tags )
GOLANGCI_LINT := go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2 GOLANGCI_LINT := go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2
SWAG := go run github.com/swaggo/swag/cmd/swag@v1.16.4 SWAG := go run github.com/swaggo/swag/cmd/swag@v1.16.4
GIT_VERSION = $(shell git describe --tags)
APP_VERSION ?= $(GIT_VERSION)
DOCKER_TAG ?= $(APP_VERSION)
format: format:
@echo "🛠️ Format and Lint code with golangci-lint" @echo "🛠️ Format and Lint code with golangci-lint"
$(GOLANGCI_LINT) run $(GOLANGCI_LINT) run
@ -19,16 +22,19 @@ swag:
build: build:
go build \ go build \
-ldflags="-X 'code.alt-gnome.ru/aides-infra/aides-repo-api/internal/config.Version=$(GIT_VERSION)'" \ -ldflags="-X 'code.alt-gnome.ru/aides-infra/aides-repo-api/internal/config.Version=$(APP_VERSION)'" \
-o aides-repo-api \ -o aides-repo-api \
./cmd/aides-repo-api/main.go ./cmd/aides-repo-api/main.go
release: release:
go build \ go build \
-ldflags="-s -w -X 'code.alt-gnome.ru/aides-infra/aides-repo-api/internal/config.Version=$(GIT_VERSION)'" \ -ldflags="-s -w -X 'code.alt-gnome.ru/aides-infra/aides-repo-api/internal/config.Version=$(APP_VERSION)'" \
-o aides-repo-api \ -o aides-repo-api \
./cmd/aides-repo-api/main.go ./cmd/aides-repo-api/main.go
build-docker: build-docker:
docker build -t ghcr.io/aides-infra/aides-repo-api . docker build \
--build-arg APP_VERSION=${APP_VERSION} \
-t ghcr.io/aides-infra/aides-repo-api:${DOCKER_TAG}\
.

View file

@ -22,6 +22,6 @@ func main() {
} }
app.Init() app.Init()
defer app.Shutdown()
app.Run() app.Run()
} }

View file

@ -121,10 +121,20 @@ func (app *App) Run() {
}, },
) )
app.repo.ForceUpdate() err := app.repo.ForceUpdate()
if err != nil {
panic(err)
}
err := http.ListenAndServe(fmt.Sprintf(":%d", app.config.Port), app.router.Setup()) err = http.ListenAndServe(
fmt.Sprintf(":%d", app.config.Port),
app.router.Setup(),
)
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
func (app *App) Shutdown() {
app.cron.Shutdown()
}

View file

@ -1,15 +1,13 @@
package cronservice package cronservice
import ( import (
"log"
"github.com/go-co-op/gocron/v2" "github.com/go-co-op/gocron/v2"
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/logger" "code.alt-gnome.ru/aides-infra/aides-repo-api/internal/logger"
) )
type RepoService interface { type RepoService interface {
ForceUpdate() ForceUpdate() error
} }
type Service struct { type Service struct {
@ -19,9 +17,12 @@ type Service struct {
} }
func New(repo RepoService) *Service { func New(repo RepoService) *Service {
log := logger.GetLogger()
scheduler, err := gocron.NewScheduler() scheduler, err := gocron.NewScheduler()
if err != nil { if err != nil {
log.Fatalf("Не удалось создать планировщик: %v", err) log.Fatal("Не удалось создать планировщик", map[string]interface{}{
"err": err,
})
} }
return &Service{ return &Service{
@ -31,18 +32,25 @@ func New(repo RepoService) *Service {
} }
func (s *Service) SetupCronJobs() { func (s *Service) SetupCronJobs() {
log := logger.GetLogger()
_, err := s.scheduler.NewJob( _, err := s.scheduler.NewJob(
gocron.CronJob("0 4 * * *", false), gocron.CronJob("0 4 * * *", false),
gocron.NewTask(func() { gocron.NewTask(func() {
log := logger.GetLogger()
log.Info( log.Info(
"[cron] force update is started", "[cron] force update is started",
) )
s.repoService.ForceUpdate() err := s.repoService.ForceUpdate()
if err != nil {
log.Error("[cron] force update error", map[string]interface{}{
"err": err,
})
}
}), }),
) )
if err != nil { if err != nil {
log.Printf("Не удалось создать задание cron: %v", err) log.Fatal("Не удалось создать задание cron", map[string]interface{}{
"err": err,
})
} }
} }
@ -51,8 +59,11 @@ func (s *Service) Start() {
} }
func (s *Service) Shutdown() { func (s *Service) Shutdown() {
log := logger.GetLogger()
err := s.scheduler.Shutdown() err := s.scheduler.Shutdown()
if err != nil { if err != nil {
log.Printf("Не удалось корректно завершить работу планировщика: %v", err) log.Error("Не удалось корректно завершить работу планировщика", map[string]interface{}{
"err": err,
})
} }
} }

View file

@ -1,9 +1,7 @@
package reposervice package reposervice
import ( import (
"fmt"
"os" "os"
"os/exec"
"path" "path"
"strconv" "strconv"
@ -29,170 +27,160 @@ func New(db *gorm.DB, cfg Config) *Service {
} }
} }
func createSymlink(target, link string) error { func (s *Service) futureRepoPathPrefix() string {
if _, err := os.Lstat(link); err == nil { return path.Join(
if err := os.Remove(link); err != nil { s.config.GetUploadDir(),
return fmt.Errorf("failed to remove existing file or symlink: %w", err) ".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) ForceUpdate() error {
const REPO_NAME = "aides"
architectures := []string{
"x86_64",
"noarch",
}
repos := []string{
"Sisyphus",
}
log := logger.GetLogger()
log.Info("Start repo update")
err := os.MkdirAll(s.futureRepoPathPrefix(), os.ModePerm)
if err != nil {
return err
}
defer os.RemoveAll(s.futureRepoPathPrefix())
err = os.MkdirAll(s.oldRepoPathPrefix(), os.ModePerm)
if err != nil {
return err
}
defer os.RemoveAll(s.oldRepoPathPrefix())
err = os.MkdirAll(s.currentRepoPathPrefix(), os.ModePerm)
if err != nil {
return err
}
for _, r := range repos {
var tasks []models.Task
altRepo := models.ALTRepo{
Name: r,
} }
}
if err := os.Symlink(target, link); err != nil { s.db.
return fmt.Errorf("failed to create symlink: %w", err) Where(&altRepo).
} First(&altRepo)
return nil 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)
func runGenbasedir(repoDir, arch, repoName string) { futureRepoPath := path.Join(
log := logger.GetLogger() s.futureRepoPathPrefix(),
cmd := exec.Command( altRepo.Name,
"genbasedir",
"--bloat",
"--progress",
fmt.Sprintf("--topdir=%s", repoDir),
arch,
repoName,
)
cmd.Stdout = nil
cmd.Stderr = nil
err := cmd.Run()
if err != nil {
log.Error(
"Failed to run genbasedir",
map[string]interface{}{
"arch": arch,
"error": err,
},
) )
os.Exit(1)
}
log.Info("Successfully ran genbasedir", map[string]interface{}{
"arch": arch,
})
}
func createRepoDirs(repoDir, repoName, arch string) { err := os.MkdirAll(
log := logger.GetLogger() futureRepoPath,
// Create the 'base' directory os.ModePerm,
baseDir := path.Join(repoDir, arch, "base") )
err := os.MkdirAll(baseDir, os.ModePerm) if err != nil {
if err != nil { return err
log.Error("Failed to create directory", map[string]interface{}{ }
"directory": baseDir,
"err": err,
})
os.Exit(1)
}
// Create the 'RPMS.<REPO_NAME>' directory for _, arch := range architectures {
rpmsDir := path.Join(repoDir, arch, fmt.Sprintf("RPMS.%s", repoName)) err = createRepoDirs(futureRepoPath, REPO_NAME, arch)
err = os.MkdirAll(rpmsDir, os.ModePerm)
if err != nil {
log.Error("Failed to create directory", map[string]interface{}{
"directory": rpmsDir,
"err": err,
})
os.Exit(1)
}
}
func (s *Service) ForceUpdate() {
var tasks []models.Task
altRepo := models.ALTRepo{
Name: "Sisyphus",
}
s.db.
Where(&altRepo).
First(&altRepo)
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)
repoPath := path.Join(s.config.GetUploadDir(), "future_repo", "Sisyphus")
err := os.MkdirAll(
repoPath,
os.ModePerm,
)
if err != nil {
panic(err)
}
repoName := "aides"
architectures := []string{"x86_64", "noarch"}
for _, arch := range architectures {
createRepoDirs(repoPath, repoName, arch)
}
for _, el := range tasks {
for _, fileInfo := range el.Files {
localFilePath := path.Join(
strconv.FormatUint(uint64(el.ID), 10), fileInfo.Name,
)
symLink := path.Join(
s.config.GetUploadDir(),
"future_repo",
"Sisyphus",
fileInfo.Arch,
"RPMS.aides",
fileInfo.Name,
)
targetPath := path.Join("../../../../tasks/", localFilePath)
err := createSymlink(targetPath, symLink)
if err != nil { if err != nil {
panic(err) return err
} }
} }
}
for _, arch := range architectures { for _, el := range tasks {
runGenbasedir(repoPath, arch, repoName) for _, fileInfo := range el.Files {
} localFilePath := path.Join(
strconv.FormatUint(uint64(el.ID), 10), fileInfo.Name,
)
symLink := path.Join(
futureRepoPath,
fileInfo.Arch,
"RPMS.aides",
fileInfo.Name,
)
targetPath := path.Join("../../../../tasks/", localFilePath)
err := createSymlink(targetPath, symLink)
if err != nil {
return err
}
}
}
s.db. for _, arch := range architectures {
Model(&models.GitRepoAltRepoTask{}). err = runGenbasedir(futureRepoPath, arch, REPO_NAME)
Where(&models.GitRepoAltRepoTask{ if err != nil {
ALTRepoID: altRepo.ID, return err
}). }
Update( }
"current_task_id", gorm.Expr("last_task_id"),
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(),
altRepo.Name,
) )
err = os.MkdirAll(path.Join(s.config.GetUploadDir(), "repo"), os.ModePerm) oldRepoPath := path.Join(
if err != nil { s.oldRepoPathPrefix(),
panic(err) altRepo.Name,
} )
aPath := path.Join(s.config.GetUploadDir(), "future_repo", "Sisyphus") if err := renameIfExists(
bPath := path.Join(s.config.GetUploadDir(), "repo", "Sisyphus") currentRepoPath,
cPath := path.Join(s.config.GetUploadDir(), "repo", ".Sisyphus") oldRepoPath,
); err != nil {
if _, err := os.Stat(bPath); err == nil { return err
if err := os.Rename(bPath, cPath); err != nil {
panic(err)
} }
} else if !os.IsNotExist(err) {
panic(err) if err := os.Rename(
futureRepoPath,
currentRepoPath,
); err != nil {
return err
}
} }
if err := os.Rename(aPath, bPath); err != nil { log.Info("Successful repo update")
panic(err) return nil
}
if err := os.RemoveAll(cPath); err != nil {
panic(err)
}
if err := os.RemoveAll(path.Join(s.config.GetUploadDir(), "future_repo")); err != nil {
panic(err)
}
} }

View file

@ -0,0 +1,91 @@
package reposervice
import (
"fmt"
"os"
"os/exec"
"path"
"code.alt-gnome.ru/aides-infra/aides-repo-api/internal/logger"
)
func createRepoDirs(repoDir, repoName, arch string) error {
log := logger.GetLogger()
// Create the 'base' directory
baseDir := path.Join(repoDir, arch, "base")
err := os.MkdirAll(baseDir, os.ModePerm)
if err != nil {
log.Error("Failed to create directory", map[string]interface{}{
"directory": baseDir,
"err": err,
})
return err
}
// 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 {
log.Error("Failed to create directory", map[string]interface{}{
"directory": rpmsDir,
"err": err,
})
return err
}
return nil
}
func runGenbasedir(repoDir, arch, repoName string) error {
log := logger.GetLogger()
cmd := exec.Command(
"genbasedir",
"--bloat",
"--progress",
fmt.Sprintf("--topdir=%s", repoDir),
arch,
repoName,
)
cmd.Stdout = nil
cmd.Stderr = nil
err := cmd.Run()
if err != nil {
log.Error(
"Failed to run genbasedir",
map[string]interface{}{
"arch": arch,
"error": err,
"cmd_error": cmd.Stderr,
},
)
return err
}
log.Debug("Successfully ran genbasedir", map[string]interface{}{
"arch": arch,
})
return nil
}
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 renameIfExists(oldPath, newPath string) error {
if _, err := os.Stat(oldPath); err == nil {
return os.Rename(oldPath, newPath)
} else if !os.IsNotExist(err) {
return err
}
return nil
}