Skip to content

Commit ddea32e

Browse files
feat4arch
1 parent ecd463c commit ddea32e

File tree

5 files changed

+172
-12
lines changed

5 files changed

+172
-12
lines changed

custom/conf/app.example.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,6 +2624,9 @@ LEVEL = Info
26242624
;LIMIT_SIZE_VAGRANT = -1
26252625
;; Enable RPM re-signing by default. (It will overwrite the old signature ,using v4 format, not compatible with CentOS 6 or older)
26262626
;DEFAULT_RPM_SIGN_ENABLED = false
2627+
;; Keep only the latest version in Arch DB.
2628+
;METADATA_ARCH_LATEST_VERSION = false
2629+
26272630
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26282631
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26292632
;; default storage for attachments, lfs and avatars

modules/setting/packages.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ var (
4545
LimitSizeVagrant int64
4646

4747
DefaultRPMSignEnabled bool
48+
49+
DefaultMetaArchLatestVersion bool
4850
}{
4951
Enabled: true,
5052
LimitTotalOwnerCount: -1,
@@ -102,6 +104,7 @@ func loadPackagesFrom(rootCfg ConfigProvider) (err error) {
102104
Packages.LimitSizeSwift = mustBytes(sec, "LIMIT_SIZE_SWIFT")
103105
Packages.LimitSizeVagrant = mustBytes(sec, "LIMIT_SIZE_VAGRANT")
104106
Packages.DefaultRPMSignEnabled = sec.Key("DEFAULT_RPM_SIGN_ENABLED").MustBool(false)
107+
Packages.DefaultMetaArchLatestVersion = sec.Key("METADATA_ARCH_LATEST_VERSION").MustBool(false)
105108
return nil
106109
}
107110

services/packages/arch/repository.go

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"code.gitea.io/gitea/modules/json"
2424
packages_module "code.gitea.io/gitea/modules/packages"
2525
arch_module "code.gitea.io/gitea/modules/packages/arch"
26+
"code.gitea.io/gitea/modules/setting"
2627
"code.gitea.io/gitea/modules/util"
2728
packages_service "code.gitea.io/gitea/services/packages"
2829

@@ -235,6 +236,30 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
235236
return packages_service.DeletePackageFile(ctx, pf)
236237
}
237238

239+
vpfs := make(map[string]*entryOptions)
240+
for _, pf := range pfs {
241+
current := &entryOptions{
242+
File: pf,
243+
}
244+
current.Version, err = packages_model.GetVersionByID(ctx, pf.VersionID)
245+
if err != nil {
246+
return err
247+
}
248+
249+
if setting.Packages.DefaultMetaArchLatestVersion {
250+
old := vpfs[pf.Name]
251+
if old != nil {
252+
if compareVersions(old.Version.Version, current.Version.Version) == -1 {
253+
vpfs[pf.Name] = current
254+
}
255+
} else {
256+
vpfs[pf.Name] = current
257+
}
258+
} else {
259+
vpfs[pf.Name] = current
260+
}
261+
}
262+
238263
indexContent, _ := packages_module.NewHashedBuffer()
239264
defer indexContent.Close()
240265

@@ -243,15 +268,7 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
243268

244269
cache := make(map[int64]*packages_model.Package)
245270

246-
for _, pf := range pfs {
247-
opts := &entryOptions{
248-
File: pf,
249-
}
250-
251-
opts.Version, err = packages_model.GetVersionByID(ctx, pf.VersionID)
252-
if err != nil {
253-
return err
254-
}
271+
for _, opts := range vpfs {
255272
if err := json.Unmarshal([]byte(opts.Version.MetadataJSON), &opts.VersionMetadata); err != nil {
256273
return err
257274
}
@@ -263,12 +280,12 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
263280
}
264281
cache[opts.Package.ID] = opts.Package
265282
}
266-
opts.Blob, err = packages_model.GetBlobByID(ctx, pf.BlobID)
283+
opts.Blob, err = packages_model.GetBlobByID(ctx, opts.File.BlobID)
267284
if err != nil {
268285
return err
269286
}
270287

271-
sig, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeFile, pf.ID, arch_module.PropertySignature)
288+
sig, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeFile, opts.File.ID, arch_module.PropertySignature)
272289
if err != nil {
273290
return err
274291
}
@@ -277,7 +294,7 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
277294
}
278295
opts.Signature = sig[0].Value
279296

