Files
codit/backend/internal/rpm/packages.go

205 lines
5.2 KiB
Go

package rpm
import "io/fs"
import "path/filepath"
import "sort"
import "strings"
import repokit "repokit"
type PackageSummary struct {
Filename string `json:"filename"`
Name string `json:"name"`
Version string `json:"version"`
Release string `json:"release"`
Arch string `json:"arch"`
Summary string `json:"summary"`
}
type PackageDetail struct {
PackageSummary
Description string `json:"description"`
License string `json:"license"`
URL string `json:"url"`
BuildTime int64 `json:"build_time"`
Size int64 `json:"size"`
Files []string `json:"files"`
Requires []string `json:"requires"`
Provides []string `json:"provides"`
Changelogs []PackageChangeLog `json:"changelogs"`
}
type PackageChangeLog struct {
Author string `json:"author"`
Date int64 `json:"date"`
Text string `json:"text"`
}
func ListPackages(repoPath string) ([]PackageSummary, error) {
var packages []PackageSummary
var walkErr error
var err error
walkErr = filepath.WalkDir(repoPath, func(path string, entry fs.DirEntry, entryErr error) error {
var lower string
var rel string
var pkg *repokit.RpmPackage
var summary PackageSummary
if entryErr != nil {
return entryErr
}
if entry.IsDir() {
return nil
}
lower = strings.ToLower(entry.Name())
if !strings.HasSuffix(lower, ".rpm") {
return nil
}
rel, err = filepath.Rel(repoPath, path)
if err != nil {
return err
}
pkg, err = repokit.RpmPackageFromRpmBase(path, 0)
if err != nil {
return nil
}
summary = packageSummaryFromRepokit(pkg, filepath.ToSlash(rel))
packages = append(packages, summary)
return nil
})
if walkErr != nil {
return nil, walkErr
}
sort.Slice(packages, func(i int, j int) bool {
if packages[i].Name == packages[j].Name {
return packages[i].Filename < packages[j].Filename
}
return packages[i].Name < packages[j].Name
})
return packages, nil
}
func GetPackageDetail(repoPath string, filename string) (PackageDetail, error) {
var detail PackageDetail
var fullPath string
var pkg *repokit.RpmPackage
var err error
fullPath = filepath.Join(repoPath, filepath.FromSlash(filename))
pkg, err = repokit.RpmPackageFromRpmBase(fullPath, 256)
if err != nil {
return detail, err
}
detail = packageDetailFromRepokit(pkg, filename)
return detail, nil
}
func packageSummaryFromRepokit(pkg *repokit.RpmPackage, filename string) PackageSummary {
var summary PackageSummary
summary = PackageSummary{
Filename: filename,
Name: strings.TrimSpace(pkg.Name),
Version: strings.TrimSpace(pkg.Version),
Release: strings.TrimSpace(pkg.Release),
Arch: strings.TrimSpace(pkg.Arch),
Summary: strings.TrimSpace(pkg.Summary),
}
return summary
}
func packageDetailFromRepokit(pkg *repokit.RpmPackage, filename string) PackageDetail {
var files []string
var file repokit.RpmPackageFile
var changelogs []PackageChangeLog
var changelog repokit.RpmChangelogEntry
var detail PackageDetail
files = make([]string, 0, len(pkg.Files))
for _, file = range pkg.Files {
if file.FullPath == "" {
continue
}
files = append(files, file.FullPath)
}
changelogs = make([]PackageChangeLog, 0, len(pkg.Changelogs))
for _, changelog = range pkg.Changelogs {
changelogs = append(changelogs, PackageChangeLog{
Author: strings.TrimSpace(changelog.Author),
Date: changelog.Date,
Text: strings.TrimSpace(changelog.Changelog),
})
}
sort.SliceStable(changelogs, func(i int, j int) bool {
return changelogs[i].Date > changelogs[j].Date
})
sort.Strings(files)
detail = PackageDetail{
PackageSummary: packageSummaryFromRepokit(pkg, filename),
Description: strings.TrimSpace(pkg.Description),
License: strings.TrimSpace(pkg.RpmLicense),
URL: strings.TrimSpace(pkg.Url),
BuildTime: pkg.TimeBuild,
Size: pkg.SizePackage,
Files: files,
Requires: dependencyListToStrings(pkg.Requires),
Provides: dependencyListToStrings(pkg.Provides),
Changelogs: changelogs,
}
return detail
}
func dependencyListToStrings(deps []repokit.RpmDependency) []string {
var lines []string
var dep repokit.RpmDependency
lines = make([]string, 0, len(deps))
for _, dep = range deps {
lines = append(lines, dependencyToString(dep))
}
return lines
}
func dependencyToString(dep repokit.RpmDependency) string {
var op string
var evr string
var line string
op = normalizeDependencyOp(dep.Flags)
evr = dependencyEVR(dep)
line = dep.Name
if op == "" || evr == "" {
return line
}
line = line + " " + op + " " + evr
return line
}
func normalizeDependencyOp(flag string) string {
switch strings.ToUpper(strings.TrimSpace(flag)) {
case "LT":
return "<"
case "GT":
return ">"
case "EQ":
return "="
case "LE":
return "<="
case "GE":
return ">="
default:
return strings.TrimSpace(flag)
}
}
func dependencyEVR(dep repokit.RpmDependency) string {
var value string
var version string
version = strings.TrimSpace(dep.Version)
if version == "" {
return ""
}
value = version
if strings.TrimSpace(dep.Release) != "" {
value = value + "-" + strings.TrimSpace(dep.Release)
}
if strings.TrimSpace(dep.Epoch) != "" && strings.TrimSpace(dep.Epoch) != "0" {
value = strings.TrimSpace(dep.Epoch) + ":" + value
}
return value
}