feat(packages): expose package file properties in the package files API (#40066)

Package files carry type specific properties like `debian.distribution`,
`debian.component`, `rpm.group` or `alpine.branch` that decide where a
file lives in a registry, but the API never returned them. A client
listing `GET /packages/{owner}/{type}/{name}/{version}/files` could not
tell which distribution or component a file belongs to, or tell apart
same-named files in different ones. Tools copying packages between
instances, like https://gitea.com/gitea/importer, need them to re-upload
a file to the same place.

This adds a `properties` map to `PackageFile`, limited to the properties
that locate a file. Internal ones like the rpm, alpine, arch and conda
metadata or the Debian control file stay hidden, as they can be many MiB
per file.

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-10-29 18:10:36 +00:00
1 parent eb9267365d
commit b0b31bc593
18 files changed
+225 -2

No files matched your search

+22
View File
@@ -0,0 +1,22 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package alpine
import (
alpine_module "gitea.dev/modules/packages/alpine"
packages_service "gitea.dev/services/packages"
)
type Specialization struct {
packages_service.SpecGetViewPackageVersionData
packages_service.SpecOnBeforeRemovePackageAll
packages_service.SpecOnBeforeRemovePackageVersion
packages_service.SpecRenderUsageManual
}
var _ packages_service.Specialization = (*Specialization)(nil)
func (s Specialization) PublicPropertyNames() []string {
return []string{alpine_module.PropertyBranch, alpine_module.PropertyRepository, alpine_module.PropertyArchitecture}
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package arch
import (
arch_module "gitea.dev/modules/packages/arch"
packages_service "gitea.dev/services/packages"
)
type Specialization struct {
packages_service.SpecGetViewPackageVersionData
packages_service.SpecOnBeforeRemovePackageAll
packages_service.SpecOnBeforeRemovePackageVersion
packages_service.SpecRenderUsageManual
}
var _ packages_service.Specialization = (*Specialization)(nil)
func (s Specialization) PublicPropertyNames() []string {
return []string{arch_module.PropertyRepository, arch_module.PropertyArchitecture}
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package conan
import (
conan_module "gitea.dev/modules/packages/conan"
packages_service "gitea.dev/services/packages"
)
type Specialization struct {
packages_service.SpecGetViewPackageVersionData
packages_service.SpecOnBeforeRemovePackageAll
packages_service.SpecOnBeforeRemovePackageVersion
packages_service.SpecRenderUsageManual
}
var _ packages_service.Specialization = (*Specialization)(nil)
func (s Specialization) PublicPropertyNames() []string {
return []string{conan_module.PropertyRecipeUser, conan_module.PropertyRecipeChannel, conan_module.PropertyRecipeRevision, conan_module.PropertyPackageReference, conan_module.PropertyPackageRevision}
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package conda
import (
conda_module "gitea.dev/modules/packages/conda"
packages_service "gitea.dev/services/packages"
)
type Specialization struct {
packages_service.SpecGetViewPackageVersionData
packages_service.SpecOnBeforeRemovePackageAll
packages_service.SpecOnBeforeRemovePackageVersion
packages_service.SpecRenderUsageManual
}
var _ packages_service.Specialization = (*Specialization)(nil)
func (s Specialization) PublicPropertyNames() []string {
return []string{conda_module.PropertySubdir}
}
+4
View File
@@ -85,3 +85,7 @@ func (s Specialization) RenderSetupManual(ctx context.Context, pkg *packages_mod
w.WriteHTML(`</div>`)
return w.HTMLString()
}
func (s Specialization) PublicPropertyNames() []string {
return []string{debian_module.PropertyDistribution, debian_module.PropertyComponent, debian_module.PropertyArchitecture}
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package nuget
import (
nuget_module "gitea.dev/modules/packages/nuget"
packages_service "gitea.dev/services/packages"
)
type Specialization struct {
packages_service.SpecGetViewPackageVersionData
packages_service.SpecOnBeforeRemovePackageAll
packages_service.SpecOnBeforeRemovePackageVersion
packages_service.SpecRenderUsageManual
}
var _ packages_service.Specialization = (*Specialization)(nil)
func (s Specialization) PublicPropertyNames() []string {
return []string{nuget_module.PropertySymbolID}
}
+1
View File
@@ -35,6 +35,7 @@ var (
)
type Specialization interface {
PublicPropertyNames() []string // only properties locating the file, the others are internal and can be large
OnBeforeRemovePackageAll(ctx context.Context, doer *user_model.User, pkg *packages_model.Package, pds []*packages_model.PackageDescriptor) error
OnBeforeRemovePackageVersion(ctx context.Context, doer *user_model.User, pd *packages_model.PackageDescriptor) error
GetViewPackageVersionData(ctx context.Context, pd *packages_model.PackageDescriptor) (any, error)
+14
View File
@@ -6,14 +6,28 @@ package pkgspec
import (
packages_model "gitea.dev/models/packages"
packages_service "gitea.dev/services/packages"
"gitea.dev/services/packages/alpine"
"gitea.dev/services/packages/arch"
"gitea.dev/services/packages/conan"
"gitea.dev/services/packages/conda"
"gitea.dev/services/packages/debian"
"gitea.dev/services/packages/nuget"
"gitea.dev/services/packages/rpm"
"gitea.dev/services/packages/terraform"
"gitea.dev/services/packages/vagrant"
)
func InitManager() error {
mgr := packages_service.GetSpecManager()
mgr.Add(packages_model.TypeAlpine, &alpine.Specialization{})
mgr.Add(packages_model.TypeArch, &arch.Specialization{})
mgr.Add(packages_model.TypeConan, &conan.Specialization{})
mgr.Add(packages_model.TypeConda, &conda.Specialization{})
mgr.Add(packages_model.TypeDebian, &debian.Specialization{})
mgr.Add(packages_model.TypeNuGet, &nuget.Specialization{})
mgr.Add(packages_model.TypeRpm, &rpm.Specialization{})
mgr.Add(packages_model.TypeTerraformState, &terraform.Specialization{})
mgr.Add(packages_model.TypeVagrant, &vagrant.Specialization{})
// TODO: add more in the future, refactor the existing code to use this approach
return nil
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package rpm
import (
rpm_module "gitea.dev/modules/packages/rpm"
packages_service "gitea.dev/services/packages"
)
type Specialization struct {
packages_service.SpecGetViewPackageVersionData
packages_service.SpecOnBeforeRemovePackageAll
packages_service.SpecOnBeforeRemovePackageVersion
packages_service.SpecRenderUsageManual
}
var _ packages_service.Specialization = (*Specialization)(nil)
func (s Specialization) PublicPropertyNames() []string {
return []string{rpm_module.PropertyGroup, rpm_module.PropertyArchitecture}
}
+7
View File
@@ -36,7 +36,14 @@ func (*SpecRenderUsageManual) RenderSetupManual(ctx context.Context, pkg *packag
return ""
}
type SpecPublicPropertyNames struct{}
func (*SpecPublicPropertyNames) PublicPropertyNames() []string {
return nil
}
type specDefault struct {
SpecPublicPropertyNames
SpecGetViewPackageVersionData
SpecOnBeforeRemovePackageAll
SpecOnBeforeRemovePackageVersion
+1
View File
@@ -15,6 +15,7 @@ import (
)
type Specialization struct {
packages_service.SpecPublicPropertyNames
packages_service.SpecRenderUsageManual
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package vagrant
import (
vagrant_module "gitea.dev/modules/packages/vagrant"
packages_service "gitea.dev/services/packages"
)
type Specialization struct {
packages_service.SpecGetViewPackageVersionData
packages_service.SpecOnBeforeRemovePackageAll
packages_service.SpecOnBeforeRemovePackageVersion
packages_service.SpecRenderUsageManual
}
var _ packages_service.Specialization = (*Specialization)(nil)
func (s Specialization) PublicPropertyNames() []string {
return []string{vagrant_module.PropertyProvider}
}