280-
meta, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeFile, pf.ID, arch_module.PropertyMetadata)
297+
meta, err := packages_model.GetPropertiesByName(ctx, packages_model.PropertyTypeFile, opts.File.ID, arch_module.PropertyMetadata)
281298
if err != nil {
282299
return err
283300
}

services/packages/arch/vercmp.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package arch
2+
3+
import (
4+
"strings"
5+
"unicode"
6+
)
7+
8+
// https://gitlab.archlinux.org/pacman/pacman/-/blob/d55b47e5512808b67bc944feb20c2bcc6c1a4c45/lib/libalpm/version.c
9+
// generated by chatgpt
10+
11+
import (
12+
"strconv"
13+
)
14+
15+
func parseEVR(evr string) (epoch, version, release string) {
16+
if before, after, f := strings.Cut(evr, ":"); f {
17+
epoch = before
18+
evr = after
19+
} else {
20+
epoch = "0"
21+
}
22+
23+
if before, after, f := strings.Cut(evr, "-"); f {
24+
version = before
25+
release = after
26+
} else {
27+
version = evr
28+
release = "1"
29+
}
30+
return epoch, version, release
31+
}
32+
33+
func compareSegments(a, b []string) int {
34+
lenA, lenB := len(a), len(b)
35+
var l int
36+
if lenA > lenB {
37+
l = lenB
38+
} else {
39+
l = lenA
40+
}
41+
for i := 0; i < l; i++ {
42+
if r := compare(a[i], b[i]); r != 0 {
43+
return r
44+
}
45+
}
46+
if lenA == lenB {
47+
return 0
48+
} else if l == lenA {
49+
return -1
50+
} else {
51+
return 1
52+
}
53+
}
54+
55+
func compare(a, b string) int {
56+
if a == b {
57+
return 0
58+
}
59+
60+
aNumeric := isNumeric(a)
61+
bNumeric := isNumeric(b)
62+
63+
if aNumeric && bNumeric {
64+
aInt, _ := strconv.Atoi(a)
65+
bInt, _ := strconv.Atoi(b)
66+
switch {
67+
case aInt < bInt:
68+
return -1
69+
case aInt > bInt:
70+
return 1
71+
default:
72+
return 0
73+
}
74+
}
75+
76+
if aNumeric {
77+
return 1
78+
}
79+
if bNumeric {
80+
return -1
81+
}
82+
83+
return strings.Compare(a, b)
84+
}
85+
86+
func isNumeric(s string) bool {
87+
for _, c := range s {
88+
if !unicode.IsDigit(c) {
89+
return false
90+
}
91+
}
92+
return true
93+
}
94+
95+
func compareVersions(a, b string) int {
96+
if a == b {
97+
return 0
98+
}
99+
100+
epochA, versionA, releaseA := parseEVR(a)
101+
epochB, versionB, releaseB := parseEVR(b)
102+
103+
if res := compareSegments([]string{epochA}, []string{epochB}); res != 0 {
104+
return res
105+
}
106+
107+
if res := compareSegments(strings.Split(versionA, "."), strings.Split(versionB, ".")); res != 0 {
108+
return res
109+
}
110+
111+
return compareSegments([]string{releaseA}, []string{releaseB})
112+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package arch
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestCompareVersions(t *testing.T) {
11+
// https://man.archlinux.org/man/vercmp.8.en
12+
checks := [][]string{
13+
{"1.0a", "1.0b", "1.0beta", "1.0p", "1.0pre", "1.0rc", "1.0", "1.0.a", "1.0.1"},
14+
{"1", "1.0", "1.1", "1.1.1", "1.2", "2.0", "3.0.0"},
15+
}
16+
for _, check := range checks {
17+
for i := 0; i < len(check)-1; i++ {
18+
require.Equal(t, -1, compareVersions(check[i], check[i+1]), fmt.Sprintf("%s > %s", check[i], check[i+1]))
19+
require.Equal(t, 1, compareVersions(check[i+1], check[i]), fmt.Sprintf("%s > %s", check[i], check[i+1]))
20+
}
21+
}
22+
require.Equal(t, 1, compareVersions("1.0-2", "1.0"))
23+
require.Equal(t, 0, compareVersions("0:1.0-1", "1.0"))
24+
require.Equal(t, 1, compareVersions("1:1.0-1", "2.0"))
25+
}

0 commit comments

Comments
 (0)