2025-01-13 19:23:44 +03:00
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2025-01-31 23:52:08 +03:00
|
|
|
|
"crypto/sha256"
|
|
|
|
|
"encoding/hex"
|
2025-01-13 19:23:44 +03:00
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strings"
|
|
|
|
|
"os/exec"
|
2025-01-31 23:52:08 +03:00
|
|
|
|
|
2025-01-13 19:23:44 +03:00
|
|
|
|
"github.com/spf13/viper"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
ARCH_X86_64 = "x86_64"
|
|
|
|
|
ARCH_RISCV64 = "riscv64"
|
|
|
|
|
ARCH_I386 = "i386"
|
|
|
|
|
ARCH_AARCH64 = "aarch64"
|
|
|
|
|
ARCH_NOARCH = "noarch"
|
|
|
|
|
ARCH_SRC = "src"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Repository struct {
|
|
|
|
|
BasePath string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewRepository() *Repository {
|
|
|
|
|
return &Repository{
|
|
|
|
|
BasePath: viper.GetString("repository.path"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-31 23:52:08 +03:00
|
|
|
|
// ProcessPackage обрабатывает загруженный пакет
|
|
|
|
|
func (r *Repository) ProcessPackage(arch, filename string, body io.Reader) error {
|
|
|
|
|
// Преобразуем body к io.ReadSeeker для возможности использовать Seek
|
|
|
|
|
readSeeker, ok := body.(io.ReadSeeker)
|
|
|
|
|
if !ok {
|
|
|
|
|
logger.Errorf("Failed to cast body to io.ReadSeeker for file %s", filename)
|
|
|
|
|
return fmt.Errorf("failed to cast body to io.ReadSeeker")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Вычисляем контрольную сумму загруженного файла
|
|
|
|
|
hash := sha256.New()
|
|
|
|
|
if _, err := io.Copy(hash, readSeeker); err != nil {
|
|
|
|
|
logger.Errorf("Error computing checksum for file %s: %v", filename, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
checksum := hex.EncodeToString(hash.Sum(nil))
|
|
|
|
|
|
|
|
|
|
// Возвращаемся к началу файла для записи
|
|
|
|
|
if _, err := readSeeker.Seek(0, 0); err != nil {
|
|
|
|
|
logger.Errorf("Error seeking to the beginning of file %s: %v", filename, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Проверяем, существует ли файл с такой контрольной суммой
|
|
|
|
|
if r.fileExistsWithChecksum(arch, filename, checksum) {
|
|
|
|
|
logger.Infof("File %s already exists with the same checksum, skipping upload.", filename)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Сохраняем пакет
|
|
|
|
|
if err := r.SavePackage(arch, filename, readSeeker); err != nil {
|
|
|
|
|
logger.Errorf("Error saving package %s: %v", filename, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-13 19:23:44 +03:00
|
|
|
|
func (r *Repository) SavePackage(arch, name string, body io.Reader) error {
|
|
|
|
|
logger.Infof("Saving package %s for architecture %s", name, arch)
|
|
|
|
|
dir := filepath.Join(r.BasePath, arch)
|
|
|
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
|
|
|
logger.Errorf("Failed to create directory %s: %v", dir, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
filePath := filepath.Join(dir, name)
|
|
|
|
|
file, err := os.Create(filePath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Errorf("Failed to create file %s: %v", filePath, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
defer file.Close()
|
|
|
|
|
_, err = io.Copy(file, body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Errorf("Failed to copy file content to %s: %v", filePath, err)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate metadata
|
|
|
|
|
cmd := exec.Command("genhdlist2", "--update", "--root", dir)
|
|
|
|
|
logger.Infof("Generating metadata for directory %s", dir)
|
|
|
|
|
if err := cmd.Run(); err != nil {
|
|
|
|
|
logger.Errorf("Failed to generate metadata: %v", err)
|
|
|
|
|
return fmt.Errorf("failed to generate metadata: %w", err)
|
|
|
|
|
}
|
|
|
|
|
logger.Infof("Package %s saved successfully for architecture %s", name, arch)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-31 23:52:08 +03:00
|
|
|
|
func (r *Repository) fileExistsWithChecksum(arch, filename, checksum string) bool {
|
|
|
|
|
filePath := filepath.Join(r.BasePath, arch, filename)
|
|
|
|
|
file, err := os.Open(filePath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
logger.Errorf("Error opening file %s: %v", filePath, err)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
|
|
hash := sha256.New()
|
|
|
|
|
if _, err := io.Copy(hash, file); err != nil {
|
|
|
|
|
logger.Errorf("Error computing checksum for file %s: %v", filePath, err)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
existingChecksum := hex.EncodeToString(hash.Sum(nil))
|
|
|
|
|
|
|
|
|
|
return existingChecksum == checksum
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-13 19:23:44 +03:00
|
|
|
|
func (r *Repository) GetArch(arch string) string {
|
|
|
|
|
switch strings.ToLower(arch) {
|
|
|
|
|
case ARCH_X86_64:
|
|
|
|
|
return ARCH_X86_64
|
|
|
|
|
case ARCH_RISCV64:
|
|
|
|
|
return ARCH_RISCV64
|
|
|
|
|
case ARCH_I386:
|
|
|
|
|
return ARCH_I386
|
|
|
|
|
case ARCH_AARCH64:
|
|
|
|
|
return ARCH_AARCH64
|
|
|
|
|
case ARCH_NOARCH:
|
|
|
|
|
return ARCH_NOARCH
|
|
|
|
|
case ARCH_SRC:
|
|
|
|
|
return ARCH_SRC
|
|
|
|
|
default:
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
}
|