From 4ced55fd0b2e36ae06cac6f48c157583fc609f73 Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 9 Sep 2023 15:42:46 +0800 Subject: [PATCH 01/23] Remove extraneous code and prepare for commit --- docs/content/usage/packages/rpm.en-us.md | 36 +++++---- docs/content/usage/packages/rpm.zh-cn.md | 28 ++++--- models/migrations/migrations.go | 2 + models/migrations/v1_21/v276.go | 86 ++++++++++++++++++++++ modules/packages/rpm/metadata.go | 13 +++- options/locale/locale_en-US.ini | 4 + routers/api/packages/api.go | 14 ++-- routers/api/packages/rpm/rpm.go | 35 +++++---- routers/web/user/package.go | 20 +++++ services/packages/rpm/repository.go | 39 +++++----- templates/package/content/rpm.tmpl | 40 +++++++--- tests/integration/api_packages_rpm_test.go | 20 ++--- 12 files changed, 250 insertions(+), 87 deletions(-) create mode 100644 models/migrations/v1_21/v276.go diff --git a/docs/content/usage/packages/rpm.en-us.md b/docs/content/usage/packages/rpm.en-us.md index 5a4a31ee39dfe..7b23aa0e10916 100644 --- a/docs/content/usage/packages/rpm.en-us.md +++ b/docs/content/usage/packages/rpm.en-us.md @@ -27,17 +27,19 @@ The following examples use `dnf`. To register the RPM registry add the url to the list of known apt sources: ```shell -dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm.repo +dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}.repo ``` -| Placeholder | Description | -| ----------- | ----------- | -| `owner` | The owner of the package. | +| Placeholder | Description | +| ----------- |----------------------------------------------------| +| `owner` | The owner of the package. | +| `distribution` | System Name, e.g. `centos`, `suse` , `rockylinux`. | +| `component` | System version, e.g. `el7`, `el9` , `fc38`. | 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): ```shell -dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm.repo +dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}.repo ``` You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.repos.d` too. @@ -47,19 +49,21 @@ You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum. To publish a RPM package (`*.rpm`), perform a HTTP PUT operation with the package content in the request body. ``` -PUT https://gitea.example.com/api/packages/{owner}/rpm/upload +PUT https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}/upload ``` | Parameter | Description | | --------- | ----------- | | `owner` | The owner of the package. | +| `distribution` | System Name, e.g. `centos`, `suse` , `rockylinux`. | +| `component` | System version, e.g. `el7`, `el9` , `fc38`. | Example request using HTTP Basic authentication: ```shell curl --user your_username:your_password_or_token \ --upload-file path/to/file.rpm \ - https://gitea.example.com/api/packages/testuser/rpm/upload + https://gitea.example.com/api/packages/testuser/rpm/centos/el7/upload ``` If you are using 2FA or OAuth use a [personal access token](development/api-usage.md#authentication) instead of the password. @@ -78,21 +82,23 @@ The server responds with the following HTTP Status codes. To delete an RPM package perform a HTTP DELETE operation. This will delete the package version too if there is no file left. ``` -DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture} +DELETE https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/package/{package_name}/{package_version}/{architecture} ``` -| Parameter | Description | -| ----------------- | ----------- | -| `owner` | The owner of the package. | -| `package_name` | The package name. | -| `package_version` | The package version. | -| `architecture` | The package architecture. | +| Parameter | Description | +|-------------------|----------------------------| +| `owner` | The owner of the package. | +| `distribution` | The package distribution. | +| `component` | The package group version. | +| `package_name` | The package name. | +| `package_version` | The package version. | +| `architecture` | The package architecture. | Example request using HTTP Basic authentication: ```shell curl --user your_username:your_token_or_password -X DELETE \ - https://gitea.example.com/api/packages/testuser/rpm/test-package/1.0.0/x86_64 + https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64 ``` The server responds with the following HTTP Status codes. diff --git a/docs/content/usage/packages/rpm.zh-cn.md b/docs/content/usage/packages/rpm.zh-cn.md index 3cc7dca8ff2cf..dd64f97573132 100644 --- a/docs/content/usage/packages/rpm.zh-cn.md +++ b/docs/content/usage/packages/rpm.zh-cn.md @@ -27,17 +27,19 @@ menu: 要注册RPM注册表,请将 URL 添加到已知 `apt` 源列表中: ```shell -dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm.repo +dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}.repo ``` -| 占位符 | 描述 | -| ------- | -------------- | -| `owner` | 软件包的所有者 | +| 占位符 | 描述 | +| ------- |--------------------------------------| +| `owner` | 软件包的所有者 | +| `distribution` | 软件包适配的系统名称,例如 `centos`、`rocky linux` | +| `component` | 软件包适合的目标版本,例如 `el7`、`fc38` | 如果注册表是私有的,请在URL中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证): ```shell -dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm.repo +dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}.repo ``` 您还必须将凭据添加到 `/etc/yum.repos.d` 中的 `rpm.repo` 文件中的URL中。 @@ -47,19 +49,21 @@ dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea. 要发布RPM软件包(`*.rpm`),请执行带有软件包内容的 HTTP `PUT` 操作。 ``` -PUT https://gitea.example.com/api/packages/{owner}/rpm/upload +PUT https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}/upload ``` | 参数 | 描述 | -| ------- | -------------- | -| `owner` | 软件包的所有者 | +| ------- |--------------| +| `owner` | 软件包的所有者 | +| `distribution` | 软件包适配的系统名称 | +| `component` | 软件包适配的系统发行版本 | 使用HTTP基本身份验证的示例请求: ```shell curl --user your_username:your_password_or_token \ --upload-file path/to/file.rpm \ - https://gitea.example.com/api/packages/testuser/rpm/upload + https://gitea.example.com/api/packages/testuser/rpm/centos/el7/version/upload ``` 如果您使用 2FA 或 OAuth,请使用[个人访问令牌](development/api-usage.md#通过-api-认证)替代密码。您无法将具有相同名称的文件两次发布到软件包中。您必须先删除现有的软件包版本。 @@ -77,12 +81,14 @@ curl --user your_username:your_password_or_token \ 要删除 RPM 软件包,请执行 HTTP `DELETE` 操作。如果没有文件剩余,这也将删除软件包版本。 ``` -DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture} +DELETE https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}/package/{package_name}/{package_version}/{architecture} ``` | 参数 | 描述 | | ----------------- | -------------- | | `owner` | 软件包的所有者 | +| `distribution` | 软件包适配的系统名称 | +| `component` | 软件包适配的系统发行版本 | | `package_name` | 软件包名称 | | `package_version` | 软件包版本 | | `architecture` | 软件包架构 | @@ -91,7 +97,7 @@ DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{packag ```shell curl --user your_username:your_token_or_password -X DELETE \ - https://gitea.example.com/api/packages/testuser/rpm/test-package/1.0.0/x86_64 + https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64 ``` 服务器将以以下HTTP状态码响应: diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index f0a8b05d5337d..901fc0cb8cd8c 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -532,6 +532,8 @@ var migrations = []Migration{ NewMigration("Add Actions artifacts expiration date", v1_21.AddExpiredUnixColumnInActionArtifactTable), // v275 -> v276 NewMigration("Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun), + // v276 -> v277 + NewMigration("Migrate old rpm package index", v1_21.RebuildRpmPackage), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_21/v276.go b/models/migrations/v1_21/v276.go new file mode 100644 index 0000000000000..2d27bdd313156 --- /dev/null +++ b/models/migrations/v1_21/v276.go @@ -0,0 +1,86 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_21 //nolint + +import ( + "fmt" + + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/packages/rpm" + + "xorm.io/xorm" +) + +func RebuildRpmPackage(x *xorm.Engine) error { + sess := x.NewSession() + defer sess.Close() + defaultDistribution := rpm.RepositoryDefaultDistribution + defaultComponent := rpm.RepositoryDefaultComponent + compositeKey, _ := fmt.Printf("%s|%s", defaultDistribution, defaultComponent) + // select all old rpm package + var oldRpmIds []int64 + ss := sess.Cols("id"). + Table("package_file"). + Where("composite_key not like", "%|%"). + And("lower_name like ?", "%.rpm") + err := ss.Find(&oldRpmIds) + if err != nil { + return err + } + // add metadata + // NOTE: package_property[name='rpm.metdata'] is very large, + // and to avoid querying all of them resulting in large memory, + // a single RPM package is now used for updating. + for _, id := range oldRpmIds { + + metadata := make([]string, 0, 3) + _, err := sess.Cols("ref_type", "ref_id", "value"). + Table("package_property"). + Where("name = 'rpm.metdata'"). + And("ref_id = ?", id). + Get(&metadata) + if err != nil { + return err + } + // get rpm info + var rpmMetadata rpm.FileMetadata + err = json.Unmarshal([]byte(metadata[2]), &rpmMetadata) + if err != nil { + return err + } + _, err = sess.Exec( + "INSERT INTO package_property(ref_type, ref_id, name, value) values (?,?,?,?),(?,?,?,?),(?,?,?,?)", + metadata[0], metadata[1], "rpm.distribution", defaultDistribution, + metadata[0], metadata[1], "rpm.component", defaultComponent, + metadata[0], metadata[1], "rpm.architecture", rpmMetadata.Architecture, + ) + if err != nil { + return err + } + // set default distribution + _, err = sess.Table("package_file"). + Where("id = ?", id). + Update(map[string]any{ + "composite_key": compositeKey, + }) + if err != nil { + return err + } + } + // set old rpm index file to default distribution + _, err = sess.Table("package_file"). + Where( + "composite_key = '' AND " + + "lower_name IN" + + "(" + + "'primary.xml.gz','other.xml.gz','filelists.xml.gz','other.xml.gz','repomd.xml','repomd.xml.asc'" + + ")"). + Update(map[string]any{ + "composite_key": compositeKey, + }) + if err != nil { + return err + } + return nil +} diff --git a/modules/packages/rpm/metadata.go b/modules/packages/rpm/metadata.go index f019a8dde1aaa..32e0a2d263cc0 100644 --- a/modules/packages/rpm/metadata.go +++ b/modules/packages/rpm/metadata.go @@ -15,13 +15,18 @@ import ( ) const ( - PropertyMetadata = "rpm.metadata" - - SettingKeyPrivate = "rpm.key.private" - SettingKeyPublic = "rpm.key.public" + PropertyMetadata = "rpm.metadata" + PropertyDistribution = "rpm.distribution" + PropertyComponent = "rpm.component" + PropertyArchitecture = "rpm.architecture" + SettingKeyPrivate = "rpm.key.private" + SettingKeyPublic = "rpm.key.public" RepositoryPackage = "_rpm" RepositoryVersion = "_repository" + + RepositoryDefaultDistribution = "default" + RepositoryDefaultComponent = "stable" ) const ( diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 39da4be17900e..9c94940e6ff91 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3383,6 +3383,10 @@ rpm.registry = Setup this registry from the command line: rpm.distros.redhat = on RedHat based distributions rpm.distros.suse = on SUSE based distributions rpm.install = To install the package, run the following command: +rpm.package.info = Package Info +rpm.package.architectures = Architectures +rpm.package.description = Description +rpm.package.summary = Summary rubygems.install = To install the package using gem, run the following command: rubygems.install2 = or add it to the Gemfile: rubygems.dependencies.runtime = Runtime Dependencies diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 2ba35e21380b2..1c59db10a29e4 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -513,14 +513,16 @@ func CommonRoutes() *web.Route { 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("/{distribution}/{component}", func() { + r.Get(".repo", rpm.GetRepositoryConfig) + 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.Get("/repodata/{filename}", rpm.GetRepositoryFile) }) - r.Get("/repodata/{filename}", rpm.GetRepositoryFile) }, reqPackageAccess(perm.AccessModeRead)) r.Group("/rubygems", func() { r.Get("/specs.4.8.gz", rubygems.EnumeratePackages) diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index 1e462bb9080f4..5ad724b479375 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -33,11 +33,13 @@ func apiError(ctx *context.Context, status int, obj any) { // https://dnf.readthedocs.io/en/latest/conf_ref.html func GetRepositoryConfig(ctx *context.Context) { + distribution := ctx.Params("distribution") + component := ctx.Params("component") 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+`-`+distribution+`-`+component+`] +name=`+ctx.Package.Owner.Name+` - `+setting.AppName+` - `+distribution+` - `+component+` +baseurl=`+url+`/`+distribution+`/`+component+` enabled=1 gpgcheck=1 gpgkey=`+url+`/repository.key`) @@ -69,7 +71,8 @@ func GetRepositoryFile(ctx *context.Context) { ctx, pv, &packages_service.PackageFileInfo{ - Filename: ctx.Params("filename"), + Filename: ctx.Params("filename"), + CompositeKey: fmt.Sprintf("%s|%s", ctx.Params("distribution"), ctx.Params("component")), }, ) if err != nil { @@ -121,7 +124,9 @@ func UploadPackageFile(ctx *context.Context) { apiError(ctx, http.StatusInternalServerError, err) return } - + distribution := ctx.Params("distribution") + component := ctx.Params("component") + compositeKey := fmt.Sprintf("%s|%s", distribution, component) _, _, err = packages_service.CreatePackageOrAddFileToExisting( &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ @@ -135,13 +140,17 @@ func UploadPackageFile(ctx *context.Context) { }, &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: compositeKey, }, Creator: ctx.Doer, Data: buf, IsLead: true, Properties: map[string]string{ - rpm_module.PropertyMetadata: string(fileMetadataRaw), + rpm_module.PropertyMetadata: string(fileMetadataRaw), + rpm_module.PropertyDistribution: distribution, + rpm_module.PropertyComponent: component, + rpm_module.PropertyArchitecture: pck.FileMetadata.Architecture, }, }, ) @@ -157,7 +166,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, compositeKey); err != nil { apiError(ctx, http.StatusInternalServerError, err) return } @@ -168,7 +177,6 @@ func UploadPackageFile(ctx *context.Context) { func DownloadPackageFile(ctx *context.Context) { name := ctx.Params("name") version := ctx.Params("version") - s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion( ctx, &packages_service.PackageInfo{ @@ -178,7 +186,8 @@ func DownloadPackageFile(ctx *context.Context) { Version: 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: fmt.Sprintf("%s|%s", ctx.Params("distribution"), ctx.Params("component")), }, ) if err != nil { @@ -197,7 +206,7 @@ func DeletePackageFile(webctx *context.Context) { name := webctx.Params("name") version := webctx.Params("version") architecture := webctx.Params("architecture") - + compositeKey := fmt.Sprintf("%s|%s", webctx.Params("distribution"), webctx.Params("component")) var pd *packages_model.PackageDescriptor err := db.WithTx(webctx, func(ctx stdctx.Context) error { @@ -210,7 +219,7 @@ func DeletePackageFile(webctx *context.Context) { ctx, pv.ID, fmt.Sprintf("%s-%s.%s.rpm", name, version, architecture), - packages_model.EmptyFileKey, + compositeKey, ) if err != nil { return err @@ -250,7 +259,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, compositeKey); err != nil { apiError(webctx, http.StatusInternalServerError, err) return } diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 57770b2b1aed8..b99aa22b315e4 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/log" alpine_module "code.gitea.io/gitea/modules/packages/alpine" debian_module "code.gitea.io/gitea/modules/packages/debian" + rpm_module "code.gitea.io/gitea/modules/packages/rpm" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -219,6 +220,25 @@ func ViewPackageVersion(ctx *context.Context) { ctx.Data["Distributions"] = distributions.Values() ctx.Data["Components"] = components.Values() ctx.Data["Architectures"] = architectures.Values() + case packages_model.TypeRpm: + distributions := make(container.Set[string]) + components := make(container.Set[string]) + architectures := make(container.Set[string]) + for _, f := range pd.Files { + for _, pp := range f.Properties { + switch pp.Name { + case rpm_module.PropertyComponent: + components.Add(pp.Value) + case rpm_module.PropertyDistribution: + distributions.Add(pp.Value) + case rpm_module.PropertyArchitecture: + architectures.Add(pp.Value) + } + } + } + ctx.Data["Distributions"] = distributions.Values() + ctx.Data["Architectures"] = architectures.Values() + ctx.Data["Components"] = components.Values() } var ( diff --git a/services/packages/rpm/repository.go b/services/packages/rpm/repository.go index cfd70ec23e2c7..1deb4d69bfd7e 100644 --- a/services/packages/rpm/repository.go +++ b/services/packages/rpm/repository.go @@ -127,16 +127,17 @@ type packageData struct { type packageCache = map[*packages_model.PackageFile]*packageData // BuildSpecificRepositoryFiles builds metadata files for the repository -func BuildRepositoryFiles(ctx context.Context, ownerID int64) error { +func BuildRepositoryFiles(ctx context.Context, ownerID int64, compositeKey string) error { pv, err := GetOrCreateRepositoryVersion(ownerID) if err != nil { return err } pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{ - OwnerID: ownerID, - PackageType: packages_model.TypeRpm, - Query: "%.rpm", + OwnerID: ownerID, + PackageType: packages_model.TypeRpm, + Query: "%.rpm", + CompositeKey: compositeKey, }) if err != nil { return err @@ -198,15 +199,15 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error { cache[pf] = pd } - primary, err := buildPrimary(pv, pfs, cache) + primary, err := buildPrimary(pv, pfs, cache, compositeKey) if err != nil { return err } - filelists, err := buildFilelists(pv, pfs, cache) + filelists, err := buildFilelists(pv, pfs, cache, compositeKey) if err != nil { return err } - other, err := buildOther(pv, pfs, cache) + other, err := buildOther(pv, pfs, cache, compositeKey) if err != nil { return err } @@ -219,11 +220,12 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error { filelists, other, }, + compositeKey, ) } // https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#repomd-xml -func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoData) error { +func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoData, distribution string) error { type Repomd struct { XMLName xml.Name `xml:"repomd"` Xmlns string `xml:"xmlns,attr"` @@ -274,7 +276,8 @@ func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoD pv, &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ - Filename: file.Name, + Filename: file.Name, + CompositeKey: distribution, }, Creator: user_model.NewGhostUser(), Data: file.Data, @@ -291,7 +294,7 @@ func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoD } // https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#primary-xml -func buildPrimary(pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { +func buildPrimary(pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) { type Version struct { Epoch string `xml:"epoch,attr"` Version string `xml:"ver,attr"` @@ -430,11 +433,11 @@ func buildPrimary(pv *packages_model.PackageVersion, pfs []*packages_model.Packa XmlnsRpm: "http://linux.duke.edu/metadata/rpm", PackageCount: len(pfs), Packages: packages, - }) + }, compositeKey) } // https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#filelists-xml -func buildFilelists(pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl +func buildFilelists(pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) { //nolint:dupl type Version struct { Epoch string `xml:"epoch,attr"` Version string `xml:"ver,attr"` @@ -477,11 +480,12 @@ func buildFilelists(pv *packages_model.PackageVersion, pfs []*packages_model.Pac Xmlns: "http://linux.duke.edu/metadata/other", PackageCount: len(pfs), Packages: packages, - }) + }, + compositeKey) } // https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#other-xml -func buildOther(pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl +func buildOther(pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) { //nolint:dupl type Version struct { Epoch string `xml:"epoch,attr"` Version string `xml:"ver,attr"` @@ -524,7 +528,7 @@ func buildOther(pv *packages_model.PackageVersion, pfs []*packages_model.Package Xmlns: "http://linux.duke.edu/metadata/other", PackageCount: len(pfs), Packages: packages, - }) + }, compositeKey) } // writtenCounter counts all written bytes @@ -544,7 +548,7 @@ func (wc *writtenCounter) Written() int64 { return wc.written } -func addDataAsFileToRepo(pv *packages_model.PackageVersion, filetype string, obj any) (*repoData, error) { +func addDataAsFileToRepo(pv *packages_model.PackageVersion, filetype string, obj any, distribution string) (*repoData, error) { content, _ := packages_module.NewHashedBuffer() gzw := gzip.NewWriter(content) wc := &writtenCounter{} @@ -567,7 +571,8 @@ func addDataAsFileToRepo(pv *packages_model.PackageVersion, filetype string, obj pv, &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ - Filename: filename, + Filename: filename, + CompositeKey: distribution, }, Creator: user_model.NewGhostUser(), Data: content, diff --git a/templates/package/content/rpm.tmpl b/templates/package/content/rpm.tmpl index fc7af639aa30a..1d55549efc6f4 100644 --- a/templates/package/content/rpm.tmpl +++ b/templates/package/content/rpm.tmpl @@ -4,19 +4,19 @@
-
# {{.locale.Tr "packages.rpm.distro.redhat"}}
-dnf config-manager --add-repo 
+				
# {{.locale.Tr "packages.rpm.distros.redhat"}}
+dnf config-manager --add-repo 
 
