clonepack/internal/core/clone.go
GnomeZworc c4776d81dd
add apt gestion
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
2026-04-25 19:03:26 +02:00

103 lines
2.8 KiB
Go

package core
import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"path/filepath"
aptclone "github.com/syonad/clonepack/internal/clone/apt"
"github.com/syonad/clonepack/internal/clone/rpm"
"github.com/syonad/clonepack/internal/store"
)
var ErrCloneAlreadyRunning = errors.New("a clone job is already running for this repo")
type CloneService struct {
repoStore store.RepoStore
jobStore store.CloneJobStore
dataDir string
}
func NewCloneService(repoStore store.RepoStore, jobStore store.CloneJobStore, dataDir string) *CloneService {
return &CloneService{repoStore: repoStore, jobStore: jobStore, dataDir: dataDir}
}
func (s *CloneService) StartClone(ctx context.Context, repoID int64) (int64, error) {
repo, err := s.repoStore.GetRepo(ctx, repoID)
if err != nil {
return 0, err
}
if repo.Type != "rpm" && repo.Type != "apt" {
return 0, fmt.Errorf("clone is only supported for rpm and apt repositories")
}
running, err := s.jobStore.HasRunningCloneJob(ctx, repoID)
if err != nil {
return 0, err
}
if running {
return 0, ErrCloneAlreadyRunning
}
jobID, err := s.jobStore.CreateCloneJob(ctx, repoID)
if err != nil {
return 0, err
}
go s.runClone(repoID, jobID, repo)
return jobID, nil
}
func (s *CloneService) GetLatestCloneJob(ctx context.Context, repoID int64) (*store.CloneJob, error) {
return s.jobStore.GetLatestCloneJob(ctx, repoID)
}
func (s *CloneService) runClone(repoID, jobID int64, repo *store.Repo) {
ctx := context.Background()
if err := s.jobStore.MarkCloneJobStarted(ctx, jobID); err != nil {
log.Printf("clone job %d: failed to mark started: %v", jobID, err)
return
}
destDir := filepath.Join(s.dataDir, "repos", fmt.Sprintf("%d", repoID), repo.Type)
var cloneErr error
switch repo.Type {
case "rpm":
cloner := rpm.New(repo.SourceURL, destDir)
cloner.OnProgress = func(p rpm.Progress) {
log.Printf("clone job %d: %s (%d bytes)", jobID, p.File, p.BytesDone)
}
if err := cloner.Clone(ctx); err != nil {
cloneErr = err
} else if err := rpm.RegenerateMetadata(destDir); err != nil {
log.Printf("clone job %d: metadata regeneration failed: %v", jobID, err)
}
case "apt":
var cfg aptclone.Config
if err := json.Unmarshal([]byte(repo.Config), &cfg); err != nil {
cloneErr = fmt.Errorf("parse apt config: %w", err)
break
}
cloner := aptclone.New(repo.SourceURL, destDir, cfg)
cloner.OnProgress = func(file string, bytes int64) {
log.Printf("clone job %d: %s (%d bytes)", jobID, file, bytes)
}
cloneErr = cloner.Clone(ctx)
}
if cloneErr != nil {
errMsg := cloneErr.Error()
_ = s.jobStore.MarkCloneJobFinished(ctx, jobID, store.CloneJobFailed, &errMsg)
log.Printf("clone job %d: failed: %v", jobID, cloneErr)
return
}
_ = s.jobStore.MarkCloneJobFinished(ctx, jobID, store.CloneJobCompleted, nil)
log.Printf("clone job %d: completed", jobID)
}