aboutsummaryrefslogtreecommitdiffstats
path: root/routers/api/packages
diff options
context:
space:
mode:
authorExploding Dragon <explodingfkl@gmail.com>2024-01-12 11:16:05 +0800
committerGitHub <noreply@github.com>2024-01-12 03:16:05 +0000
commitba4d0b8ffbd78473273800f586ae8bde55cda6c5 (patch)
treed828fd0f24bf6ddb38b2b4993b152f225c778c0a /routers/api/packages
parent7c2f093e856395cc118dcaa390b7a2234b8363f3 (diff)
downloadgitea-ba4d0b8ffbd78473273800f586ae8bde55cda6c5.tar.gz
gitea-ba4d0b8ffbd78473273800f586ae8bde55cda6c5.zip
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](https://github.com/go-gitea/gitea/pull/25866)
Diffstat (limited to 'routers/api/packages')
-rw-r--r--routers/api/packages/api.go90
-rw-r--r--routers/api/packages/rpm/rpm.go45
2 files changed, 105 insertions, 30 deletions
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index 76116d0751..9026387129 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -512,19 +512,7 @@ func CommonRoutes() *web.Route {
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
r.Get("/simple/{id}", pypi.PackageMetadata)
}, reqPackageAccess(perm.AccessModeRead))
- r.Group("/rpm", func() {
- r.Get(".repo", rpm.GetRepositoryConfig)
- r.Get("/repository.key", rpm.GetRepositoryKey)
- r.Put("/upload", reqPackageAccess(perm.AccessModeWrite), rpm.UploadPackageFile)
- r.Group("/package/{name}/{version}/{architecture}", func() {
- r.Get("", rpm.DownloadPackageFile)
- r.Delete("", reqPackageAccess(perm.AccessModeWrite), rpm.DeletePackageFile)
- })
- r.Group("/repodata/{filename}", func() {
- r.Head("", rpm.CheckRepositoryFileExistence)
- r.Get("", rpm.GetRepositoryFile)
- })
- }, reqPackageAccess(perm.AccessModeRead))
+ r.Group("/rpm", RpmRoutes(r), reqPackageAccess(perm.AccessModeRead))
r.Group("/rubygems", func() {
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
@@ -589,6 +577,82 @@ func CommonRoutes() *web.Route {
return r
}
+// Support for uploading rpm packages with arbitrary depth paths
+func RpmRoutes(r *web.Route) func() {
+ var (
+ groupRepoInfo = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)\.repo\z`)
+ groupUpload = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/upload\z`)
+ groupRpm = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/package/([^/]+)/([^/]+)/([^/]+)(?:/([^/]+\.rpm)|)\z`)
+ groupMetadata = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/repodata/([^/]+)\z`)
+ )
+
+ return func() {
+ r.Methods("HEAD,GET,POST,PUT,PATCH,DELETE", "*", func(ctx *context.Context) {
+ path := ctx.Params("*")
+ isHead := ctx.Req.Method == "HEAD"
+ isGetHead := ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET"
+ isPut := ctx.Req.Method == "PUT"
+ isDelete := ctx.Req.Method == "DELETE"
+
+ if path == "/repository.key" && isGetHead {
+ rpm.GetRepositoryKey(ctx)
+ return
+ }
+
+ // get repo
+ m := groupRepoInfo.FindStringSubmatch(path)
+ if len(m) == 2 && isGetHead {
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ rpm.GetRepositoryConfig(ctx)
+ return
+ }
+ // get meta
+ m = groupMetadata.FindStringSubmatch(path)
+ if len(m) == 3 && isGetHead {
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ ctx.SetParams("filename", m[2])
+ if isHead {
+ rpm.CheckRepositoryFileExistence(ctx)
+ } else {
+ rpm.GetRepositoryFile(ctx)
+ }
+ return
+ }
+ // upload
+ m = groupUpload.FindStringSubmatch(path)
+ if len(m) == 2 && isPut {
+ reqPackageAccess(perm.AccessModeWrite)(ctx)
+ if ctx.Written() {
+ return
+ }
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ rpm.UploadPackageFile(ctx)
+ return
+ }
+ // rpm down/delete
+ m = groupRpm.FindStringSubmatch(path)
+ if len(m) == 6 {
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ ctx.SetParams("name", m[2])
+ ctx.SetParams("version", m[3])
+ ctx.SetParams("architecture", m[4])
+ if isGetHead {
+ rpm.DownloadPackageFile(ctx)
+ return
+ } else if isDelete {
+ reqPackageAccess(perm.AccessModeWrite)(ctx)
+ if ctx.Written() {
+ return
+ }
+ rpm.DeletePackageFile(ctx)
+ }
+ }
+ // default
+ ctx.Status(http.StatusNotFound)
+ })
+ }
+}
+
// ContainerRoutes provides endpoints that implement the OCI API to serve containers
// These have to be mounted on `/v2/...` to comply with the OCI spec:
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md
diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go
index 2e161940b8..75d19e2b43 100644
--- a/routers/api/packages/rpm/rpm.go
+++ b/routers/api/packages/rpm/rpm.go
@@ -33,11 +33,14 @@ func apiError(ctx *context.Context, status int, obj any) {
// https://dnf.readthedocs.io/en/latest/conf_ref.html
func GetRepositoryConfig(ctx *context.Context) {
+ group := ctx.Params("group")
+ if group != "" {
+ group = fmt.Sprintf("/%s", group)
+ }
url := fmt.Sprintf("%sapi/packages/%s/rpm", setting.AppURL, ctx.Package.Owner.Name)
-
- ctx.PlainText(http.StatusOK, `[gitea-`+ctx.Package.Owner.LowerName+`]
-name=`+ctx.Package.Owner.Name+` - `+setting.AppName+`
-baseurl=`+url+`
+ ctx.PlainText(http.StatusOK, `[gitea-`+ctx.Package.Owner.LowerName+strings.ReplaceAll(group, "/", "-")+`]
+name=`+ctx.Package.Owner.Name+` - `+setting.AppName+strings.ReplaceAll(group, "/", " - ")+`
+baseurl=`+url+group+`/
enabled=1
gpgcheck=1
gpgkey=`+url+`/repository.key`)
@@ -64,7 +67,7 @@ func CheckRepositoryFileExistence(ctx *context.Context) {
return
}
- pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), packages_model.EmptyFileKey)
+ pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), ctx.Params("group"))
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Status(http.StatusNotFound)
@@ -93,7 +96,8 @@ func GetRepositoryFile(ctx *context.Context) {
ctx,
pv,
&packages_service.PackageFileInfo{
- Filename: ctx.Params("filename"),
+ Filename: ctx.Params("filename"),
+ CompositeKey: ctx.Params("group"),
},
)
if err != nil {
@@ -145,7 +149,7 @@ func UploadPackageFile(ctx *context.Context) {
apiError(ctx, http.StatusInternalServerError, err)
return
}
-
+ group := ctx.Params("group")
_, _, err = packages_service.CreatePackageOrAddFileToExisting(
ctx,
&packages_service.PackageCreationInfo{
@@ -153,14 +157,15 @@ func UploadPackageFile(ctx *context.Context) {
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeRpm,
Name: pck.Name,
- Version: pck.Version,
+ Version: strings.Trim(fmt.Sprintf("%s/%s", group, pck.Version), "/"),
},
Creator: ctx.Doer,
Metadata: pck.VersionMetadata,
},
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
- Filename: fmt.Sprintf("%s-%s.%s.rpm", pck.Name, pck.Version, pck.FileMetadata.Architecture),
+ Filename: fmt.Sprintf("%s-%s.%s.rpm", pck.Name, pck.Version, pck.FileMetadata.Architecture),
+ CompositeKey: group,
},
Creator: ctx.Doer,
Data: buf,
@@ -182,7 +187,7 @@ func UploadPackageFile(ctx *context.Context) {
return
}
- if err := rpm_service.BuildRepositoryFiles(ctx, ctx.Package.Owner.ID); err != nil {
+ if err := rpm_service.BuildRepositoryFiles(ctx, ctx.Package.Owner.ID, group); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
@@ -191,19 +196,20 @@ func UploadPackageFile(ctx *context.Context) {
}
func DownloadPackageFile(ctx *context.Context) {
+ group := ctx.Params("group")
name := ctx.Params("name")
version := ctx.Params("version")
-
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
ctx,
&packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeRpm,
Name: name,
- Version: version,
+ Version: strings.Trim(fmt.Sprintf("%s/%s", group, version), "/"),
},
&packages_service.PackageFileInfo{
- Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.Params("architecture")),
+ Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.Params("architecture")),
+ CompositeKey: group,
},
)
if err != nil {
@@ -219,14 +225,19 @@ func DownloadPackageFile(ctx *context.Context) {
}
func DeletePackageFile(webctx *context.Context) {
+ group := webctx.Params("group")
name := webctx.Params("name")
version := webctx.Params("version")
architecture := webctx.Params("architecture")
-
var pd *packages_model.PackageDescriptor
err := db.WithTx(webctx, func(ctx stdctx.Context) error {
- pv, err := packages_model.GetVersionByNameAndVersion(ctx, webctx.Package.Owner.ID, packages_model.TypeRpm, name, version)
+ pv, err := packages_model.GetVersionByNameAndVersion(ctx,
+ webctx.Package.Owner.ID,
+ packages_model.TypeRpm,
+ name,
+ strings.Trim(fmt.Sprintf("%s/%s", group, version), "/"),
+ )
if err != nil {
return err
}
@@ -235,7 +246,7 @@ func DeletePackageFile(webctx *context.Context) {
ctx,
pv.ID,
fmt.Sprintf("%s-%s.%s.rpm", name, version, architecture),
- packages_model.EmptyFileKey,
+ group,
)
if err != nil {
return err
@@ -275,7 +286,7 @@ func DeletePackageFile(webctx *context.Context) {
notify_service.PackageDelete(webctx, webctx.Doer, pd)
}
- if err := rpm_service.BuildRepositoryFiles(webctx, webctx.Package.Owner.ID); err != nil {
+ if err := rpm_service.BuildRepositoryFiles(webctx, webctx.Package.Owner.ID, group); err != nil {
apiError(webctx, http.StatusInternalServerError, err)
return
}