aboutsummaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorExploding Dragon <explodingfkl@gmail.com>2025-02-13 09:24:44 +0800
committerGitHub <noreply@github.com>2025-02-13 01:24:44 +0000
commitfba365b42558227e5580ed1e3bbed2da902216da (patch)
tree8d47dd06778668adf006acbe6a679980e3badfbd /services
parent42d817e814da5bb7fcfa8289f6bedb615546e499 (diff)
downloadgitea-fba365b42558227e5580ed1e3bbed2da902216da.tar.gz
gitea-fba365b42558227e5580ed1e3bbed2da902216da.zip
Only show the latest version in the Arch index (#33262)
Only show the latest version of the package in the arch repo. closes #33534 --------- Co-authored-by: Giteabot <teabot@gitea.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Diffstat (limited to 'services')
-rw-r--r--services/packages/arch/repository.go38
-rw-r--r--services/packages/arch/vercmp.go113
-rw-r--r--services/packages/arch/vercmp_test.go27
3 files changed, 166 insertions, 12 deletions
diff --git a/services/packages/arch/repository.go b/services/packages/arch/repository.go
index 7fb4222cf6..a12af82ba5 100644
--- a/services/packages/arch/repository.go
+++ b/services/packages/arch/repository.go
@@ -235,6 +235,28 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
return packages_service.DeletePackageFile(ctx, pf)
}
+ vpfs := make(map[int64]*entryOptions)
+ for _, pf := range pfs {
+ current := &entryOptions{
+ File: pf,
+ }
+ current.Version, err = packages_model.GetVersionByID(ctx, pf.VersionID)
+ if err != nil {
+ return err
+ }
+
+ // here we compare the versions but not using SearchLatestVersions because we shouldn't allow "downgrading" to a older version by "latest" one.
+ // https://wiki.archlinux.org/title/Downgrading_packages : randomly downgrading can mess up dependencies:
+ // If a downgrade involves a soname change, all dependencies may need downgrading or rebuilding too.
+ if old, ok := vpfs[current.Version.PackageID]; ok {
+ if compareVersions(old.Version.Version, current.Version.Version) == -1 {
+ vpfs[current.Version.PackageID] = current
+ }
+ } else {
+ vpfs[current.Version.PackageID] = current
+ }
+ }
+
indexContent, _ := packages_module.NewHashedBuffer()
defer indexContent.Close()
@@ -243,15 +265,7 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
cache := make(map[int64]*packages_model.Package)
- for _, pf := range pfs {
- opts := &entryOptions{
- File: pf,
- }
-
- opts.Version, err = packages_model.GetVersionByID(ctx, pf.VersionID)
- if err != nil {
- return err
- }
+ for _, opts := range vpfs {
if err := json.Unmarshal([]byte(opts.Version.MetadataJSON), &opts.VersionMetadata); err != nil {
return err
}
@@ -263,12 +277,12 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
}
cache[opts.Package.ID] = opts.Package
}
- opts.Blob, err = packages_model.GetBlobByID(ctx, pf.BlobID)
+ opts.Blob, err = packages_model.GetBlobByID(ctx, opts.File.BlobID)
if err != nil {
return err
}
- sig, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeFile, pf.ID, arch_module.PropertySignature)
+ sig, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeFile, opts.File.ID, arch_module.PropertySignature)
if err != nil {
return err
}
@@ -277,7 +291,7 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
}
opts.Signature = sig[0].Value
- meta, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeFile, pf.ID, arch_module.PropertyMetadata)
+ meta, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeFile, opts.File.ID, arch_module.PropertyMetadata)
if err != nil {
return err
}
diff --git a/services/packages/arch/vercmp.go b/services/packages/arch/vercmp.go
new file mode 100644
index 0000000000..0d33dda0f1
--- /dev/null
+++ b/services/packages/arch/vercmp.go
@@ -0,0 +1,113 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package arch
+
+import (
+ "strings"
+ "unicode"
+)
+
+// https://gitlab.archlinux.org/pacman/pacman/-/blob/d55b47e5512808b67bc944feb20c2bcc6c1a4c45/lib/libalpm/version.c
+
+import (
+ "strconv"
+)
+
+func parseEVR(evr string) (epoch, version, release string) {
+ if before, after, f := strings.Cut(evr, ":"); f {
+ epoch = before
+ evr = after
+ } else {
+ epoch = "0"
+ }
+
+ if before, after, f := strings.Cut(evr, "-"); f {
+ version = before
+ release = after
+ } else {
+ version = evr
+ release = "1"
+ }
+ return epoch, version, release
+}
+
+func compareSegments(a, b []string) int {
+ lenA, lenB := len(a), len(b)
+ var l int
+ if lenA > lenB {
+ l = lenB
+ } else {
+ l = lenA
+ }
+ for i := 0; i < l; i++ {
+ if r := compare(a[i], b[i]); r != 0 {
+ return r
+ }
+ }
+ if lenA == lenB {
+ return 0
+ } else if l == lenA {
+ return -1
+ }
+ return 1
+}
+
+func compare(a, b string) int {
+ if a == b {
+ return 0
+ }
+
+ aNumeric := isNumeric(a)
+ bNumeric := isNumeric(b)
+
+ if aNumeric && bNumeric {
+ aInt, _ := strconv.Atoi(a)
+ bInt, _ := strconv.Atoi(b)
+ switch {
+ case aInt < bInt:
+ return -1
+ case aInt > bInt:
+ return 1
+ default:
+ return 0
+ }
+ }
+
+ if aNumeric {
+ return 1
+ }
+ if bNumeric {
+ return -1
+ }
+
+ return strings.Compare(a, b)
+}
+
+func isNumeric(s string) bool {
+ for _, c := range s {
+ if !unicode.IsDigit(c) {
+ return false
+ }
+ }
+ return true
+}
+
+func compareVersions(a, b string) int {
+ if a == b {
+ return 0
+ }
+
+ epochA, versionA, releaseA := parseEVR(a)
+ epochB, versionB, releaseB := parseEVR(b)
+
+ if res := compareSegments([]string{epochA}, []string{epochB}); res != 0 {
+ return res
+ }
+
+ if res := compareSegments(strings.Split(versionA, "."), strings.Split(versionB, ".")); res != 0 {
+ return res
+ }
+
+ return compareSegments([]string{releaseA}, []string{releaseB})
+}
diff --git a/services/packages/arch/vercmp_test.go b/services/packages/arch/vercmp_test.go
new file mode 100644
index 0000000000..2014a6d429
--- /dev/null
+++ b/services/packages/arch/vercmp_test.go
@@ -0,0 +1,27 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package arch
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestCompareVersions(t *testing.T) {
+ // https://man.archlinux.org/man/vercmp.8.en
+ checks := [][]string{
+ {"1.0a", "1.0b", "1.0beta", "1.0p", "1.0pre", "1.0rc", "1.0", "1.0.a", "1.0.1"},
+ {"1", "1.0", "1.1", "1.1.1", "1.2", "2.0", "3.0.0"},
+ }
+ for _, check := range checks {
+ for i := 0; i < len(check)-1; i++ {
+ require.Equal(t, -1, compareVersions(check[i], check[i+1]))
+ require.Equal(t, 1, compareVersions(check[i+1], check[i]))
+ }
+ }
+ require.Equal(t, 1, compareVersions("1.0-2", "1.0"))
+ require.Equal(t, 0, compareVersions("0:1.0-1", "1.0"))
+ require.Equal(t, 1, compareVersions("1:1.0-1", "2.0"))
+}