Skip to content

Commit ba4d0b8

Browse files
Support for grouping RPMs using paths (#26984)
The current rpm repository places all packages in the same repository, and different systems (el7,f34) may hit packages that do not belong to this distribution ( #25304 ) , which now supports grouping of rpm. ![图片](https://github.com/go-gitea/gitea/assets/33776693/d1e1d99f-7799-4b2b-a19b-cb2a5c692914) Fixes #25304 . Fixes #27056 . Refactor: [#25866](#25866)
1 parent 7c2f093 commit ba4d0b8

File tree

9 files changed

+192
-101
lines changed

9 files changed

+192
-101
lines changed

Diff for: docs/content/usage/packages/rpm.en-us.md

+18-15
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,18 @@ The following examples use `dnf`.
2727
To register the RPM registry add the url to the list of known apt sources:
2828

2929
```shell
30-
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm.repo
30+
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo
3131
```
3232

33-
| Placeholder | Description |
34-
| ----------- | ----------- |
35-
| `owner` | The owner of the package. |
33+
| Placeholder | Description |
34+
| ----------- |----------------------------------------------------|
35+
| `owner` | The owner of the package. |
36+
| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
3637

3738
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
3839

3940
```shell
40-
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm.repo
41+
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo
4142
```
4243

4344
You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.repos.d` too.
@@ -47,19 +48,20 @@ You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.
4748
To publish a RPM package (`*.rpm`), perform a HTTP PUT operation with the package content in the request body.
4849

4950
```
50-
PUT https://gitea.example.com/api/packages/{owner}/rpm/upload
51+
PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload
5152
```
5253

5354
| Parameter | Description |
5455
| --------- | ----------- |
5556
| `owner` | The owner of the package. |
57+
| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
5658

5759
Example request using HTTP Basic authentication:
5860

5961
```shell
6062
curl --user your_username:your_password_or_token \
6163
--upload-file path/to/file.rpm \
62-
https://gitea.example.com/api/packages/testuser/rpm/upload
64+
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/upload
6365
```
6466

6567
If you are using 2FA or OAuth use a [personal access token](development/api-usage.md#authentication) instead of the password.
@@ -78,21 +80,22 @@ The server responds with the following HTTP Status codes.
7880
To delete an RPM package perform a HTTP DELETE operation. This will delete the package version too if there is no file left.
7981

8082
```
81-
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture}
83+
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture}
8284
```
8385

84-
| Parameter | Description |
85-
| ----------------- | ----------- |
86-
| `owner` | The owner of the package. |
87-
| `package_name` | The package name. |
88-
| `package_version` | The package version. |
89-
| `architecture` | The package architecture. |
86+
| Parameter | Description |
87+
|-------------------|----------------------------|
88+
| `owner` | The owner of the package. |
89+
| `group` | The package group . |
90+
| `package_name` | The package name. |
91+
| `package_version` | The package version. |
92+
| `architecture` | The package architecture. |
9093

9194
Example request using HTTP Basic authentication:
9295

9396
```shell
9497
curl --user your_username:your_token_or_password -X DELETE \
95-
https://gitea.example.com/api/packages/testuser/rpm/test-package/1.0.0/x86_64
98+
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64
9699
```
97100

98101
The server responds with the following HTTP Status codes.

Diff for: docs/content/usage/packages/rpm.zh-cn.md

+14-11
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,18 @@ menu:
2727
要注册RPM注册表,请将 URL 添加到已知 `apt` 源列表中:
2828

2929
```shell
30-
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm.repo
30+
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo
3131
```
3232

33-
| 占位符 | 描述 |
34-
| ------- | -------------- |
35-
| `owner` | 软件包的所有者 |
33+
| 占位符 | 描述 |
34+
| ------- |--------------------------------------|
35+
| `owner` | 软件包的所有者 |
36+
| `group` | 任何名称,例如 `centos/7``el-7``fc38` |
3637

3738
如果注册表是私有的,请在URL中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证)
3839

3940
```shell
40-
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm.repo
41+
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo
4142
```
4243

4344
您还必须将凭据添加到 `/etc/yum.repos.d` 中的 `rpm.repo` 文件中的URL中。
@@ -47,19 +48,20 @@ dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.
4748
要发布RPM软件包(`*.rpm`),请执行带有软件包内容的 HTTP `PUT` 操作。
4849

4950
```
50-
PUT https://gitea.example.com/api/packages/{owner}/rpm/upload
51+
PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload
5152
```
5253

5354
| 参数 | 描述 |
54-
| ------- | -------------- |
55-
| `owner` | 软件包的所有者 |
55+
| ------- |--------------|
56+
| `owner` | 软件包的所有者 |
57+
| `group` | 软件包自定义分组名称 |
5658

5759
使用HTTP基本身份验证的示例请求:
5860

5961
```shell
6062
curl --user your_username:your_password_or_token \
6163
--upload-file path/to/file.rpm \
62-
https://gitea.example.com/api/packages/testuser/rpm/upload
64+
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/version/upload
6365
```
6466

6567
如果您使用 2FA 或 OAuth,请使用[个人访问令牌](development/api-usage.md#通过-api-认证)替代密码。您无法将具有相同名称的文件两次发布到软件包中。您必须先删除现有的软件包版本。
@@ -77,12 +79,13 @@ curl --user your_username:your_password_or_token \
7779
要删除 RPM 软件包,请执行 HTTP `DELETE` 操作。如果没有文件剩余,这也将删除软件包版本。
7880

7981
```
80-
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture}
82+
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture}
8183
```
8284

8385
| 参数 | 描述 |
8486
| ----------------- | -------------- |
8587
| `owner` | 软件包的所有者 |
88+
| `group` | 软件包自定义分组 |
8689
| `package_name` | 软件包名称 |
8790
| `package_version` | 软件包版本 |
8891
| `architecture` | 软件包架构 |
@@ -91,7 +94,7 @@ DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{packag
9194

9295
```shell
9396
curl --user your_username:your_token_or_password -X DELETE \
94-
https://gitea.example.com/api/packages/testuser/rpm/test-package/1.0.0/x86_64
97+
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64
9598
```
9699

97100
服务器将以以下HTTP状态码响应:

Diff for: modules/packages/rpm/metadata.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ import (
1515
)
1616

1717
const (
18-
PropertyMetadata = "rpm.metadata"
19-
18+
PropertyMetadata = "rpm.metadata"
2019
SettingKeyPrivate = "rpm.key.private"
2120
SettingKeyPublic = "rpm.key.public"
2221

Diff for: modules/templates/util_string.go

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package templates
55

66
import (
7+
"regexp"
78
"strings"
89

910
"code.gitea.io/gitea/modules/base"
@@ -25,6 +26,10 @@ func (su *StringUtils) Contains(s, substr string) bool {
2526
return strings.Contains(s, substr)
2627
}
2728

29+
func (su *StringUtils) ReplaceAllStringRegex(s, regex, new string) string {
30+
return regexp.MustCompile(regex).ReplaceAllString(s, new)
31+
}
32+
2833
func (su *StringUtils) Split(s, sep string) []string {
2934
return strings.Split(s, sep)
3035
}

Diff for: routers/api/packages/api.go

+77-13
Original file line numberDiff line numberDiff line change
@@ -512,19 +512,7 @@ func CommonRoutes() *web.Route {
512512
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
513513
r.Get("/simple/{id}", pypi.PackageMetadata)
514514
}, reqPackageAccess(perm.AccessModeRead))
515-
r.Group("/rpm", func() {
516-
r.Get(".repo", rpm.GetRepositoryConfig)
517-
r.Get("/repository.key", rpm.GetRepositoryKey)
518-
r.Put("/upload", reqPackageAccess(perm.AccessModeWrite), rpm.UploadPackageFile)
519-
r.Group("/package/{name}/{version}/{architecture}", func() {
520-
r.Get("", rpm.DownloadPackageFile)
521-
r.Delete("", reqPackageAccess(perm.AccessModeWrite), rpm.DeletePackageFile)
522-
})
523-
r.Group("/repodata/{filename}", func() {
524-
r.Head("", rpm.CheckRepositoryFileExistence)
525-
r.Get("", rpm.GetRepositoryFile)
526-
})
527-
}, reqPackageAccess(perm.AccessModeRead))
515+
r.Group("/rpm", RpmRoutes(r), reqPackageAccess(perm.AccessModeRead))
528516
r.Group("/rubygems", func() {
529517
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
530518
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
@@ -589,6 +577,82 @@ func CommonRoutes() *web.Route {
589577
return r
590578
}
591579

580+
// Support for uploading rpm packages with arbitrary depth paths
581+
func RpmRoutes(r *web.Route) func() {
582+
var (
583+
groupRepoInfo = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)\.repo\z`)
584+
groupUpload = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/upload\z`)
585+
groupRpm = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/package/([^/]+)/([^/]+)/([^/]+)(?:/([^/]+\.rpm)|)\z`)
586+
groupMetadata = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/repodata/([^/]+)\z`)
587+
)
588+
589+
return func() {
590+
r.Methods("HEAD,GET,POST,PUT,PATCH,DELETE", "*", func(ctx *context.Context) {
591+
path := ctx.Params("*")
592+
isHead := ctx.Req.Method == "HEAD"
593+
isGetHead := ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET"
594+
isPut := ctx.Req.Method == "PUT"
595+
isDelete := ctx.Req.Method == "DELETE"
596+
597+
if path == "/repository.key" && isGetHead {
598+
rpm.GetRepositoryKey(ctx)
599+
return
600+
}
601+
602+
// get repo
603+
m := groupRepoInfo.FindStringSubmatch(path)
604+
if len(m) == 2 && isGetHead {
605+
ctx.SetParams("group", strings.Trim(m[1], "/"))
606+
rpm.GetRepositoryConfig(ctx)
607+
return
608+
}
609+
// get meta
610+
m = groupMetadata.FindStringSubmatch(path)
611+
if len(m) == 3 && isGetHead {
612+
ctx.SetParams("group", strings.Trim(m[1], "/"))
613+
ctx.SetParams("filename", m[2])
614+
if isHead {
615+
rpm.CheckRepositoryFileExistence(ctx)
616+
} else {
617+
rpm.GetRepositoryFile(ctx)
618+
}
619+
return
620+
}
621+
// upload
622+
m = groupUpload.FindStringSubmatch(path)
623+
if len(m) == 2 && isPut {
624+
reqPackageAccess(perm.AccessModeWrite)(ctx)
625+
if ctx.Written() {
626+
return
627+
}
628+
ctx.SetParams("group", strings.Trim(m[1], "/"))
629+
rpm.UploadPackageFile(ctx)
630+
return
631+
}
632+
// rpm down/delete
633+
m = groupRpm.FindStringSubmatch(path)
634+
if len(m) == 6 {
635+
ctx.SetParams("group", strings.Trim(m[1], "/"))
636+
ctx.SetParams("name", m[2])
637+
ctx.SetParams("version", m[3])
638+
ctx.SetParams("architecture", m[4])
639+
if isGetHead {
640+
rpm.DownloadPackageFile(ctx)
641+
return
642+
} else if isDelete {
643+
reqPackageAccess(perm.AccessModeWrite)(ctx)
644+
if ctx.Written() {
645+
return
646+
}
647+
rpm.DeletePackageFile(ctx)
648+
}
649+
}
650+
// default
651+
ctx.Status(http.StatusNotFound)
652+
})
653+
}
654+
}
655+
592656
// ContainerRoutes provides endpoints that implement the OCI API to serve containers
593657
// These have to be mounted on `/v2/...` to comply with the OCI spec:
594658
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md

0 commit comments

Comments
 (0)