-# {{.locale.Tr "packages.rpm.distro.suse"}}
-zypper addrepo 
+# {{.locale.Tr "packages.rpm.distros.suse"}} +zypper addrepo
-
# {{.locale.Tr "packages.rpm.distro.redhat"}}
+					
# {{.locale.Tr "packages.rpm.distros.redhat"}}
 dnf install {{$.PackageDescriptor.Package.Name}}
 
-# {{.locale.Tr "packages.rpm.distro.suse"}}
+# {{.locale.Tr "packages.rpm.distros.suse"}}
 zypper install {{$.PackageDescriptor.Package.Name}}
@@ -26,9 +26,27 @@ zypper install {{$.PackageDescriptor.Package.Name}}
- {{if or .PackageDescriptor.Metadata.Summary .PackageDescriptor.Metadata.Description}} -

{{.locale.Tr "packages.about"}}

- {{if .PackageDescriptor.Metadata.Summary}}
{{.PackageDescriptor.Metadata.Summary}}
{{end}} - {{if .PackageDescriptor.Metadata.Description}}
{{.PackageDescriptor.Metadata.Description}}
{{end}} - {{end}} +

{{.locale.Tr "packages.rpm.package.info"}}

+
+ + + + + + + {{if .PackageDescriptor.Metadata.Summary}} + + + + + {{end}} + {{if .PackageDescriptor.Metadata.Description}} + + + + + {{end}} + +
{{.locale.Tr "packages.rpm.package.architectures"}}
{{StringUtils.Join .Architectures ", "}}
{{.locale.Tr "packages.rpm.package.summary"}}
{{.PackageDescriptor.Metadata.Summary}}
{{.locale.Tr "packages.rpm.package.description"}}
{{.PackageDescriptor.Metadata.Description}}
+
{{end}} diff --git a/tests/integration/api_packages_rpm_test.go b/tests/integration/api_packages_rpm_test.go index fc4c4d1c4b66c..28d0aaad5ae1f 100644 --- a/tests/integration/api_packages_rpm_test.go +++ b/tests/integration/api_packages_rpm_test.go @@ -76,12 +76,12 @@ Mu0UFYgZ/bYnuvn/vz4wtCz8qMwsHUvP0PX3tbYFUctAPdrY6tiiDtcCddDECahx7SuVNP5dpmb5 t.Run("RepositoryConfig", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - req := NewRequest(t, "GET", rootURL+".repo") + req := NewRequest(t, "GET", rootURL+"/el9/stable.repo") resp := MakeRequest(t, req, http.StatusOK) - expected := fmt.Sprintf(`[gitea-%s] -name=%s - %s -baseurl=%sapi/packages/%s/rpm + expected := fmt.Sprintf(`[gitea-%s-el9-stable] +name=%s - %s - el9 - stable +baseurl=%sapi/packages/%s/rpm/el9/stable enabled=1 gpgcheck=1 gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppName, setting.AppURL, user.Name, setting.AppURL, user.Name) @@ -100,7 +100,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN }) t.Run("Upload", func(t *testing.T) { - url := rootURL + "/upload" + url := rootURL + "/el9/stable/upload" req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)) MakeRequest(t, req, http.StatusUnauthorized) @@ -138,7 +138,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN t.Run("Download", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - req := NewRequest(t, "GET", fmt.Sprintf("%s/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)) + req := NewRequest(t, "GET", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)) resp := MakeRequest(t, req, http.StatusOK) assert.Equal(t, content, resp.Body.Bytes()) @@ -147,7 +147,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN t.Run("Repository", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - url := rootURL + "/repodata" + url := rootURL + "/el9/stable/repodata" req := NewRequest(t, "GET", url+"/dummy.xml") MakeRequest(t, req, http.StatusNotFound) @@ -395,10 +395,10 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN t.Run("Delete", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - req := NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)) + req := NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)) MakeRequest(t, req, http.StatusUnauthorized) - req = NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)) + req = NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)) req = AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusNoContent) @@ -406,7 +406,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN assert.NoError(t, err) assert.Empty(t, pvs) - req = NewRequest(t, "DELETE", fmt.Sprintf("%s/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)) + req = NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)) req = AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusNotFound) }) From f3c4131b1702d47894ef569b86cd554c63f044a2 Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 9 Sep 2023 16:53:30 +0800 Subject: [PATCH 02/23] Change rpm help description --- options/locale/locale_en-US.ini | 2 ++ templates/package/content/rpm.tmpl | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 9c94940e6ff91..8cf57982a767c 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3384,6 +3384,8 @@ rpm.distros.redhat = on RedHat based distributions rpm.distros.suse = on SUSE based distributions rpm.install = To install the package, run the following command: rpm.package.info = Package Info +rpm.package.distributions.support = Specify the distribution , for example: +rpm.package.components.support = Specifies the distribution version, for example: rpm.package.architectures = Architectures rpm.package.description = Description rpm.package.summary = Summary diff --git a/templates/package/content/rpm.tmpl b/templates/package/content/rpm.tmpl index 1d55549efc6f4..21dcfb3b20bc9 100644 --- a/templates/package/content/rpm.tmpl +++ b/templates/package/content/rpm.tmpl @@ -4,11 +4,17 @@
-
# {{.locale.Tr "packages.rpm.distros.redhat"}}
-dnf config-manager --add-repo 
+				
# {{.locale.Tr "packages.rpm.package.distributions.support"}}  {{StringUtils.Join .Distributions ", "}}
+export distribution='{{index .Distributions 0}}'
+
+# {{.locale.Tr "packages.rpm.package.components.support"}}  {{StringUtils.Join .Components ", "}}
+export component='{{index .Components 0}}'
+
+# {{.locale.Tr "packages.rpm.distros.redhat"}}
+dnf config-manager --add-repo 
 
 # {{.locale.Tr "packages.rpm.distros.suse"}}
