feat: add architecture-specific removal support for arch package (#5351)
- [x] add architecture-specific removal support
- [x] Fix upload competition
- [x] Fix not checking input when downloading
docs: https://codeberg.org/forgejo/docs/pulls/874
### Release notes
- [ ] I do not want this change to show in the release notes.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5351
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Co-authored-by: Exploding Dragon <explodingfkl@gmail.com>
Co-committed-by: Exploding Dragon <explodingfkl@gmail.com>
(cherry picked from commit 89742c4913
)
This commit is contained in:
parent
f0dab9cc05
commit
658ed564cb
7 changed files with 151 additions and 100 deletions
|
@ -39,8 +39,8 @@ const (
|
|||
var (
|
||||
reName = regexp.MustCompile(`^[a-zA-Z0-9@._+-]+$`)
|
||||
reVer = regexp.MustCompile(`^[a-zA-Z0-9:_.+]+-+[0-9]+$`)
|
||||
reOptDep = regexp.MustCompile(`^[a-zA-Z0-9@._+-]+([<>]?=?[a-zA-Z0-9@._+-]+)?(:.*)?$`)
|
||||
rePkgVer = regexp.MustCompile(`^[a-zA-Z0-9@._+-]+([<>]?=?[a-zA-Z0-9@._+-]+)?$`)
|
||||
reOptDep = regexp.MustCompile(`^[a-zA-Z0-9@._+-]+([<>]?=?([0-9]+:)?[a-zA-Z0-9@._+-]+)?(:.*)?$`)
|
||||
rePkgVer = regexp.MustCompile(`^[a-zA-Z0-9@._+-]+([<>]?=?([0-9]+:)?[a-zA-Z0-9@._+-]+)?$`)
|
||||
|
||||
magicZSTD = []byte{0x28, 0xB5, 0x2F, 0xFD}
|
||||
magicXZ = []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A}
|
||||
|
@ -71,7 +71,7 @@ type VersionMetadata struct {
|
|||
Conflicts []string `json:"conflicts,omitempty"`
|
||||
Replaces []string `json:"replaces,omitempty"`
|
||||
Backup []string `json:"backup,omitempty"`
|
||||
Xdata []string `json:"xdata,omitempty"`
|
||||
XData []string `json:"xdata,omitempty"`
|
||||
}
|
||||
|
||||
// FileMetadata Metadata related to specific package file.
|
||||
|
@ -125,7 +125,7 @@ func ParsePackage(r *packages.HashedBuffer) (*Package, error) {
|
|||
defer tarball.Close()
|
||||
|
||||
var pkg *Package
|
||||
var mtree bool
|
||||
var mTree bool
|
||||
|
||||
for {
|
||||
f, err := tarball.Read()
|
||||
|
@ -135,24 +135,24 @@ func ParsePackage(r *packages.HashedBuffer) (*Package, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
switch f.Name() {
|
||||
case ".PKGINFO":
|
||||
pkg, err = ParsePackageInfo(tarballType, f)
|
||||
if err != nil {
|
||||
_ = f.Close()
|
||||
return nil, err
|
||||
}
|
||||
case ".MTREE":
|
||||
mtree = true
|
||||
mTree = true
|
||||
}
|
||||
_ = f.Close()
|
||||
}
|
||||
|
||||
if pkg == nil {
|
||||
return nil, util.NewInvalidArgumentErrorf(".PKGINFO file not found")
|
||||
}
|
||||
|
||||
if !mtree {
|
||||
if !mTree {
|
||||
return nil, util.NewInvalidArgumentErrorf(".MTREE file not found")
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ func ParsePackageInfo(compressType string, r io.Reader) (*Package, error) {
|
|||
case "replaces":
|
||||
p.VersionMetadata.Replaces = append(p.VersionMetadata.Replaces, value)
|
||||
case "xdata":
|
||||
p.VersionMetadata.Xdata = append(p.VersionMetadata.Xdata, value)
|
||||
p.VersionMetadata.XData = append(p.VersionMetadata.XData, value)
|
||||
case "builddate":
|
||||
bd, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
|
@ -260,48 +260,43 @@ func ValidatePackageSpec(p *Package) error {
|
|||
return util.NewInvalidArgumentErrorf("invalid project URL")
|
||||
}
|
||||
}
|
||||
for _, cd := range p.VersionMetadata.CheckDepends {
|
||||
if !rePkgVer.MatchString(cd) {
|
||||
return util.NewInvalidArgumentErrorf("invalid check dependency: %s", cd)
|
||||
for _, checkDepend := range p.VersionMetadata.CheckDepends {
|
||||
if !rePkgVer.MatchString(checkDepend) {
|
||||
return util.NewInvalidArgumentErrorf("invalid check dependency: %s", checkDepend)
|
||||
}
|
||||
}
|
||||
for _, d := range p.VersionMetadata.Depends {
|
||||
if !rePkgVer.MatchString(d) {
|
||||
return util.NewInvalidArgumentErrorf("invalid dependency: %s", d)
|
||||
for _, depend := range p.VersionMetadata.Depends {
|
||||
if !rePkgVer.MatchString(depend) {
|
||||
return util.NewInvalidArgumentErrorf("invalid dependency: %s", depend)
|
||||
}
|
||||
}
|
||||
for _, md := range p.VersionMetadata.MakeDepends {
|
||||
if !rePkgVer.MatchString(md) {
|
||||
return util.NewInvalidArgumentErrorf("invalid make dependency: %s", md)
|
||||
for _, makeDepend := range p.VersionMetadata.MakeDepends {
|
||||
if !rePkgVer.MatchString(makeDepend) {
|
||||
return util.NewInvalidArgumentErrorf("invalid make dependency: %s", makeDepend)
|
||||
}
|
||||
}
|
||||
for _, p := range p.VersionMetadata.Provides {
|
||||
if !rePkgVer.MatchString(p) {
|
||||
return util.NewInvalidArgumentErrorf("invalid provides: %s", p)
|
||||
for _, provide := range p.VersionMetadata.Provides {
|
||||
if !rePkgVer.MatchString(provide) {
|
||||
return util.NewInvalidArgumentErrorf("invalid provides: %s", provide)
|
||||
}
|
||||
}
|
||||
for _, p := range p.VersionMetadata.Conflicts {
|
||||
if !rePkgVer.MatchString(p) {
|
||||
return util.NewInvalidArgumentErrorf("invalid conflicts: %s", p)
|
||||
for _, conflict := range p.VersionMetadata.Conflicts {
|
||||
if !rePkgVer.MatchString(conflict) {
|
||||
return util.NewInvalidArgumentErrorf("invalid conflicts: %s", conflict)
|
||||
}
|
||||
}
|
||||
for _, p := range p.VersionMetadata.Replaces {
|
||||
if !rePkgVer.MatchString(p) {
|
||||
return util.NewInvalidArgumentErrorf("invalid replaces: %s", p)
|
||||
for _, replace := range p.VersionMetadata.Replaces {
|
||||
if !rePkgVer.MatchString(replace) {
|
||||
return util.NewInvalidArgumentErrorf("invalid replaces: %s", replace)
|
||||
}
|
||||
}
|
||||
for _, p := range p.VersionMetadata.Replaces {
|
||||
if !rePkgVer.MatchString(p) {
|
||||
return util.NewInvalidArgumentErrorf("invalid xdata: %s", p)
|
||||
for _, optDepend := range p.VersionMetadata.OptDepends {
|
||||
if !reOptDep.MatchString(optDepend) {
|
||||
return util.NewInvalidArgumentErrorf("invalid optional dependency: %s", optDepend)
|
||||
}
|
||||
}
|
||||
for _, od := range p.VersionMetadata.OptDepends {
|
||||
if !reOptDep.MatchString(od) {
|
||||
return util.NewInvalidArgumentErrorf("invalid optional dependency: %s", od)
|
||||
}
|
||||
}
|
||||
for _, bf := range p.VersionMetadata.Backup {
|
||||
if strings.HasPrefix(bf, "/") {
|
||||
for _, b := range p.VersionMetadata.Backup {
|
||||
if strings.HasPrefix(b, "/") {
|
||||
return util.NewInvalidArgumentErrorf("backup file contains leading forward slash")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,18 +175,20 @@ func CommonRoutes() *web.Route {
|
|||
arch.PushPackage(ctx)
|
||||
return
|
||||
} else if isDelete {
|
||||
if groupLen < 2 {
|
||||
if groupLen < 3 {
|
||||
ctx.Status(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if groupLen == 2 {
|
||||
if groupLen == 3 {
|
||||
ctx.SetParams("group", "")
|
||||
ctx.SetParams("package", pathGroups[0])
|
||||
ctx.SetParams("version", pathGroups[1])
|
||||
ctx.SetParams("arch", pathGroups[2])
|
||||
} else {
|
||||
ctx.SetParams("group", strings.Join(pathGroups[:groupLen-2], "/"))
|
||||
ctx.SetParams("package", pathGroups[groupLen-2])
|
||||
ctx.SetParams("version", pathGroups[groupLen-1])
|
||||
ctx.SetParams("group", strings.Join(pathGroups[:groupLen-3], "/"))
|
||||
ctx.SetParams("package", pathGroups[groupLen-3])
|
||||
ctx.SetParams("version", pathGroups[groupLen-2])
|
||||
ctx.SetParams("arch", pathGroups[groupLen-1])
|
||||
}
|
||||
reqPackageAccess(perm.AccessModeWrite)(ctx)
|
||||
if ctx.Written() {
|
||||
|
|
|
@ -9,12 +9,14 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
packages_module "code.gitea.io/gitea/modules/packages"
|
||||
arch_module "code.gitea.io/gitea/modules/packages/arch"
|
||||
"code.gitea.io/gitea/modules/sync"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers/api/packages/helper"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
|
@ -25,6 +27,8 @@ import (
|
|||
var (
|
||||
archPkgOrSig = regexp.MustCompile(`^.*\.pkg\.tar\.\w+(\.sig)*$`)
|
||||
archDBOrSig = regexp.MustCompile(`^.*.db(\.tar\.gz)*(\.sig)*$`)
|
||||
|
||||
locker = sync.NewExclusivePool()
|
||||
)
|
||||
|
||||
func apiError(ctx *context.Context, status int, obj any) {
|
||||
|
@ -33,6 +37,14 @@ func apiError(ctx *context.Context, status int, obj any) {
|
|||
})
|
||||
}
|
||||
|
||||
func refreshLocker(ctx *context.Context, group string) func() {
|
||||
key := fmt.Sprintf("pkg_%d_arch_pkg_%s", ctx.Package.Owner.ID, group)
|
||||
locker.CheckIn(key)
|
||||
return func() {
|
||||
locker.CheckOut(key)
|
||||
}
|
||||
}
|
||||
|
||||
func GetRepositoryKey(ctx *context.Context) {
|
||||
_, pub, err := arch_service.GetOrCreateKeyPair(ctx, ctx.Package.Owner.ID)
|
||||
if err != nil {
|
||||
|
@ -48,7 +60,8 @@ func GetRepositoryKey(ctx *context.Context) {
|
|||
|
||||
func PushPackage(ctx *context.Context) {
|
||||
group := ctx.Params("group")
|
||||
|
||||
releaser := refreshLocker(ctx, group)
|
||||
defer releaser()
|
||||
upload, needToClose, err := ctx.UploadStream()
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
|
@ -154,6 +167,7 @@ func PushPackage(ctx *context.Context) {
|
|||
})
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
if err = arch_service.BuildPacmanDB(ctx, ctx.Package.Owner.ID, group, p.FileMetadata.Arch); err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
|
@ -169,7 +183,7 @@ func GetPackageOrDB(ctx *context.Context) {
|
|||
arch = ctx.Params("arch")
|
||||
)
|
||||
if archPkgOrSig.MatchString(file) {
|
||||
pkg, err := arch_service.GetPackageFile(ctx, group, file, ctx.Package.Owner.ID)
|
||||
pkg, u, pf, err := arch_service.GetPackageFile(ctx, group, file, ctx.Package.Owner.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
apiError(ctx, http.StatusNotFound, err)
|
||||
|
@ -178,15 +192,12 @@ func GetPackageOrDB(ctx *context.Context) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.ServeContent(pkg, &context.ServeHeaderOptions{
|
||||
Filename: file,
|
||||
})
|
||||
helper.ServePackageFile(ctx, pkg, u, pf)
|
||||
return
|
||||
}
|
||||
|
||||
if archDBOrSig.MatchString(file) {
|
||||
pkg, err := arch_service.GetPackageDBFile(ctx, group, arch, ctx.Package.Owner.ID,
|
||||
pkg, u, pf, err := arch_service.GetPackageDBFile(ctx, group, arch, ctx.Package.Owner.ID,
|
||||
strings.HasSuffix(file, ".sig"))
|
||||
if err != nil {
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
|
@ -196,9 +207,7 @@ func GetPackageOrDB(ctx *context.Context) {
|
|||
}
|
||||
return
|
||||
}
|
||||
ctx.ServeContent(pkg, &context.ServeHeaderOptions{
|
||||
Filename: file,
|
||||
})
|
||||
helper.ServePackageFile(ctx, pkg, u, pf)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -210,7 +219,10 @@ func RemovePackage(ctx *context.Context) {
|
|||
group = ctx.Params("group")
|
||||
pkg = ctx.Params("package")
|
||||
ver = ctx.Params("version")
|
||||
pkgArch = ctx.Params("arch")
|
||||
)
|
||||
releaser := refreshLocker(ctx, group)
|
||||
defer releaser()
|
||||
pv, err := packages_model.GetVersionByNameAndVersion(
|
||||
ctx, ctx.Package.Owner.ID, packages_model.TypeArch, pkg, ver,
|
||||
)
|
||||
|
@ -229,7 +241,13 @@ func RemovePackage(ctx *context.Context) {
|
|||
}
|
||||
deleted := false
|
||||
for _, file := range files {
|
||||
if file.CompositeKey == group {
|
||||
extName := fmt.Sprintf("-%s.pkg.tar%s", pkgArch, filepath.Ext(file.LowerName))
|
||||
if strings.HasSuffix(file.LowerName, ".sig") {
|
||||
extName = fmt.Sprintf("-%s.pkg.tar%s.sig", pkgArch,
|
||||
filepath.Ext(strings.TrimSuffix(file.LowerName, filepath.Ext(file.LowerName))))
|
||||
}
|
||||
if file.CompositeKey == group &&
|
||||
strings.HasSuffix(file.LowerName, extName) {
|
||||
deleted = true
|
||||
err := packages_service.RemovePackageFileAndVersionIfUnreferenced(ctx, ctx.ContextUser, file)
|
||||
if err != nil {
|
||||
|
@ -242,6 +260,7 @@ func RemovePackage(ctx *context.Context) {
|
|||
err = arch_service.BuildCustomRepositoryFiles(ctx, ctx.Package.Owner.ID, group)
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
ctx.Status(http.StatusNoContent)
|
||||
} else {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
@ -20,6 +21,7 @@ import (
|
|||
packages_module "code.gitea.io/gitea/modules/packages"
|
||||
arch_module "code.gitea.io/gitea/modules/packages/arch"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/sync"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
packages_service "code.gitea.io/gitea/services/packages"
|
||||
|
||||
|
@ -28,6 +30,8 @@ import (
|
|||
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
||||
)
|
||||
|
||||
var locker = sync.NewExclusivePool()
|
||||
|
||||
func GetOrCreateRepositoryVersion(ctx context.Context, ownerID int64) (*packages_model.PackageVersion, error) {
|
||||
return packages_service.GetOrCreateInternalPackageVersion(ctx, ownerID, packages_model.TypeArch, arch_module.RepositoryPackage, arch_module.RepositoryVersion)
|
||||
}
|
||||
|
@ -101,6 +105,9 @@ func NewFileSign(ctx context.Context, ownerID int64, input io.Reader) (*packages
|
|||
|
||||
// BuildPacmanDB Create db signature cache
|
||||
func BuildPacmanDB(ctx context.Context, ownerID int64, group, arch string) error {
|
||||
key := fmt.Sprintf("pkg_%d_arch_db_%s", ownerID, group)
|
||||
locker.CheckIn(key)
|
||||
defer locker.CheckOut(key)
|
||||
pv, err := GetOrCreateRepositoryVersion(ctx, ownerID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -173,15 +180,18 @@ func createDB(ctx context.Context, ownerID int64, group, arch string) (*packages
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer db.Close()
|
||||
gw := gzip.NewWriter(db)
|
||||
defer gw.Close()
|
||||
tw := tar.NewWriter(gw)
|
||||
defer tw.Close()
|
||||
count := 0
|
||||
for _, pkg := range pkgs {
|
||||
versions, err := packages_model.GetVersionsByPackageName(
|
||||
ctx, ownerID, packages_model.TypeArch, pkg.Name,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Join(tw.Close(), gw.Close(), db.Close(), err)
|
||||
return nil, err
|
||||
}
|
||||
sort.Slice(versions, func(i, j int) bool {
|
||||
return versions[i].CreatedUnix > versions[j].CreatedUnix
|
||||
|
@ -190,7 +200,7 @@ func createDB(ctx context.Context, ownerID int64, group, arch string) (*packages
|
|||
for _, ver := range versions {
|
||||
files, err := packages_model.GetFilesByVersionID(ctx, ver.ID)
|
||||
if err != nil {
|
||||
return nil, errors.Join(tw.Close(), gw.Close(), db.Close(), err)
|
||||
return nil, err
|
||||
}
|
||||
var pf *packages_model.PackageFile
|
||||
for _, file := range files {
|
||||
|
@ -213,7 +223,7 @@ func createDB(ctx context.Context, ownerID int64, group, arch string) (*packages
|
|||
ctx, packages_model.PropertyTypeFile, pf.ID, arch_module.PropertyDescription,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Join(tw.Close(), gw.Close(), db.Close(), err)
|
||||
return nil, err
|
||||
}
|
||||
if len(pps) >= 1 {
|
||||
meta := []byte(pps[0].Value)
|
||||
|
@ -223,60 +233,50 @@ func createDB(ctx context.Context, ownerID int64, group, arch string) (*packages
|
|||
Mode: int64(os.ModePerm),
|
||||
}
|
||||
if err = tw.WriteHeader(header); err != nil {
|
||||
return nil, errors.Join(tw.Close(), gw.Close(), db.Close(), err)
|
||||
return nil, err
|
||||
}
|
||||
if _, err := tw.Write(meta); err != nil {
|
||||
return nil, errors.Join(tw.Close(), gw.Close(), db.Close(), err)
|
||||
return nil, err
|
||||
}
|
||||
count++
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
defer gw.Close()
|
||||
defer tw.Close()
|
||||
if count == 0 {
|
||||
return nil, errors.Join(db.Close(), io.EOF)
|
||||
return nil, io.EOF
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// GetPackageFile Get data related to provided filename and distribution, for package files
|
||||
// update download counter.
|
||||
func GetPackageFile(ctx context.Context, group, file string, ownerID int64) (io.ReadSeekCloser, error) {
|
||||
pf, err := getPackageFile(ctx, group, file, ownerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func GetPackageFile(ctx context.Context, group, file string, ownerID int64) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||
fileSplit := strings.Split(file, "-")
|
||||
if len(fileSplit) <= 3 {
|
||||
return nil, nil, nil, errors.New("invalid file format, need <name>-<version>-<release>-<arch>.pkg.<archive>")
|
||||
}
|
||||
|
||||
filestream, _, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
||||
return filestream, err
|
||||
}
|
||||
|
||||
// Ejects parameters required to get package file property from file name.
|
||||
func getPackageFile(ctx context.Context, group, file string, ownerID int64) (*packages_model.PackageFile, error) {
|
||||
var (
|
||||
splt = strings.Split(file, "-")
|
||||
pkgname = strings.Join(splt[0:len(splt)-3], "-")
|
||||
vername = splt[len(splt)-3] + "-" + splt[len(splt)-2]
|
||||
pkgName = strings.Join(fileSplit[0:len(fileSplit)-3], "-")
|
||||
pkgVer = fileSplit[len(fileSplit)-3] + "-" + fileSplit[len(fileSplit)-2]
|
||||
)
|
||||
|
||||
version, err := packages_model.GetVersionByNameAndVersion(ctx, ownerID, packages_model.TypeArch, pkgname, vername)
|
||||
version, err := packages_model.GetVersionByNameAndVersion(ctx, ownerID, packages_model.TypeArch, pkgName, pkgVer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
pkgfile, err := packages_model.GetFileForVersionByName(ctx, version.ID, file, group)
|
||||
pkgFile, err := packages_model.GetFileForVersionByName(ctx, version.ID, file, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return pkgfile, nil
|
||||
|
||||
return packages_service.GetPackageFileStream(ctx, pkgFile)
|
||||
}
|
||||
|
||||
func GetPackageDBFile(ctx context.Context, group, arch string, ownerID int64, signFile bool) (io.ReadSeekCloser, error) {
|
||||
func GetPackageDBFile(ctx context.Context, group, arch string, ownerID int64, signFile bool) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||
pv, err := GetOrCreateRepositoryVersion(ctx, ownerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
fileName := fmt.Sprintf("%s.db", arch)
|
||||
if signFile {
|
||||
|
@ -284,10 +284,9 @@ func GetPackageDBFile(ctx context.Context, group, arch string, ownerID int64, si
|
|||
}
|
||||
file, err := packages_model.GetFileForVersionByName(ctx, pv.ID, fileName, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
filestream, _, _, err := packages_service.GetPackageFileStream(ctx, file)
|
||||
return filestream, err
|
||||
return packages_service.GetPackageFileStream(ctx, file)
|
||||
}
|
||||
|
||||
// GetOrCreateKeyPair gets or creates the PGP keys used to sign repository metadata files
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{if eq .PackageDescriptor.Package.Type "arch"}}
|
||||
{{range .PackageDescriptor.Metadata.License}}<div class="item" title="{{$.locale.Tr "packages.details.license"}}">{{svg "octicon-law" 16 "gt-mr-3"}} {{.}}</div>{{end}}
|
||||
{{if .PackageDescriptor.Metadata.ProjectURL}}<div class="item">{{svg "octicon-link-external" 16 "mr-3"}} <a href="{{.PackageDescriptor.Metadata.ProjectURL}}" target="_blank" rel="noopener noreferrer me">{{ctx.Locale.Tr "packages.details.project_site"}}</a></div>{{end}}
|
||||
{{if .PackageDescriptor.Metadata.ProjectURL}}<div class="item">{{svg "octicon-link-external" 16 "tw-mr-2"}} <a href="{{.PackageDescriptor.Metadata.ProjectURL}}" target="_blank" rel="noopener noreferrer me">{{ctx.Locale.Tr "packages.details.project_site"}}</a></div>{{end}}
|
||||
{{range .PackageDescriptor.Metadata.License}}<div class="item" title="{{$.locale.Tr "packages.details.license"}}">{{svg "octicon-law" 16 "tw-mr-2"}} {{.}}</div>{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
|
@ -258,11 +259,15 @@ HMhNSS1IzUsBcpJAPFAwwUXSM0u4BjoaR8EoGAWjgGQAAILFeyQADAAA
|
|||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
req = NewRequestWithBody(t, "DELETE", rootURL+"/base/notfound/1.0.0-1", nil).
|
||||
req = NewRequestWithBody(t, "DELETE", rootURL+"/base/notfound/1.0.0-1/any", nil).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestWithBody(t, "DELETE", groupURL+"/test/1.0.0-1", nil).
|
||||
req = NewRequestWithBody(t, "DELETE", groupURL+"/test/1.0.0-1/x86_64", nil).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
req = NewRequestWithBody(t, "DELETE", groupURL+"/test/1.0.0-1/any", nil).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
|
@ -270,12 +275,22 @@ HMhNSS1IzUsBcpJAPFAwwUXSM0u4BjoaR8EoGAWjgGQAAILFeyQADAAA
|
|||
respPkg := MakeRequest(t, req, http.StatusOK)
|
||||
files, err := listTarGzFiles(respPkg.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, files, 1) // other pkg in L225
|
||||
require.Len(t, files, 1)
|
||||
|
||||
req = NewRequestWithBody(t, "DELETE", groupURL+"/test2/1.0.0-1", nil).
|
||||
req = NewRequestWithBody(t, "DELETE", groupURL+"/test2/1.0.0-1/any", nil).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
req = NewRequest(t, "GET", groupURL+"/x86_64/base.db")
|
||||
|
||||
req = NewRequest(t, "GET", groupURL+"/x86_64/base.db").
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
req = NewRequestWithBody(t, "DELETE", groupURL+"/test/1.0.0-1/aarch64", nil).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
req = NewRequest(t, "GET", groupURL+"/aarch64/base.db").
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
|
@ -294,12 +309,33 @@ HMhNSS1IzUsBcpJAPFAwwUXSM0u4BjoaR8EoGAWjgGQAAILFeyQADAAA
|
|||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
require.Equal(t, pkgs[key], resp.Body.Bytes())
|
||||
|
||||
req = NewRequestWithBody(t, "DELETE", groupURL+"/test2/1.0.0-1", nil).
|
||||
req = NewRequestWithBody(t, "DELETE", groupURL+"/test2/1.0.0-1/any", nil).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
})
|
||||
}
|
||||
}
|
||||
t.Run("Concurrent Upload", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
var wg sync.WaitGroup
|
||||
|
||||
targets := []string{"any", "aarch64", "x86_64"}
|
||||
for _, tag := range targets {
|
||||
wg.Add(1)
|
||||
go func(i string) {
|
||||
defer wg.Done()
|
||||
req := NewRequestWithBody(t, "PUT", rootURL, bytes.NewReader(pkgs[i])).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
}(tag)
|
||||
}
|
||||
wg.Wait()
|
||||
for _, target := range targets {
|
||||
req := NewRequestWithBody(t, "DELETE", rootURL+"/test/1.0.0-1/"+target, nil).
|
||||
AddBasicAuth(user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func getProperty(data, key string) string {
|
||||
|
@ -318,10 +354,10 @@ func getProperty(data, key string) string {
|
|||
|
||||
func listTarGzFiles(data []byte) (fstest.MapFS, error) {
|
||||
reader, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
defer reader.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer reader.Close()
|
||||
tarRead := tar.NewReader(reader)
|
||||
files := make(fstest.MapFS)
|
||||
for {
|
||||
|
|
Loading…
Reference in a new issue