add apt gestion

Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
GnomeZworc 2026-04-25 19:03:26 +02:00
commit c4776d81dd
Signed by: nicolas.boufideline
GPG key ID: 4406BBBF8845D632
22 changed files with 1465 additions and 163 deletions

View file

@ -2,10 +2,12 @@ package core
import (
"context"
"encoding/json"
"fmt"
"log"
"path/filepath"
aptclone "github.com/syonad/clonepack/internal/clone/apt"
rpmclone "github.com/syonad/clonepack/internal/clone/rpm"
"github.com/syonad/clonepack/internal/store"
)
@ -24,10 +26,13 @@ func NewRepoService(s store.RepoStore, dataDir string) *RepoService {
var validSyncModes = map[string]bool{"auto": true, "manual": true}
type CreateRepoInput struct {
Name string `json:"name"`
Type string `json:"type"`
SourceURL string `json:"source_url"`
SyncMode string `json:"sync_mode"`
Name string `json:"name"`
Type string `json:"type"`
SourceURL string `json:"source_url"`
SyncMode string `json:"sync_mode"`
AptSuite string `json:"apt_suite,omitempty"`
AptComponents []string `json:"apt_components,omitempty"`
AptArchitectures []string `json:"apt_architectures,omitempty"`
}
func (s *RepoService) Create(ctx context.Context, in CreateRepoInput) (*store.Repo, error) {
@ -46,7 +51,30 @@ func (s *RepoService) Create(ctx context.Context, in CreateRepoInput) (*store.Re
return nil, fmt.Errorf("invalid sync_mode: %s (must be auto or manual)", in.SyncMode)
}
r := &store.Repo{Name: in.Name, Type: in.Type, SourceURL: in.SourceURL, SyncMode: in.SyncMode}
var configJSON string
if in.Type == "apt" {
if in.AptSuite == "" {
return nil, fmt.Errorf("apt_suite is required for apt repositories")
}
if len(in.AptComponents) == 0 {
in.AptComponents = []string{"main"}
}
if len(in.AptArchitectures) == 0 {
in.AptArchitectures = []string{"amd64"}
}
cfg := aptclone.Config{
Suite: in.AptSuite,
Components: in.AptComponents,
Architectures: in.AptArchitectures,
}
b, err := json.Marshal(cfg)
if err != nil {
return nil, fmt.Errorf("marshal apt config: %w", err)
}
configJSON = string(b)
}
r := &store.Repo{Name: in.Name, Type: in.Type, SourceURL: in.SourceURL, SyncMode: in.SyncMode, Config: configJSON}
id, err := s.store.CreateRepo(ctx, r)
if err != nil {
return nil, err
@ -60,15 +88,85 @@ func (s *RepoService) Create(ctx context.Context, in CreateRepoInput) (*store.Re
}
func (s *RepoService) initStorage(repo *store.Repo) {
localDir := filepath.Join(s.dataDir, "repos", fmt.Sprintf("%d", repo.ID), repo.Type)
switch repo.Type {
case "rpm":
localDir := filepath.Join(s.dataDir, "repos", fmt.Sprintf("%d", repo.ID), "rpm")
if err := rpmclone.InitEmptyRepo(localDir); err != nil {
log.Printf("init storage for repo %d: %v", repo.ID, err)
}
case "apt":
var cfg aptclone.Config
if err := json.Unmarshal([]byte(repo.Config), &cfg); err != nil {
log.Printf("init storage for repo %d: parse config: %v", repo.ID, err)
return
}
if err := aptclone.InitEmptyRepo(localDir, cfg); err != nil {
log.Printf("init storage for repo %d: %v", repo.ID, err)
}
}
}
type UpdateRepoInput struct {
SourceURL *string
SyncMode *string
AptSuite *string
AptComponents []string
AptArchitectures []string
}
func (s *RepoService) Update(ctx context.Context, id int64, in UpdateRepoInput) (*store.Repo, error) {
repo, err := s.store.GetRepo(ctx, id)
if err != nil {
return nil, err
}
if in.SourceURL != nil {
if *in.SourceURL == "" {
return nil, fmt.Errorf("source_url cannot be empty")
}
repo.SourceURL = *in.SourceURL
}
if in.SyncMode != nil {
if !validSyncModes[*in.SyncMode] {
return nil, fmt.Errorf("invalid sync_mode: %s (must be auto or manual)", *in.SyncMode)
}
repo.SyncMode = *in.SyncMode
}
if repo.Type == "apt" && (in.AptSuite != nil || in.AptComponents != nil || in.AptArchitectures != nil) {
var cfg aptclone.Config
if repo.Config != "" {
if err := json.Unmarshal([]byte(repo.Config), &cfg); err != nil {
return nil, fmt.Errorf("parse existing apt config: %w", err)
}
}
if in.AptSuite != nil {
if *in.AptSuite == "" {
return nil, fmt.Errorf("apt_suite cannot be empty")
}
cfg.Suite = *in.AptSuite
}
if in.AptComponents != nil {
cfg.Components = in.AptComponents
}
if in.AptArchitectures != nil {
cfg.Architectures = in.AptArchitectures
}
b, err := json.Marshal(cfg)
if err != nil {
return nil, fmt.Errorf("marshal apt config: %w", err)
}
repo.Config = string(b)
} else if repo.Type != "apt" && (in.AptSuite != nil || in.AptComponents != nil || in.AptArchitectures != nil) {
return nil, fmt.Errorf("apt fields only apply to apt repositories")
}
if err := s.store.UpdateRepo(ctx, id, repo.SourceURL, repo.SyncMode, repo.Config); err != nil {
return nil, err
}
return s.store.GetRepo(ctx, id)
}
func (s *RepoService) List(ctx context.Context) ([]store.Repo, error) {
return s.store.ListRepos(ctx)
}
@ -77,6 +175,10 @@ func (s *RepoService) Get(ctx context.Context, id int64) (*store.Repo, error) {
return s.store.GetRepo(ctx, id)
}
func (s *RepoService) GetByName(ctx context.Context, name string) (*store.Repo, error) {
return s.store.GetRepoByName(ctx, name)
}
func (s *RepoService) Delete(ctx context.Context, id int64) error {
return s.store.DeleteRepo(ctx, id)
}