-zypper addrepo 
+zypper addrepo
From 895f419d42d5f8a3de442769bb85d5416688f96d Mon Sep 17 00:00:00 2001 From: dragon Date: Sun, 10 Sep 2023 13:51:58 +0800 Subject: [PATCH 03/23] Fix bugs and optimize queries --- models/migrations/v1_21/v276.go | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/models/migrations/v1_21/v276.go b/models/migrations/v1_21/v276.go index 2d27bdd313156..36235868c6029 100644 --- a/models/migrations/v1_21/v276.go +++ b/models/migrations/v1_21/v276.go @@ -15,21 +15,19 @@ import ( func RebuildRpmPackage(x *xorm.Engine) error { sess := x.NewSession() defer sess.Close() - defaultDistribution := rpm.RepositoryDefaultDistribution - defaultComponent := rpm.RepositoryDefaultComponent - compositeKey, _ := fmt.Printf("%s|%s", defaultDistribution, defaultComponent) + compositeKey, _ := fmt.Printf("%s|%s", rpm.RepositoryDefaultDistribution, rpm.RepositoryDefaultComponent) // select all old rpm package var oldRpmIds []int64 ss := sess.Cols("id"). Table("package_file"). - Where("composite_key not like", "%|%"). + Where("composite_key not like ?", "%|%"). And("lower_name like ?", "%.rpm") err := ss.Find(&oldRpmIds) if err != nil { return err } // add metadata - // NOTE: package_property[name='rpm.metdata'] is very large, + // NOTE: package_property[name='rpm.metadata'] is very large, // and to avoid querying all of them resulting in large memory, // a single RPM package is now used for updating. for _, id := range oldRpmIds { @@ -37,7 +35,7 @@ func RebuildRpmPackage(x *xorm.Engine) error { metadata := make([]string, 0, 3) _, err := sess.Cols("ref_type", "ref_id", "value"). Table("package_property"). - Where("name = 'rpm.metdata'"). + Where("name = 'rpm.metadata'"). And("ref_id = ?", id). Get(&metadata) if err != nil { @@ -51,8 +49,8 @@ func RebuildRpmPackage(x *xorm.Engine) error { } _, err = sess.Exec( "INSERT INTO package_property(ref_type, ref_id, name, value) values (?,?,?,?),(?,?,?,?),(?,?,?,?)", - metadata[0], metadata[1], "rpm.distribution", defaultDistribution, - metadata[0], metadata[1], "rpm.component", defaultComponent, + metadata[0], metadata[1], "rpm.distribution", rpm.RepositoryDefaultDistribution, + metadata[0], metadata[1], "rpm.component", rpm.RepositoryDefaultComponent, metadata[0], metadata[1], "rpm.architecture", rpmMetadata.Architecture, ) if err != nil { @@ -71,11 +69,10 @@ func RebuildRpmPackage(x *xorm.Engine) error { // set old rpm index file to default distribution _, err = sess.Table("package_file"). Where( - "composite_key = '' AND " + - "lower_name IN" + - "(" + - "'primary.xml.gz','other.xml.gz','filelists.xml.gz','other.xml.gz','repomd.xml','repomd.xml.asc'" + - ")"). + `composite_key = '' AND + lower_name IN + ('primary.xml.gz','other.xml.gz','filelists.xml.gz','other.xml.gz','repomd.xml','repomd.xml.asc')`, + ). Update(map[string]any{ "composite_key": compositeKey, }) From e1e2575fc3d080d0a2d70fb433e7074462612c24 Mon Sep 17 00:00:00 2001 From: Exploding Dragon Date: Mon, 11 Sep 2023 01:54:49 +0000 Subject: [PATCH 04/23] Fix formatting --- models/migrations/v1_21/v276.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/migrations/v1_21/v276.go b/models/migrations/v1_21/v276.go index 36235868c6029..93776edaffa59 100644 --- a/models/migrations/v1_21/v276.go +++ b/models/migrations/v1_21/v276.go @@ -15,7 +15,7 @@ import ( func RebuildRpmPackage(x *xorm.Engine) error { sess := x.NewSession() defer sess.Close() - compositeKey, _ := fmt.Printf("%s|%s", rpm.RepositoryDefaultDistribution, rpm.RepositoryDefaultComponent) + compositeKey := fmt.Sprintf("%s|%s", rpm.RepositoryDefaultDistribution, rpm.RepositoryDefaultComponent) // select all old rpm package var oldRpmIds []int64 ss := sess.Cols("id"). From 51596b60d917931086e31a4261ae9431016d938e Mon Sep 17 00:00:00 2001 From: Exploding Dragon Date: Tue, 12 Sep 2023 07:04:42 +0000 Subject: [PATCH 05/23] Fix some problems --- routers/api/packages/api.go | 4 ++++ services/packages/rpm/repository.go | 22 ++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 1c59db10a29e4..ba40516e85e69 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -519,6 +519,10 @@ func CommonRoutes() *web.Route { r.Put("/upload", reqPackageAccess(perm.AccessModeWrite), rpm.UploadPackageFile) r.Group("/package/{name}/{version}/{architecture}", func() { r.Get("", rpm.DownloadPackageFile) + // yum/dnf client does not recognize the filename of the header. + // which will result in a failure to hit the cache locally. + // So add a new spurious route + r.Get("/{file_name}", rpm.DownloadPackageFile) r.Delete("", reqPackageAccess(perm.AccessModeWrite), rpm.DeletePackageFile) }) r.Get("/repodata/{filename}", rpm.GetRepositoryFile) diff --git a/services/packages/rpm/repository.go b/services/packages/rpm/repository.go index 1deb4d69bfd7e..8128e484b8aac 100644 --- a/services/packages/rpm/repository.go +++ b/services/packages/rpm/repository.go @@ -150,11 +150,13 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64, compositeKey strin return err } for _, pf := range pfs { - if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil { - return err - } - if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil { - return err + if compositeKey == pf.CompositeKey { + if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil { + return err + } + if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil { + return err + } } } @@ -225,7 +227,7 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64, compositeKey strin } // https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#repomd-xml -func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoData, distribution string) error { +func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoData, compositeKey string) error { type Repomd struct { XMLName xml.Name `xml:"repomd"` Xmlns string `xml:"xmlns,attr"` @@ -277,7 +279,7 @@ func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoD &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ Filename: file.Name, - CompositeKey: distribution, + CompositeKey: compositeKey, }, Creator: user_model.NewGhostUser(), Data: file.Data, @@ -403,7 +405,7 @@ func buildPrimary(pv *packages_model.PackageVersion, pfs []*packages_model.Packa Archive: pd.FileMetadata.ArchiveSize, }, Location: Location{ - Href: fmt.Sprintf("package/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(pd.Version.Version), url.PathEscape(pd.FileMetadata.Architecture)), + Href: fmt.Sprintf("package/%s/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(pd.Version.Version), url.PathEscape(pd.FileMetadata.Architecture), url.PathEscape(fmt.Sprintf("%s-%s.%s.rpm", pd.Package.Name, pd.Version.Version, pd.FileMetadata.Architecture))), }, Format: Format{ License: pd.VersionMetadata.License, @@ -548,7 +550,7 @@ func (wc *writtenCounter) Written() int64 { return wc.written } -func addDataAsFileToRepo(pv *packages_model.PackageVersion, filetype string, obj any, distribution string) (*repoData, error) { +func addDataAsFileToRepo(pv *packages_model.PackageVersion, filetype string, obj any, compositeKey string) (*repoData, error) { content, _ := packages_module.NewHashedBuffer() gzw := gzip.NewWriter(content) wc := &writtenCounter{} @@ -572,7 +574,7 @@ func addDataAsFileToRepo(pv *packages_model.PackageVersion, filetype string, obj &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ Filename: filename, - CompositeKey: distribution, + CompositeKey: compositeKey, }, Creator: user_model.NewGhostUser(), Data: content, From 6fb18d3189375e0f80a59eb7b9246c95f68a29b5 Mon Sep 17 00:00:00 2001 From: Exploding Dragon Date: Wed, 13 Sep 2023 01:19:00 +0000 Subject: [PATCH 06/23] fix tests --- tests/integration/api_packages_rpm_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/integration/api_packages_rpm_test.go b/tests/integration/api_packages_rpm_test.go index 28d0aaad5ae1f..d6885262a5263 100644 --- a/tests/integration/api_packages_rpm_test.go +++ b/tests/integration/api_packages_rpm_test.go @@ -195,8 +195,8 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN switch d.Type { case "primary": - assert.EqualValues(t, 718, d.Size) - assert.EqualValues(t, 1729, d.OpenSize) + assert.EqualValues(t, 722, d.Size) + assert.EqualValues(t, 1759, d.OpenSize) assert.Equal(t, "repodata/primary.xml.gz", d.Location.Href) case "filelists": assert.EqualValues(t, 257, d.Size) @@ -305,7 +305,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN assert.EqualValues(t, len(content), p.Size.Package) assert.EqualValues(t, 13, p.Size.Installed) assert.EqualValues(t, 272, p.Size.Archive) - assert.Equal(t, fmt.Sprintf("package/%s/%s/%s", packageName, packageVersion, packageArchitecture), p.Location.Href) + assert.Equal(t, fmt.Sprintf("package/%s/%s/%s/%s", packageName, packageVersion, packageArchitecture, fmt.Sprintf("%s-%s.%s.rpm", packageName, packageVersion, packageArchitecture)), p.Location.Href) f := p.Format assert.Equal(t, "MIT", f.License) assert.Len(t, f.Provides.Entries, 2) From b860b79eb558073471eb4e95e2e672484688f216 Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 28 Oct 2023 12:28:02 +0800 Subject: [PATCH 07/23] Merge branch 'main' of into feature-rpm-dist --- models/migrations/migrations.go | 2 +- models/migrations/v1_22/v282.go | 83 +++++++++++++++++++++++++++++ templates/package/metadata/rpm.tmpl | 2 + 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 models/migrations/v1_22/v282.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index f82978518d23d..48d63a2912f48 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -549,7 +549,7 @@ var migrations = []Migration{ // v281 -> v282 NewMigration("Add auth_token table", v1_22.CreateAuthTokenTable), // v282 -> v283 - NewMigration("Migrate old rpm package index", v1_21.RebuildRpmPackage), + NewMigration("Migrate old rpm package index", v1_22.RebuildRpmPackage), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_22/v282.go b/models/migrations/v1_22/v282.go new file mode 100644 index 0000000000000..501f61139453c --- /dev/null +++ b/models/migrations/v1_22/v282.go @@ -0,0 +1,83 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_22 //nolint + +import ( + "fmt" + + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/packages/rpm" + + "xorm.io/xorm" +) + +func RebuildRpmPackage(x *xorm.Engine) error { + sess := x.NewSession() + defer sess.Close() + compositeKey := fmt.Sprintf("%s|%s", rpm.RepositoryDefaultDistribution, rpm.RepositoryDefaultComponent) + // select all old rpm package + var oldRpmIds []int64 + ss := sess.Cols("id"). + Table("package_file"). + Where("composite_key not like ?", "%|%"). + And("lower_name like ?", "%.rpm") + err := ss.Find(&oldRpmIds) + if err != nil { + return err + } + // add metadata + // NOTE: package_property[name='rpm.metadata'] is very large, + // and to avoid querying all of them resulting in large memory, + // a single RPM package is now used for updating. + for _, id := range oldRpmIds { + + metadata := make([]string, 0, 3) + _, err := sess.Cols("ref_type", "ref_id", "value"). + Table("package_property"). + Where("name = 'rpm.metadata'"). + And("ref_id = ?", id). + Get(&metadata) + if err != nil { + return err + } + // get rpm info + var rpmMetadata rpm.FileMetadata + err = json.Unmarshal([]byte(metadata[2]), &rpmMetadata) + if err != nil { + return err + } + _, err = sess.Exec( + "INSERT INTO package_property(ref_type, ref_id, name, value) values (?,?,?,?),(?,?,?,?),(?,?,?,?)", + metadata[0], metadata[1], "rpm.distribution", rpm.RepositoryDefaultDistribution, + metadata[0], metadata[1], "rpm.component", rpm.RepositoryDefaultComponent, + metadata[0], metadata[1], "rpm.architecture", rpmMetadata.Architecture, + ) + if err != nil { + return err + } + // set default distribution + _, err = sess.Table("package_file"). + Where("id = ?", id). + Update(map[string]any{ + "composite_key": compositeKey, + }) + if err != nil { + return err + } + } + // set old rpm index file to default distribution + _, err = sess.Table("package_file"). + Where( + `composite_key = '' AND + lower_name IN + ('primary.xml.gz','other.xml.gz','filelists.xml.gz','other.xml.gz','repomd.xml','repomd.xml.asc')`, + ). + Update(map[string]any{ + "composite_key": compositeKey, + }) + if err != nil { + return err + } + return nil +} diff --git a/templates/package/metadata/rpm.tmpl b/templates/package/metadata/rpm.tmpl index 026f129590598..78548faa28629 100644 --- a/templates/package/metadata/rpm.tmpl +++ b/templates/package/metadata/rpm.tmpl @@ -1,4 +1,6 @@ {{if eq .PackageDescriptor.Package.Type "rpm"}} +
{{svg "octicon-location" 16 "gt-mr-3"}} {{index .Distributions 0}}/{{index .Components 0}}
+
{{svg "octicon-server" 16 "gt-mr-3"}} {{StringUtils.Join .Architectures ", "}}
{{if .PackageDescriptor.Metadata.ProjectURL}}
{{svg "octicon-link-external" 16 "gt-mr-3"}} {{ctx.Locale.Tr "packages.details.project_site"}}
{{end}} {{if .PackageDescriptor.Metadata.License}}
{{svg "octicon-law" 16 "gt-mr-3"}} {{.PackageDescriptor.Metadata.License}}
{{end}} {{end}} From ca647ee0d6a61509695ef3017bbf1d246e1de203 Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 28 Oct 2023 12:57:15 +0800 Subject: [PATCH 08/23] compress filter --- modules/packages/rpm/metadata.go | 3 +-- routers/api/packages/api.go | 4 ++-- routers/api/packages/rpm/rpm.go | 22 +++++++++------------- routers/web/user/package.go | 12 ++++-------- templates/package/content/rpm.tmpl | 4 ++-- templates/package/metadata/rpm.tmpl | 2 +- 6 files changed, 19 insertions(+), 28 deletions(-) diff --git a/modules/packages/rpm/metadata.go b/modules/packages/rpm/metadata.go index 32e0a2d263cc0..89559f192839a 100644 --- a/modules/packages/rpm/metadata.go +++ b/modules/packages/rpm/metadata.go @@ -16,8 +16,7 @@ import ( const ( PropertyMetadata = "rpm.metadata" - PropertyDistribution = "rpm.distribution" - PropertyComponent = "rpm.component" + PropertyGroup = "rpm.group" PropertyArchitecture = "rpm.architecture" SettingKeyPrivate = "rpm.key.private" SettingKeyPublic = "rpm.key.public" diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index ba40516e85e69..31120c0bb5722 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -514,7 +514,7 @@ func CommonRoutes() *web.Route { }, reqPackageAccess(perm.AccessModeRead)) r.Group("/rpm", func() { r.Get("/repository.key", rpm.GetRepositoryKey) - r.Group("/{distribution}/{component}", func() { + r.Group("/{group}", func() { r.Get(".repo", rpm.GetRepositoryConfig) r.Put("/upload", reqPackageAccess(perm.AccessModeWrite), rpm.UploadPackageFile) r.Group("/package/{name}/{version}/{architecture}", func() { @@ -522,7 +522,7 @@ func CommonRoutes() *web.Route { // yum/dnf client does not recognize the filename of the header. // which will result in a failure to hit the cache locally. // So add a new spurious route - r.Get("/{file_name}", rpm.DownloadPackageFile) + r.Get("/{_}", rpm.DownloadPackageFile) r.Delete("", reqPackageAccess(perm.AccessModeWrite), rpm.DeletePackageFile) }) r.Get("/repodata/{filename}", rpm.GetRepositoryFile) diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index 8b712078d5f8b..3bc643a50f55f 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -33,13 +33,12 @@ func apiError(ctx *context.Context, status int, obj any) { // https://dnf.readthedocs.io/en/latest/conf_ref.html func GetRepositoryConfig(ctx *context.Context) { - distribution := ctx.Params("distribution") - component := ctx.Params("component") + group := ctx.Params("group") url := fmt.Sprintf("%sapi/packages/%s/rpm", setting.AppURL, ctx.Package.Owner.Name) - ctx.PlainText(http.StatusOK, `[gitea-`+ctx.Package.Owner.LowerName+`-`+distribution+`-`+component+`] -name=`+ctx.Package.Owner.Name+` - `+setting.AppName+` - `+distribution+` - `+component+` -baseurl=`+url+`/`+distribution+`/`+component+` + ctx.PlainText(http.StatusOK, `[gitea-`+ctx.Package.Owner.LowerName+`-`+group+`] +name=`+ctx.Package.Owner.Name+` - `+setting.AppName+` - `+group+` +baseurl=`+url+`/`+group+` enabled=1 gpgcheck=1 gpgkey=`+url+`/repository.key`) @@ -72,7 +71,7 @@ func GetRepositoryFile(ctx *context.Context) { pv, &packages_service.PackageFileInfo{ Filename: ctx.Params("filename"), - CompositeKey: fmt.Sprintf("%s|%s", ctx.Params("distribution"), ctx.Params("component")), + CompositeKey: ctx.Params("group"), }, ) if err != nil { @@ -124,9 +123,7 @@ func UploadPackageFile(ctx *context.Context) { apiError(ctx, http.StatusInternalServerError, err) return } - distribution := ctx.Params("distribution") - component := ctx.Params("component") - compositeKey := fmt.Sprintf("%s|%s", distribution, component) + compositeKey := ctx.Params("group") _, _, err = packages_service.CreatePackageOrAddFileToExisting( ctx, &packages_service.PackageCreationInfo{ @@ -149,8 +146,7 @@ func UploadPackageFile(ctx *context.Context) { IsLead: true, Properties: map[string]string{ rpm_module.PropertyMetadata: string(fileMetadataRaw), - rpm_module.PropertyDistribution: distribution, - rpm_module.PropertyComponent: component, + rpm_module.PropertyGroup: compositeKey, rpm_module.PropertyArchitecture: pck.FileMetadata.Architecture, }, }, @@ -188,7 +184,7 @@ func DownloadPackageFile(ctx *context.Context) { }, &packages_service.PackageFileInfo{ Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.Params("architecture")), - CompositeKey: fmt.Sprintf("%s|%s", ctx.Params("distribution"), ctx.Params("component")), + CompositeKey: ctx.Params("group"), }, ) if err != nil { @@ -207,7 +203,7 @@ func DeletePackageFile(webctx *context.Context) { name := webctx.Params("name") version := webctx.Params("version") architecture := webctx.Params("architecture") - compositeKey := fmt.Sprintf("%s|%s", webctx.Params("distribution"), webctx.Params("component")) + compositeKey := webctx.Params("group") var pd *packages_model.PackageDescriptor err := db.WithTx(webctx, func(ctx stdctx.Context) error { diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 3c1ce5be6846c..7015235aa04e7 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -221,24 +221,20 @@ func ViewPackageVersion(ctx *context.Context) { ctx.Data["Components"] = components.Values() ctx.Data["Architectures"] = architectures.Values() case packages_model.TypeRpm: - distributions := make(container.Set[string]) - components := make(container.Set[string]) + groups := make(container.Set[string]) architectures := make(container.Set[string]) for _, f := range pd.Files { for _, pp := range f.Properties { switch pp.Name { - case rpm_module.PropertyComponent: - components.Add(pp.Value) - case rpm_module.PropertyDistribution: - distributions.Add(pp.Value) + case rpm_module.PropertyGroup: + groups.Add(pp.Value) case rpm_module.PropertyArchitecture: architectures.Add(pp.Value) } } } - ctx.Data["Distributions"] = distributions.Values() ctx.Data["Architectures"] = architectures.Values() - ctx.Data["Components"] = components.Values() + ctx.Data["Groups"] = groups.Values() } var ( diff --git a/templates/package/content/rpm.tmpl b/templates/package/content/rpm.tmpl index 75526e9a5be2d..ad69c4ca510b7 100644 --- a/templates/package/content/rpm.tmpl +++ b/templates/package/content/rpm.tmpl @@ -5,10 +5,10 @@
# {{ctx.Locale.Tr "packages.rpm.distros.redhat"}}
-dnf config-manager --add-repo 
+dnf config-manager --add-repo 
 
 # {{ctx.Locale.Tr "packages.rpm.distros.suse"}}
-zypper addrepo 
+zypper addrepo
diff --git a/templates/package/metadata/rpm.tmpl b/templates/package/metadata/rpm.tmpl index 78548faa28629..cf4bfdb9551ca 100644 --- a/templates/package/metadata/rpm.tmpl +++ b/templates/package/metadata/rpm.tmpl @@ -1,5 +1,5 @@ {{if eq .PackageDescriptor.Package.Type "rpm"}} -
{{svg "octicon-location" 16 "gt-mr-3"}} {{index .Distributions 0}}/{{index .Components 0}}
+
{{svg "octicon-location" 16 "gt-mr-3"}} {{index .Groups 0}}
{{svg "octicon-server" 16 "gt-mr-3"}} {{StringUtils.Join .Architectures ", "}}
{{if .PackageDescriptor.Metadata.ProjectURL}}
{{svg "octicon-link-external" 16 "gt-mr-3"}} {{ctx.Locale.Tr "packages.details.project_site"}}
{{end}} {{if .PackageDescriptor.Metadata.License}}
{{svg "octicon-law" 16 "gt-mr-3"}} {{.PackageDescriptor.Metadata.License}}
{{end}} From 64c3a7ed763973c9b2d9c29fc206dd3eea4b9926 Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 28 Oct 2023 17:28:13 +0800 Subject: [PATCH 09/23] rpm packages with arbitrary depth paths --- routers/api/packages/api.go | 99 +++++++++++++++++++++++++++------ routers/api/packages/rpm/rpm.go | 10 ++-- 2 files changed, 89 insertions(+), 20 deletions(-) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 31120c0bb5722..071a2abe3cbb6 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -512,22 +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("/repository.key", rpm.GetRepositoryKey) - r.Group("/{group}", func() { - r.Get(".repo", rpm.GetRepositoryConfig) - r.Put("/upload", reqPackageAccess(perm.AccessModeWrite), rpm.UploadPackageFile) - r.Group("/package/{name}/{version}/{architecture}", func() { - r.Get("", rpm.DownloadPackageFile) - // yum/dnf client does not recognize the filename of the header. - // which will result in a failure to hit the cache locally. - // So add a new spurious route - r.Get("/{_}", rpm.DownloadPackageFile) - r.Delete("", reqPackageAccess(perm.AccessModeWrite), rpm.DeletePackageFile) - }) - r.Get("/repodata/{filename}", 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) @@ -592,6 +577,88 @@ 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((?:/(?:[^/]+))*|)/package/upload\z`) + groupRpm = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/package/([^/]+)/([^/]+)/([^/]+)(?:/([^/]+\.rpm)|)\z`) + groupMetadata = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/repodata/([^/]+)\z`) + ) + const DEFAULT_GROUP = "/" + + groupFormat := func(input string) string { + if input == "" { + return DEFAULT_GROUP + } + return input + } + + return func() { + r.Methods("HEAD,GET,POST,PUT,PATCH,DELETE", "*", func(ctx *context.Context) { + path := ctx.Params("*") + 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", groupFormat(m[1])) + rpm.GetRepositoryConfig(ctx) + return + } + // get meta + m = groupMetadata.FindStringSubmatch(path) + if len(m) == 3 && isGetHead { + ctx.SetParams("group", groupFormat(m[1])) + ctx.SetParams("filename", groupFormat(m[2])) + 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", groupFormat(m[1])) + rpm.UploadPackageFile(ctx) + return + } + // rpm down/delete + m = groupRpm.FindStringSubmatch(path) + ctx.SetParams("group", groupFormat(m[1])) + + if len(m) == 6 { + ctx.SetParams("group", groupFormat(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 3bc643a50f55f..d6299ec27c002 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -34,11 +34,13 @@ 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 = "" + } url := fmt.Sprintf("%sapi/packages/%s/rpm", setting.AppURL, ctx.Package.Owner.Name) - - ctx.PlainText(http.StatusOK, `[gitea-`+ctx.Package.Owner.LowerName+`-`+group+`] -name=`+ctx.Package.Owner.Name+` - `+setting.AppName+` - `+group+` -baseurl=`+url+`/`+group+` + 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`) From 561d86b0f1180ed1e82d34536a1b966b2bcb7116 Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 28 Oct 2023 18:35:45 +0800 Subject: [PATCH 10/23] fix ui --- routers/api/packages/api.go | 2 +- templates/package/content/rpm.tmpl | 8 ++++++-- templates/package/metadata/rpm.tmpl | 4 ++-- tests/integration/api_packages_rpm_test.go | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 071a2abe3cbb6..0013120f30b1c 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -581,7 +581,7 @@ func CommonRoutes() *web.Route { func RpmRoutes(r *web.Route) func() { var ( groupRepoInfo = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)\.repo\z`) - groupUpload = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/package/upload\z`) + groupUpload = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/upload\z`) groupRpm = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/package/([^/]+)/([^/]+)/([^/]+)(?:/([^/]+\.rpm)|)\z`) groupMetadata = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/repodata/([^/]+)\z`) ) diff --git a/templates/package/content/rpm.tmpl b/templates/package/content/rpm.tmpl index ad69c4ca510b7..bee434af13fc3 100644 --- a/templates/package/content/rpm.tmpl +++ b/templates/package/content/rpm.tmpl @@ -5,10 +5,14 @@
# {{ctx.Locale.Tr "packages.rpm.distros.redhat"}}
-dnf config-manager --add-repo 
+{{$group_name:= (index .Groups 0) -}}
+{{- if eq $group_name "/" -}}
+{{- $group_name = "" -}}
+{{- end -}}
+dnf config-manager --add-repo 
 
 # {{ctx.Locale.Tr "packages.rpm.distros.suse"}}
-zypper addrepo 
+zypper addrepo
diff --git a/templates/package/metadata/rpm.tmpl b/templates/package/metadata/rpm.tmpl index cf4bfdb9551ca..aafb6a854ef3c 100644 --- a/templates/package/metadata/rpm.tmpl +++ b/templates/package/metadata/rpm.tmpl @@ -1,6 +1,6 @@ {{if eq .PackageDescriptor.Package.Type "rpm"}} -
{{svg "octicon-location" 16 "gt-mr-3"}} {{index .Groups 0}}
-
{{svg "octicon-server" 16 "gt-mr-3"}} {{StringUtils.Join .Architectures ", "}}
+
{{svg "octicon-file-directory-open-fill" 16 "gt-mr-3"}}{{StringUtils.Join .Groups ", "}}
+
{{svg "octicon-server" 16 "gt-mr-3"}} {{StringUtils.Join .Architectures ", "}}
{{if .PackageDescriptor.Metadata.ProjectURL}}
{{svg "octicon-link-external" 16 "gt-mr-3"}} {{ctx.Locale.Tr "packages.details.project_site"}}
{{end}} {{if .PackageDescriptor.Metadata.License}}
{{svg "octicon-law" 16 "gt-mr-3"}} {{.PackageDescriptor.Metadata.License}}
{{end}} {{end}} diff --git a/tests/integration/api_packages_rpm_test.go b/tests/integration/api_packages_rpm_test.go index d6885262a5263..5bc0e13af8364 100644 --- a/tests/integration/api_packages_rpm_test.go +++ b/tests/integration/api_packages_rpm_test.go @@ -81,7 +81,7 @@ Mu0UFYgZ/bYnuvn/vz4wtCz8qMwsHUvP0PX3tbYFUctAPdrY6tiiDtcCddDECahx7SuVNP5dpmb5 expected := fmt.Sprintf(`[gitea-%s-el9-stable] name=%s - %s - el9 - stable -baseurl=%sapi/packages/%s/rpm/el9/stable +baseurl=%sapi/packages/%s/rpm/el9/stable/ enabled=1 gpgcheck=1 gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppName, setting.AppURL, user.Name, setting.AppURL, user.Name) From 7957d607eaa170843cb97188280e1184bdbf281e Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 28 Oct 2023 18:46:31 +0800 Subject: [PATCH 11/23] fix migrations --- models/migrations/v1_22/v282.go | 17 +++++++---------- modules/packages/rpm/metadata.go | 3 --- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/models/migrations/v1_22/v282.go b/models/migrations/v1_22/v282.go index 501f61139453c..330049aef9cbb 100644 --- a/models/migrations/v1_22/v282.go +++ b/models/migrations/v1_22/v282.go @@ -4,8 +4,6 @@ package v1_22 //nolint import ( - "fmt" - "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/packages/rpm" @@ -15,12 +13,12 @@ import ( func RebuildRpmPackage(x *xorm.Engine) error { sess := x.NewSession() defer sess.Close() - compositeKey := fmt.Sprintf("%s|%s", rpm.RepositoryDefaultDistribution, rpm.RepositoryDefaultComponent) + groupId := "/" // select all old rpm package var oldRpmIds []int64 ss := sess.Cols("id"). Table("package_file"). - Where("composite_key not like ?", "%|%"). + Where("composite_key not like ?", "/%"). And("lower_name like ?", "%.rpm") err := ss.Find(&oldRpmIds) if err != nil { @@ -48,10 +46,9 @@ func RebuildRpmPackage(x *xorm.Engine) error { return err } _, err = sess.Exec( - "INSERT INTO package_property(ref_type, ref_id, name, value) values (?,?,?,?),(?,?,?,?),(?,?,?,?)", - metadata[0], metadata[1], "rpm.distribution", rpm.RepositoryDefaultDistribution, - metadata[0], metadata[1], "rpm.component", rpm.RepositoryDefaultComponent, - metadata[0], metadata[1], "rpm.architecture", rpmMetadata.Architecture, + "INSERT INTO package_property(ref_type, ref_id, name, value) values (?,?,?,?),(?,?,?,?)", + metadata[0], metadata[1], rpm.PropertyGroup, groupId, + metadata[0], metadata[1], rpm.PropertyArchitecture, rpmMetadata.Architecture, ) if err != nil { return err @@ -60,7 +57,7 @@ func RebuildRpmPackage(x *xorm.Engine) error { _, err = sess.Table("package_file"). Where("id = ?", id). Update(map[string]any{ - "composite_key": compositeKey, + "composite_key": groupId, }) if err != nil { return err @@ -74,7 +71,7 @@ func RebuildRpmPackage(x *xorm.Engine) error { ('primary.xml.gz','other.xml.gz','filelists.xml.gz','other.xml.gz','repomd.xml','repomd.xml.asc')`, ). Update(map[string]any{ - "composite_key": compositeKey, + "composite_key": groupId, }) if err != nil { return err diff --git a/modules/packages/rpm/metadata.go b/modules/packages/rpm/metadata.go index 89559f192839a..a1142cd60455a 100644 --- a/modules/packages/rpm/metadata.go +++ b/modules/packages/rpm/metadata.go @@ -23,9 +23,6 @@ const ( RepositoryPackage = "_rpm" RepositoryVersion = "_repository" - - RepositoryDefaultDistribution = "default" - RepositoryDefaultComponent = "stable" ) const ( From 2e2cd0f79b9041a2fb4f481ec839cc8d193f42e2 Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 28 Oct 2023 18:54:51 +0800 Subject: [PATCH 12/23] i10n clean --- options/locale/locale_en-US.ini | 6 ------ templates/package/content/rpm.tmpl | 24 +++++------------------- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 82fce11fe7b07..8c40bbc01df59 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3395,12 +3395,6 @@ rpm.registry = Setup this registry from the command line: rpm.distros.redhat = on RedHat based distributions rpm.distros.suse = on SUSE based distributions rpm.install = To install the package, run the following command: -rpm.package.info = Package Info -rpm.package.distributions.support = Specify the distribution , for example: -rpm.package.components.support = Specifies the distribution version, for example: -rpm.package.architectures = Architectures -rpm.package.description = Description -rpm.package.summary = Summary rubygems.install = To install the package using gem, run the following command: rubygems.install2 = or add it to the Gemfile: rubygems.dependencies.runtime = Runtime Dependencies diff --git a/templates/package/content/rpm.tmpl b/templates/package/content/rpm.tmpl index bee434af13fc3..db6660ef82951 100644 --- a/templates/package/content/rpm.tmpl +++ b/templates/package/content/rpm.tmpl @@ -30,23 +30,9 @@ zypper install {{$.PackageDescriptor.Package.Name}}
-

{{ctx.Locale.Tr "packages.about"}}

-
- - - {{if .PackageDescriptor.Metadata.Summary}} - - - - - {{end}} - {{if .PackageDescriptor.Metadata.Description}} - - - - - {{end}} - -
{{ctx.Locale.Tr "packages.rpm.package.summary"}}
{{.PackageDescriptor.Metadata.Summary}}
{{ctx.Locale.Tr "packages.rpm.package.description"}}
{{.PackageDescriptor.Metadata.Description}}
-
+ {{if or .PackageDescriptor.Metadata.Summary .PackageDescriptor.Metadata.Description}} +

{{ctx.Locale.Tr "packages.about"}}

+ {{if .PackageDescriptor.Metadata.Summary}}
{{.PackageDescriptor.Metadata.Summary}}
{{end}} + {{if .PackageDescriptor.Metadata.Description}}
{{.PackageDescriptor.Metadata.Description}}
{{end}} + {{end}} {{end}} From a8fff900e339737beb43021b202b302f8fdeac5d Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 28 Oct 2023 19:07:54 +0800 Subject: [PATCH 13/23] move varfunc --- routers/api/packages/api.go | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 0013120f30b1c..740b20200fd33 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -577,6 +577,13 @@ func CommonRoutes() *web.Route { return r } +func rpmGroupFormat(input string) string { + if input == "" { + return "/" + } + return input +} + // Support for uploading rpm packages with arbitrary depth paths func RpmRoutes(r *web.Route) func() { var ( @@ -585,14 +592,6 @@ func RpmRoutes(r *web.Route) func() { groupRpm = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/package/([^/]+)/([^/]+)/([^/]+)(?:/([^/]+\.rpm)|)\z`) groupMetadata = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/repodata/([^/]+)\z`) ) - const DEFAULT_GROUP = "/" - - groupFormat := func(input string) string { - if input == "" { - return DEFAULT_GROUP - } - return input - } return func() { r.Methods("HEAD,GET,POST,PUT,PATCH,DELETE", "*", func(ctx *context.Context) { @@ -609,15 +608,15 @@ func RpmRoutes(r *web.Route) func() { // get repo m := groupRepoInfo.FindStringSubmatch(path) if len(m) == 2 && isGetHead { - ctx.SetParams("group", groupFormat(m[1])) + ctx.SetParams("group", rpmGroupFormat(m[1])) rpm.GetRepositoryConfig(ctx) return } // get meta m = groupMetadata.FindStringSubmatch(path) if len(m) == 3 && isGetHead { - ctx.SetParams("group", groupFormat(m[1])) - ctx.SetParams("filename", groupFormat(m[2])) + ctx.SetParams("group", rpmGroupFormat(m[1])) + ctx.SetParams("filename", rpmGroupFormat(m[2])) rpm.GetRepositoryFile(ctx) return } @@ -629,16 +628,16 @@ func RpmRoutes(r *web.Route) func() { if ctx.Written() { return } - ctx.SetParams("group", groupFormat(m[1])) + ctx.SetParams("group", rpmGroupFormat(m[1])) rpm.UploadPackageFile(ctx) return } // rpm down/delete m = groupRpm.FindStringSubmatch(path) - ctx.SetParams("group", groupFormat(m[1])) + ctx.SetParams("group", rpmGroupFormat(m[1])) if len(m) == 6 { - ctx.SetParams("group", groupFormat(m[1])) + ctx.SetParams("group", rpmGroupFormat(m[1])) ctx.SetParams("name", m[2]) ctx.SetParams("version", m[3]) ctx.SetParams("architecture", m[4]) From 1887c933e0ec8b63b4e9dff8ab4b765d25461de4 Mon Sep 17 00:00:00 2001 From: dragon Date: Sat, 28 Oct 2023 19:33:27 +0800 Subject: [PATCH 14/23] fix docs --- docs/content/usage/packages/rpm.en-us.md | 17 +++++++---------- docs/content/usage/packages/rpm.zh-cn.md | 19 ++++++++----------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/docs/content/usage/packages/rpm.en-us.md b/docs/content/usage/packages/rpm.en-us.md index 7b23aa0e10916..586e48d47fe3e 100644 --- a/docs/content/usage/packages/rpm.en-us.md +++ b/docs/content/usage/packages/rpm.en-us.md @@ -27,19 +27,18 @@ The following examples use `dnf`. To register the RPM registry add the url to the list of known apt sources: ```shell -dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}.repo +dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo ``` | Placeholder | Description | | ----------- |----------------------------------------------------| | `owner` | The owner of the package. | -| `distribution` | System Name, e.g. `centos`, `suse` , `rockylinux`. | -| `component` | System version, e.g. `el7`, `el9` , `fc38`. | +| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.| 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): ```shell -dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}.repo +dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo ``` You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.repos.d` too. @@ -49,14 +48,13 @@ You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum. To publish a RPM package (`*.rpm`), perform a HTTP PUT operation with the package content in the request body. ``` -PUT https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}/upload +PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload ``` | Parameter | Description | | --------- | ----------- | | `owner` | The owner of the package. | -| `distribution` | System Name, e.g. `centos`, `suse` , `rockylinux`. | -| `component` | System version, e.g. `el7`, `el9` , `fc38`. | +| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.| Example request using HTTP Basic authentication: @@ -82,14 +80,13 @@ The server responds with the following HTTP Status codes. To delete an RPM package perform a HTTP DELETE operation. This will delete the package version too if there is no file left. ``` -DELETE https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/package/{package_name}/{package_version}/{architecture} +DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture} ``` | Parameter | Description | |-------------------|----------------------------| | `owner` | The owner of the package. | -| `distribution` | The package distribution. | -| `component` | The package group version. | +| `group` | The package group . | | `package_name` | The package name. | | `package_version` | The package version. | | `architecture` | The package architecture. | diff --git a/docs/content/usage/packages/rpm.zh-cn.md b/docs/content/usage/packages/rpm.zh-cn.md index dd64f97573132..cbe74bfee230d 100644 --- a/docs/content/usage/packages/rpm.zh-cn.md +++ b/docs/content/usage/packages/rpm.zh-cn.md @@ -27,19 +27,18 @@ menu: 要注册RPM注册表,请将 URL 添加到已知 `apt` 源列表中: ```shell -dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}.repo +dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo ``` | 占位符 | 描述 | | ------- |--------------------------------------| -| `owner` | 软件包的所有者 | -| `distribution` | 软件包适配的系统名称,例如 `centos`、`rocky linux` | -| `component` | 软件包适合的目标版本,例如 `el7`、`fc38` | +| `owner` | 软件包的所有者 | +| `group` | 任何名称,例如 `centos/7`、`el-7`、`fc38` | 如果注册表是私有的,请在URL中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证): ```shell -dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}.repo +dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo ``` 您还必须将凭据添加到 `/etc/yum.repos.d` 中的 `rpm.repo` 文件中的URL中。 @@ -49,14 +48,13 @@ dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea. 要发布RPM软件包(`*.rpm`),请执行带有软件包内容的 HTTP `PUT` 操作。 ``` -PUT https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}/upload +PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload ``` | 参数 | 描述 | | ------- |--------------| | `owner` | 软件包的所有者 | -| `distribution` | 软件包适配的系统名称 | -| `component` | 软件包适配的系统发行版本 | +| `group` | 软件包自定义分组名称 | 使用HTTP基本身份验证的示例请求: @@ -81,14 +79,13 @@ curl --user your_username:your_password_or_token \ 要删除 RPM 软件包,请执行 HTTP `DELETE` 操作。如果没有文件剩余,这也将删除软件包版本。 ``` -DELETE https://gitea.example.com/api/packages/{owner}/rpm/{distribution}/{component}/package/{package_name}/{package_version}/{architecture} +DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture} ``` | 参数 | 描述 | | ----------------- | -------------- | | `owner` | 软件包的所有者 | -| `distribution` | 软件包适配的系统名称 | -| `component` | 软件包适配的系统发行版本 | +| `group` | 软件包自定义分组 | | `package_name` | 软件包名称 | | `package_version` | 软件包版本 | | `architecture` | 软件包架构 | From a66f80b5354b5873ffd3e9acef977fa6992aba8f Mon Sep 17 00:00:00 2001 From: dragon Date: Sun, 29 Oct 2023 13:49:52 +0800 Subject: [PATCH 15/23] fixed bugs --- routers/api/packages/api.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 740b20200fd33..c6313b9cb58cd 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -634,8 +634,6 @@ func RpmRoutes(r *web.Route) func() { } // rpm down/delete m = groupRpm.FindStringSubmatch(path) - ctx.SetParams("group", rpmGroupFormat(m[1])) - if len(m) == 6 { ctx.SetParams("group", rpmGroupFormat(m[1])) ctx.SetParams("name", m[2]) From 83a4b18278e16882eb97a2a1886675cc970a659f Mon Sep 17 00:00:00 2001 From: "kailong.fu" Date: Mon, 30 Oct 2023 12:56:01 +0800 Subject: [PATCH 16/23] add group by version --- models/migrations/v1_22/v282.go | 94 +++++++++++----------- routers/api/packages/rpm/rpm.go | 23 +++--- services/packages/rpm/repository.go | 7 +- templates/package/metadata/rpm.tmpl | 1 - tests/integration/api_packages_rpm_test.go | 2 +- 5 files changed, 67 insertions(+), 60 deletions(-) diff --git a/models/migrations/v1_22/v282.go b/models/migrations/v1_22/v282.go index 330049aef9cbb..dd741ca38a10f 100644 --- a/models/migrations/v1_22/v282.go +++ b/models/migrations/v1_22/v282.go @@ -8,19 +8,48 @@ import ( "code.gitea.io/gitea/modules/packages/rpm" "xorm.io/xorm" + "xorm.io/xorm/schemas" ) func RebuildRpmPackage(x *xorm.Engine) error { sess := x.NewSession() defer sess.Close() - groupId := "/" - // select all old rpm package - var oldRpmIds []int64 - ss := sess.Cols("id"). - Table("package_file"). - Where("composite_key not like ?", "/%"). - And("lower_name like ?", "%.rpm") - err := ss.Find(&oldRpmIds) + // group composite_key + _, err := sess.Exec(` + UPDATE package_file + set composite_key = '/' + WHERE package_file.lower_name like '%.rpm' + OR package_file.lower_name IN + ('primary.xml.gz', 'other.xml.gz', 'filelists.xml.gz', 'other.xml.gz', 'repomd.xml', 'repomd.xml.asc') + `) + if err != nil { + return err + } + // group version + switch x.Dialect().URI().DBType { + case schemas.SQLITE: + _, err = sess.Exec(`update package_version + set version = '/' || version, + lower_version = '/' || lower_version + WHERE id IN (SELECT package_file.version_id as id + from package_file + WHERE package_file.name like '%.rpm')`) + case schemas.MSSQL: + _, err = sess.Exec(`update package_version + set version = '/' + version, + lower_version = '/' + lower_version + WHERE id IN (SELECT package_file.version_id as id + from package_file + WHERE package_file.name like '%.rpm')`) + + default: + _, err = sess.Exec(`update package_version + set version = CONCAT('/',version), + lower_version = CONCAT('/',lower_version) + WHERE id IN (SELECT package_file.version_id as id + from package_file + WHERE package_file.name like '%.rpm')`) + } if err != nil { return err } @@ -28,53 +57,28 @@ func RebuildRpmPackage(x *xorm.Engine) error { // NOTE: package_property[name='rpm.metadata'] is very large, // and to avoid querying all of them resulting in large memory, // a single RPM package is now used for updating. - for _, id := range oldRpmIds { - - metadata := make([]string, 0, 3) - _, err := sess.Cols("ref_type", "ref_id", "value"). - Table("package_property"). - Where("name = 'rpm.metadata'"). - And("ref_id = ?", id). - Get(&metadata) - if err != nil { - return err - } - // get rpm info + metadata := make([][]string, 0, 4) + _, err = sess.Cols("ref_type", "ref_id", "package_file.composite_key", "value"). + Table("package_property"). + Join("left", "package_file", "`package_file`.id = `package_property`.ref_id"). + Where("package_property.name = 'rpm.metadata'").Get(&metadata) + if err != nil { + return err + } + for _, data := range metadata { var rpmMetadata rpm.FileMetadata - err = json.Unmarshal([]byte(metadata[2]), &rpmMetadata) + err = json.Unmarshal([]byte(data[3]), &rpmMetadata) if err != nil { return err } _, err = sess.Exec( "INSERT INTO package_property(ref_type, ref_id, name, value) values (?,?,?,?),(?,?,?,?)", - metadata[0], metadata[1], rpm.PropertyGroup, groupId, - metadata[0], metadata[1], rpm.PropertyArchitecture, rpmMetadata.Architecture, + data[0], data[1], rpm.PropertyGroup, data[2], + data[0], data[1], rpm.PropertyArchitecture, rpmMetadata.Architecture, ) if err != nil { return err } - // set default distribution - _, err = sess.Table("package_file"). - Where("id = ?", id). - Update(map[string]any{ - "composite_key": groupId, - }) - if err != nil { - return err - } - } - // set old rpm index file to default distribution - _, err = sess.Table("package_file"). - Where( - `composite_key = '' AND - lower_name IN - ('primary.xml.gz','other.xml.gz','filelists.xml.gz','other.xml.gz','repomd.xml','repomd.xml.asc')`, - ). - Update(map[string]any{ - "composite_key": groupId, - }) - if err != nil { - return err } return nil } diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index d6299ec27c002..9faf2bf4ad46b 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -125,7 +125,7 @@ func UploadPackageFile(ctx *context.Context) { apiError(ctx, http.StatusInternalServerError, err) return } - compositeKey := ctx.Params("group") + group := ctx.Params("group") _, _, err = packages_service.CreatePackageOrAddFileToExisting( ctx, &packages_service.PackageCreationInfo{ @@ -133,7 +133,7 @@ func UploadPackageFile(ctx *context.Context) { Owner: ctx.Package.Owner, PackageType: packages_model.TypeRpm, Name: pck.Name, - Version: pck.Version, + Version: fmt.Sprintf("%s/%s", group, pck.Version), }, Creator: ctx.Doer, Metadata: pck.VersionMetadata, @@ -141,14 +141,14 @@ func UploadPackageFile(ctx *context.Context) { &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ Filename: fmt.Sprintf("%s-%s.%s.rpm", pck.Name, pck.Version, pck.FileMetadata.Architecture), - CompositeKey: compositeKey, + CompositeKey: group, }, Creator: ctx.Doer, Data: buf, IsLead: true, Properties: map[string]string{ rpm_module.PropertyMetadata: string(fileMetadataRaw), - rpm_module.PropertyGroup: compositeKey, + rpm_module.PropertyGroup: group, rpm_module.PropertyArchitecture: pck.FileMetadata.Architecture, }, }, @@ -165,7 +165,7 @@ func UploadPackageFile(ctx *context.Context) { return } - if err := rpm_service.BuildRepositoryFiles(ctx, ctx.Package.Owner.ID, compositeKey); err != nil { + if err := rpm_service.BuildRepositoryFiles(ctx, ctx.Package.Owner.ID, group); err != nil { apiError(ctx, http.StatusInternalServerError, err) return } @@ -174,6 +174,7 @@ 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( @@ -182,11 +183,11 @@ func DownloadPackageFile(ctx *context.Context) { Owner: ctx.Package.Owner, PackageType: packages_model.TypeRpm, Name: name, - Version: version, + Version: fmt.Sprintf("%s/%s", group, version), }, &packages_service.PackageFileInfo{ Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.Params("architecture")), - CompositeKey: ctx.Params("group"), + CompositeKey: group, }, ) if err != nil { @@ -202,14 +203,14 @@ 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") - compositeKey := webctx.Params("group") 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, fmt.Sprintf("%s/%s", group, version)) if err != nil { return err } @@ -218,7 +219,7 @@ func DeletePackageFile(webctx *context.Context) { ctx, pv.ID, fmt.Sprintf("%s-%s.%s.rpm", name, version, architecture), - compositeKey, + group, ) if err != nil { return err @@ -258,7 +259,7 @@ func DeletePackageFile(webctx *context.Context) { notify_service.PackageDelete(webctx, webctx.Doer, pd) } - if err := rpm_service.BuildRepositoryFiles(webctx, webctx.Package.Owner.ID, compositeKey); err != nil { + if err := rpm_service.BuildRepositoryFiles(webctx, webctx.Package.Owner.ID, group); err != nil { apiError(webctx, http.StatusInternalServerError, err) return } diff --git a/services/packages/rpm/repository.go b/services/packages/rpm/repository.go index 377bac2fbbf0c..9fb23235fe718 100644 --- a/services/packages/rpm/repository.go +++ b/services/packages/rpm/repository.go @@ -262,11 +262,14 @@ func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID } repomdAscContent, _ := packages_module.NewHashedBuffer() + defer repomdAscContent.Close() + if err := openpgp.ArmoredDetachSign(repomdAscContent, e, bytes.NewReader(buf.Bytes()), nil); err != nil { return err } repomdContent, _ := packages_module.CreateHashedBufferFromReader(&buf) + defer repomdContent.Close() for _, file := range []struct { Name string @@ -378,7 +381,7 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs [] files = append(files, f) } } - + packageVersion := fmt.Sprintf("%s-%s", pd.FileMetadata.Version, pd.FileMetadata.Release) packages = append(packages, &Package{ Type: "rpm", Name: pd.Package.Name, @@ -407,7 +410,7 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs [] Archive: pd.FileMetadata.ArchiveSize, }, Location: Location{ - Href: fmt.Sprintf("package/%s/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(pd.Version.Version), url.PathEscape(pd.FileMetadata.Architecture), url.PathEscape(fmt.Sprintf("%s-%s.%s.rpm", pd.Package.Name, pd.Version.Version, pd.FileMetadata.Architecture))), + Href: fmt.Sprintf("package/%s/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(packageVersion), url.PathEscape(pd.FileMetadata.Architecture), url.PathEscape(fmt.Sprintf("%s-%s.%s.rpm", pd.Package.Name, packageVersion, pd.FileMetadata.Architecture))), }, Format: Format{ License: pd.VersionMetadata.License, diff --git a/templates/package/metadata/rpm.tmpl b/templates/package/metadata/rpm.tmpl index aafb6a854ef3c..ac7d1384ab6e3 100644 --- a/templates/package/metadata/rpm.tmpl +++ b/templates/package/metadata/rpm.tmpl @@ -1,5 +1,4 @@ {{if eq .PackageDescriptor.Package.Type "rpm"}} -
{{svg "octicon-file-directory-open-fill" 16 "gt-mr-3"}}{{StringUtils.Join .Groups ", "}}
{{svg "octicon-server" 16 "gt-mr-3"}} {{StringUtils.Join .Architectures ", "}}
{{if .PackageDescriptor.Metadata.ProjectURL}}
{{svg "octicon-link-external" 16 "gt-mr-3"}} {{ctx.Locale.Tr "packages.details.project_site"}}
{{end}} {{if .PackageDescriptor.Metadata.License}}
{{svg "octicon-law" 16 "gt-mr-3"}} {{.PackageDescriptor.Metadata.License}}
{{end}} diff --git a/tests/integration/api_packages_rpm_test.go b/tests/integration/api_packages_rpm_test.go index 5bc0e13af8364..5de4bb68c827b 100644 --- a/tests/integration/api_packages_rpm_test.go +++ b/tests/integration/api_packages_rpm_test.go @@ -118,7 +118,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN assert.Nil(t, pd.SemVer) assert.IsType(t, &rpm_module.VersionMetadata{}, pd.Metadata) assert.Equal(t, packageName, pd.Package.Name) - assert.Equal(t, packageVersion, pd.Version.Version) + assert.Equal(t, fmt.Sprintf("/el9/stable/%s", packageVersion), pd.Version.Version) pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID) assert.NoError(t, err) From 5f6ebb5bbba21184742f1cf1ca3b69706f9251cf Mon Sep 17 00:00:00 2001 From: "kailong.fu" Date: Mon, 30 Oct 2023 12:56:06 +0800 Subject: [PATCH 17/23] add group by version --- models/migrations/v1_22/v282.go | 1 - 1 file changed, 1 deletion(-) diff --git a/models/migrations/v1_22/v282.go b/models/migrations/v1_22/v282.go index dd741ca38a10f..cf43a471188c3 100644 --- a/models/migrations/v1_22/v282.go +++ b/models/migrations/v1_22/v282.go @@ -53,7 +53,6 @@ func RebuildRpmPackage(x *xorm.Engine) error { if err != nil { return err } - // add metadata // NOTE: package_property[name='rpm.metadata'] is very large, // and to avoid querying all of them resulting in large memory, // a single RPM package is now used for updating. From d8ede80375e321315cf11398ed662a78f545cd39 Mon Sep 17 00:00:00 2001 From: "kailong.fu" Date: Mon, 30 Oct 2023 13:07:40 +0800 Subject: [PATCH 18/23] fix nogroup upload --- routers/api/packages/rpm/rpm.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index 9faf2bf4ad46b..00e84c34382e2 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -133,7 +133,7 @@ func UploadPackageFile(ctx *context.Context) { Owner: ctx.Package.Owner, PackageType: packages_model.TypeRpm, Name: pck.Name, - Version: fmt.Sprintf("%s/%s", group, pck.Version), + Version: fmt.Sprintf("%s/%s", strings.TrimRight(group, "/"), pck.Version), }, Creator: ctx.Doer, Metadata: pck.VersionMetadata, @@ -183,7 +183,7 @@ func DownloadPackageFile(ctx *context.Context) { Owner: ctx.Package.Owner, PackageType: packages_model.TypeRpm, Name: name, - Version: fmt.Sprintf("%s/%s", group, version), + Version: fmt.Sprintf("%s/%s", strings.TrimRight(group, "/"), version), }, &packages_service.PackageFileInfo{ Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.Params("architecture")), @@ -210,7 +210,7 @@ func DeletePackageFile(webctx *context.Context) { 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, fmt.Sprintf("%s/%s", group, version)) + pv, err := packages_model.GetVersionByNameAndVersion(ctx, webctx.Package.Owner.ID, packages_model.TypeRpm, name, fmt.Sprintf("%s/%s", strings.TrimRight(group, "/"), version)) if err != nil { return err } From 1b4e2ce108ca490e908c123318e1d9cdf5aa8c02 Mon Sep 17 00:00:00 2001 From: "kailong.fu" Date: Mon, 30 Oct 2023 13:40:12 +0800 Subject: [PATCH 19/23] style clean --- models/migrations/v1_22/v282.go | 42 +--------------------- routers/api/packages/api.go | 18 +++------- routers/api/packages/rpm/rpm.go | 15 +++++--- templates/package/content/rpm.tmpl | 4 +-- tests/integration/api_packages_rpm_test.go | 2 +- 5 files changed, 19 insertions(+), 62 deletions(-) diff --git a/models/migrations/v1_22/v282.go b/models/migrations/v1_22/v282.go index cf43a471188c3..4974332375b3b 100644 --- a/models/migrations/v1_22/v282.go +++ b/models/migrations/v1_22/v282.go @@ -8,56 +8,16 @@ import ( "code.gitea.io/gitea/modules/packages/rpm" "xorm.io/xorm" - "xorm.io/xorm/schemas" ) func RebuildRpmPackage(x *xorm.Engine) error { sess := x.NewSession() defer sess.Close() - // group composite_key - _, err := sess.Exec(` - UPDATE package_file - set composite_key = '/' - WHERE package_file.lower_name like '%.rpm' - OR package_file.lower_name IN - ('primary.xml.gz', 'other.xml.gz', 'filelists.xml.gz', 'other.xml.gz', 'repomd.xml', 'repomd.xml.asc') - `) - if err != nil { - return err - } - // group version - switch x.Dialect().URI().DBType { - case schemas.SQLITE: - _, err = sess.Exec(`update package_version - set version = '/' || version, - lower_version = '/' || lower_version - WHERE id IN (SELECT package_file.version_id as id - from package_file - WHERE package_file.name like '%.rpm')`) - case schemas.MSSQL: - _, err = sess.Exec(`update package_version - set version = '/' + version, - lower_version = '/' + lower_version - WHERE id IN (SELECT package_file.version_id as id - from package_file - WHERE package_file.name like '%.rpm')`) - - default: - _, err = sess.Exec(`update package_version - set version = CONCAT('/',version), - lower_version = CONCAT('/',lower_version) - WHERE id IN (SELECT package_file.version_id as id - from package_file - WHERE package_file.name like '%.rpm')`) - } - if err != nil { - return err - } // NOTE: package_property[name='rpm.metadata'] is very large, // and to avoid querying all of them resulting in large memory, // a single RPM package is now used for updating. metadata := make([][]string, 0, 4) - _, err = sess.Cols("ref_type", "ref_id", "package_file.composite_key", "value"). + _, err := sess.Cols("ref_type", "ref_id", "package_file.composite_key", "value"). Table("package_property"). Join("left", "package_file", "`package_file`.id = `package_property`.ref_id"). Where("package_property.name = 'rpm.metadata'").Get(&metadata) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index c6313b9cb58cd..92da70a31035e 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -577,13 +577,6 @@ func CommonRoutes() *web.Route { return r } -func rpmGroupFormat(input string) string { - if input == "" { - return "/" - } - return input -} - // Support for uploading rpm packages with arbitrary depth paths func RpmRoutes(r *web.Route) func() { var ( @@ -608,19 +601,18 @@ func RpmRoutes(r *web.Route) func() { // get repo m := groupRepoInfo.FindStringSubmatch(path) if len(m) == 2 && isGetHead { - ctx.SetParams("group", rpmGroupFormat(m[1])) + 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", rpmGroupFormat(m[1])) - ctx.SetParams("filename", rpmGroupFormat(m[2])) + ctx.SetParams("group", strings.Trim(m[1], "/")) + ctx.SetParams("filename", m[2]) rpm.GetRepositoryFile(ctx) return } - // upload m = groupUpload.FindStringSubmatch(path) if len(m) == 2 && isPut { @@ -628,14 +620,14 @@ func RpmRoutes(r *web.Route) func() { if ctx.Written() { return } - ctx.SetParams("group", rpmGroupFormat(m[1])) + 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", rpmGroupFormat(m[1])) + ctx.SetParams("group", strings.Trim(m[1], "/")) ctx.SetParams("name", m[2]) ctx.SetParams("version", m[3]) ctx.SetParams("architecture", m[4]) diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index 00e84c34382e2..9a547e6510cbe 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -34,8 +34,8 @@ 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 = "" + 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+strings.ReplaceAll(group, "/", "-")+`] @@ -133,7 +133,7 @@ func UploadPackageFile(ctx *context.Context) { Owner: ctx.Package.Owner, PackageType: packages_model.TypeRpm, Name: pck.Name, - Version: fmt.Sprintf("%s/%s", strings.TrimRight(group, "/"), pck.Version), + Version: strings.Trim(fmt.Sprintf("%s/%s", group, pck.Version), "/"), }, Creator: ctx.Doer, Metadata: pck.VersionMetadata, @@ -183,7 +183,7 @@ func DownloadPackageFile(ctx *context.Context) { Owner: ctx.Package.Owner, PackageType: packages_model.TypeRpm, Name: name, - Version: fmt.Sprintf("%s/%s", strings.TrimRight(group, "/"), 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")), @@ -210,7 +210,12 @@ func DeletePackageFile(webctx *context.Context) { 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, fmt.Sprintf("%s/%s", strings.TrimRight(group, "/"), 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 } diff --git a/templates/package/content/rpm.tmpl b/templates/package/content/rpm.tmpl index db6660ef82951..05e3c182a2308 100644 --- a/templates/package/content/rpm.tmpl +++ b/templates/package/content/rpm.tmpl @@ -6,8 +6,8 @@
# {{ctx.Locale.Tr "packages.rpm.distros.redhat"}}
 {{$group_name:= (index .Groups 0) -}}
-{{- if eq $group_name "/" -}}
-{{- $group_name = "" -}}
+{{- if $group_name -}}
+{{- $group_name = (print "/" $group_name) -}}
 {{- end -}}
 dnf config-manager --add-repo 
 
diff --git a/tests/integration/api_packages_rpm_test.go b/tests/integration/api_packages_rpm_test.go
index 5de4bb68c827b..3e4d5c86f6d79 100644
--- a/tests/integration/api_packages_rpm_test.go
+++ b/tests/integration/api_packages_rpm_test.go
@@ -118,7 +118,7 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN
 		assert.Nil(t, pd.SemVer)
 		assert.IsType(t, &rpm_module.VersionMetadata{}, pd.Metadata)
 		assert.Equal(t, packageName, pd.Package.Name)
-		assert.Equal(t, fmt.Sprintf("/el9/stable/%s", packageVersion), pd.Version.Version)
+		assert.Equal(t, fmt.Sprintf("el9/stable/%s", packageVersion), pd.Version.Version)
 
 		pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
 		assert.NoError(t, err)

From f66f1b92d5b0936ccd184658b334f3bfa25d43b6 Mon Sep 17 00:00:00 2001
From: "kailong.fu" 
Date: Mon, 30 Oct 2023 14:40:55 +0800
Subject: [PATCH 20/23] remove db merge

---
 models/migrations/migrations.go     |  2 --
 models/migrations/v1_22/v282.go     | 43 -----------------------------
 modules/templates/util_string.go    |  5 ++++
 routers/api/packages/rpm/rpm.go     |  4 +--
 routers/web/user/package.go         | 16 -----------
 templates/package/content/rpm.tmpl  |  2 +-
 templates/package/metadata/rpm.tmpl |  1 -
 7 files changed, 7 insertions(+), 66 deletions(-)
 delete mode 100644 models/migrations/v1_22/v282.go

diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 48d63a2912f48..4a06cdc73a3ac 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -548,8 +548,6 @@ var migrations = []Migration{
 	NewMigration("Rename user themes", v1_22.RenameUserThemes),
 	// v281 -> v282
 	NewMigration("Add auth_token table", v1_22.CreateAuthTokenTable),
-	// v282 -> v283
-	NewMigration("Migrate old rpm package index", v1_22.RebuildRpmPackage),
 }
 
 // GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v1_22/v282.go b/models/migrations/v1_22/v282.go
deleted file mode 100644
index 4974332375b3b..0000000000000
--- a/models/migrations/v1_22/v282.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package v1_22 //nolint
-
-import (
-	"code.gitea.io/gitea/modules/json"
-	"code.gitea.io/gitea/modules/packages/rpm"
-
-	"xorm.io/xorm"
-)
-
-func RebuildRpmPackage(x *xorm.Engine) error {
-	sess := x.NewSession()
-	defer sess.Close()
-	// NOTE: package_property[name='rpm.metadata'] is very large,
-	// and to avoid querying all of them resulting in large memory,
-	// a single RPM package is now used for updating.
-	metadata := make([][]string, 0, 4)
-	_, err := sess.Cols("ref_type", "ref_id", "package_file.composite_key", "value").
-		Table("package_property").
-		Join("left", "package_file", "`package_file`.id = `package_property`.ref_id").
-		Where("package_property.name = 'rpm.metadata'").Get(&metadata)
-	if err != nil {
-		return err
-	}
-	for _, data := range metadata {
-		var rpmMetadata rpm.FileMetadata
-		err = json.Unmarshal([]byte(data[3]), &rpmMetadata)
-		if err != nil {
-			return err
-		}
-		_, err = sess.Exec(
-			"INSERT INTO package_property(ref_type, ref_id, name, value) values (?,?,?,?),(?,?,?,?)",
-			data[0], data[1], rpm.PropertyGroup, data[2],
-			data[0], data[1], rpm.PropertyArchitecture, rpmMetadata.Architecture,
-		)
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
diff --git a/modules/templates/util_string.go b/modules/templates/util_string.go
index 18a0d5cacc976..613940ccdc487 100644
--- a/modules/templates/util_string.go
+++ b/modules/templates/util_string.go
@@ -4,6 +4,7 @@
 package templates
 
 import (
+	"regexp"
 	"strings"
 
 	"code.gitea.io/gitea/modules/base"
@@ -25,6 +26,10 @@ func (su *StringUtils) Contains(s, substr string) bool {
 	return strings.Contains(s, substr)
 }
 
+func (su *StringUtils) ReplaceAllStringRegex(s, regex, new string) string {
+	return regexp.MustCompile(regex).ReplaceAllString(s, new)
+}
+
 func (su *StringUtils) Split(s, sep string) []string {
 	return strings.Split(s, sep)
 }
diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go
index 9a547e6510cbe..37d01f04599b9 100644
--- a/routers/api/packages/rpm/rpm.go
+++ b/routers/api/packages/rpm/rpm.go
@@ -147,9 +147,7 @@ func UploadPackageFile(ctx *context.Context) {
 			Data:    buf,
 			IsLead:  true,
 			Properties: map[string]string{
-				rpm_module.PropertyMetadata:     string(fileMetadataRaw),
-				rpm_module.PropertyGroup:        group,
-				rpm_module.PropertyArchitecture: pck.FileMetadata.Architecture,
+				rpm_module.PropertyMetadata: string(fileMetadataRaw),
 			},
 		},
 	)
diff --git a/routers/web/user/package.go b/routers/web/user/package.go
index 7015235aa04e7..d8da6a192e55d 100644
--- a/routers/web/user/package.go
+++ b/routers/web/user/package.go
@@ -19,7 +19,6 @@ import (
 	"code.gitea.io/gitea/modules/log"
 	alpine_module "code.gitea.io/gitea/modules/packages/alpine"
 	debian_module "code.gitea.io/gitea/modules/packages/debian"
-	rpm_module "code.gitea.io/gitea/modules/packages/rpm"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/util"
 	"code.gitea.io/gitea/modules/web"
@@ -220,21 +219,6 @@ func ViewPackageVersion(ctx *context.Context) {
 		ctx.Data["Distributions"] = distributions.Values()
 		ctx.Data["Components"] = components.Values()
 		ctx.Data["Architectures"] = architectures.Values()
-	case packages_model.TypeRpm:
-		groups := make(container.Set[string])
-		architectures := make(container.Set[string])
-		for _, f := range pd.Files {
-			for _, pp := range f.Properties {
-				switch pp.Name {
-				case rpm_module.PropertyGroup:
-					groups.Add(pp.Value)
-				case rpm_module.PropertyArchitecture:
-					architectures.Add(pp.Value)
-				}
-			}
-		}
-		ctx.Data["Architectures"] = architectures.Values()
-		ctx.Data["Groups"] = groups.Values()
 	}
 
 	var (
diff --git a/templates/package/content/rpm.tmpl b/templates/package/content/rpm.tmpl
index 05e3c182a2308..4fd54a3197738 100644
--- a/templates/package/content/rpm.tmpl
+++ b/templates/package/content/rpm.tmpl
@@ -5,7 +5,7 @@
 			
# {{ctx.Locale.Tr "packages.rpm.distros.redhat"}}
-{{$group_name:= (index .Groups 0) -}}
+{{$group_name:= StringUtils.ReplaceAllStringRegex .PackageDescriptor.Version.Version "(/[^/]+|[^/]*)\\z" "" -}}
 {{- if $group_name -}}
 {{- $group_name = (print "/" $group_name) -}}
 {{- end -}}
diff --git a/templates/package/metadata/rpm.tmpl b/templates/package/metadata/rpm.tmpl
index ac7d1384ab6e3..026f129590598 100644
--- a/templates/package/metadata/rpm.tmpl
+++ b/templates/package/metadata/rpm.tmpl
@@ -1,5 +1,4 @@
 {{if eq .PackageDescriptor.Package.Type "rpm"}}
-	
{{svg "octicon-server" 16 "gt-mr-3"}} {{StringUtils.Join .Architectures ", "}}
{{if .PackageDescriptor.Metadata.ProjectURL}}
{{svg "octicon-link-external" 16 "gt-mr-3"}} {{ctx.Locale.Tr "packages.details.project_site"}}
{{end}} {{if .PackageDescriptor.Metadata.License}}
{{svg "octicon-law" 16 "gt-mr-3"}} {{.PackageDescriptor.Metadata.License}}
{{end}} {{end}} From 85c54fee1d5ae068c4b0774a5f19272d3443aa18 Mon Sep 17 00:00:00 2001 From: "kailong.fu" Date: Mon, 30 Oct 2023 14:43:58 +0800 Subject: [PATCH 21/23] remove db merge --- modules/packages/rpm/metadata.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/packages/rpm/metadata.go b/modules/packages/rpm/metadata.go index a1142cd60455a..1ba4c73e8d5ca 100644 --- a/modules/packages/rpm/metadata.go +++ b/modules/packages/rpm/metadata.go @@ -15,11 +15,9 @@ import ( ) const ( - PropertyMetadata = "rpm.metadata" - PropertyGroup = "rpm.group" - PropertyArchitecture = "rpm.architecture" - SettingKeyPrivate = "rpm.key.private" - SettingKeyPublic = "rpm.key.public" + PropertyMetadata = "rpm.metadata" + SettingKeyPrivate = "rpm.key.private" + SettingKeyPublic = "rpm.key.public" RepositoryPackage = "_rpm" RepositoryVersion = "_repository" From d69539c8e25a64a70d5d580e5b5e0cfe162fc8a1 Mon Sep 17 00:00:00 2001 From: dragon Date: Tue, 5 Dec 2023 18:52:01 +0800 Subject: [PATCH 22/23] merge #28309 --- routers/api/packages/rpm/rpm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index 922c38e38df14..75d19e2b436b8 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -67,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) From 5bb1193e11c28e6d7fe086b4a67ef25771c1902e Mon Sep 17 00:00:00 2001 From: dragon Date: Mon, 8 Jan 2024 12:02:33 +0800 Subject: [PATCH 23/23] fix rpm unit test --- tests/integration/api_packages_rpm_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/api_packages_rpm_test.go b/tests/integration/api_packages_rpm_test.go index 60e633d3d7af6..822b0b040e780 100644 --- a/tests/integration/api_packages_rpm_test.go +++ b/tests/integration/api_packages_rpm_test.go @@ -404,14 +404,14 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`, user.Name, user.Name, setting.AppN req := NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)) MakeRequest(t, req, http.StatusUnauthorized) - req = NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)). + req = NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)). AddBasicAuth(user.Name) MakeRequest(t, req, http.StatusNoContent) pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeRpm) assert.NoError(t, err) assert.Empty(t, pvs) - req = NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)). + req = NewRequest(t, "DELETE", fmt.Sprintf("%s/el9/stable/package/%s/%s/%s", rootURL, packageName, packageVersion, packageArchitecture)). AddBasicAuth(user.Name) MakeRequest(t, req, http.StatusNotFound) })