mirror of
https://github.com/go-gitea/gitea.git
synced 2024-09-01 14:56:30 +00:00
212 lines
5.7 KiB
Go
212 lines
5.7 KiB
Go
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package arch
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"code.gitea.io/gitea/models/db"
|
|
pkg_model "code.gitea.io/gitea/models/packages"
|
|
"code.gitea.io/gitea/models/repo"
|
|
"code.gitea.io/gitea/models/user"
|
|
"code.gitea.io/gitea/modules/context"
|
|
"code.gitea.io/gitea/modules/json"
|
|
"code.gitea.io/gitea/modules/packages"
|
|
"code.gitea.io/gitea/modules/packages/arch"
|
|
"code.gitea.io/gitea/modules/storage"
|
|
pkg_service "code.gitea.io/gitea/services/packages"
|
|
)
|
|
|
|
type UpdateMetadataParameters struct {
|
|
User *user.User
|
|
Md *arch.Metadata
|
|
}
|
|
|
|
// This function gets existing package metadata for provided version present,
|
|
// combines architecture and distribution info and creates new metadata with
|
|
// combined set of parameters.
|
|
func UpdateMetadata(ctx *context.Context, p *UpdateMetadataParameters) error {
|
|
ver, err := pkg_model.GetVersionByNameAndVersion(ctx, p.User.ID, pkg_model.TypeArch, p.Md.Name, p.Md.Version)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var currmd arch.Metadata
|
|
err = json.Unmarshal([]byte(ver.MetadataJSON), &currmd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
currmd.Arch = arch.UnifiedList(currmd.Arch, p.Md.Arch)
|
|
currmd.Distribution = arch.UnifiedList(currmd.Distribution, p.Md.Distribution)
|
|
currmd.DistroArch = arch.UnifiedList(currmd.DistroArch, p.Md.DistroArch)
|
|
|
|
b, err := json.Marshal(&currmd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ver.MetadataJSON = string(b)
|
|
|
|
return pkg_model.UpdateVersion(ctx, ver)
|
|
}
|
|
|
|
// Parameters required to save new arch package.
|
|
type SaveFileParams struct {
|
|
Creator *user.User
|
|
Owner *user.User
|
|
Metadata *arch.Metadata
|
|
Data []byte
|
|
Filename string
|
|
Distro string
|
|
IsLead bool
|
|
}
|
|
|
|
// This function creates new package, version and package_file properties in
|
|
// database, and writes blob to file storage. If package/version/blob exists it
|
|
// will overwrite existing data. Package id and error will be returned.
|
|
func SaveFile(ctx *context.Context, p *SaveFileParams) (int64, error) {
|
|
buf, err := packages.CreateHashedBufferFromReader(bytes.NewReader(p.Data))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer buf.Close()
|
|
|
|
pv, _, err := pkg_service.CreatePackageOrAddFileToExisting(
|
|
&pkg_service.PackageCreationInfo{
|
|
PackageInfo: pkg_service.PackageInfo{
|
|
Owner: p.Owner,
|
|
PackageType: pkg_model.TypeArch,
|
|
Name: p.Metadata.Name,
|
|
Version: p.Metadata.Version,
|
|
},
|
|
Creator: p.Creator,
|
|
Metadata: p.Metadata,
|
|
},
|
|
&pkg_service.PackageFileCreationInfo{
|
|
PackageFileInfo: pkg_service.PackageFileInfo{
|
|
Filename: p.Filename,
|
|
CompositeKey: p.Distro + "-" + p.Filename,
|
|
},
|
|
Creator: p.Creator,
|
|
Data: buf,
|
|
OverwriteExisting: true,
|
|
IsLead: p.IsLead,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return pv.PackageID, nil
|
|
}
|
|
|
|
// Get data related to provided file name and distribution, and update download
|
|
// counter if actual package file is retrieved from database.
|
|
func GetFileObject(ctx *context.Context, distro, file string) (storage.Object, error) {
|
|
db := db.GetEngine(ctx)
|
|
|
|
pkgfile := &pkg_model.PackageFile{CompositeKey: distro + "-" + file}
|
|
|
|
ok, err := db.Get(pkgfile)
|
|
if err != nil || !ok {
|
|
return nil, fmt.Errorf("%+v %t", err, ok)
|
|
}
|
|
|
|
blob, err := pkg_model.GetBlobByID(ctx, pkgfile.BlobID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if strings.HasSuffix(file, ".pkg.tar.zst") {
|
|
err = pkg_model.IncrementDownloadCounter(ctx, pkgfile.VersionID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
cs := packages.NewContentStore()
|
|
|
|
return cs.Get(packages.BlobHash256Key(blob.HashSHA256))
|
|
}
|
|
|
|
// Automatically connect repository to pushed package, if package with provided
|
|
// with provided name exists in namespace scope.
|
|
func RepositoryAutoconnect(ctx *context.Context, owner, repository string, pkgid int64) error {
|
|
repo, err := repo.GetRepositoryByOwnerAndName(ctx, owner, repository)
|
|
if err == nil {
|
|
err = pkg_model.SetRepositoryLink(ctx, pkgid, repo.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// This function is collecting information about packages in some organization/
|
|
// user space, and created pacman database archive based on package metadata.
|
|
func CreatePacmanDb(ctx *context.Context, owner, architecture, distro string) ([]byte, error) {
|
|
u, err := user.GetUserByName(ctx, owner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pkgs, err := pkg_model.GetPackagesByType(ctx, u.ID, pkg_model.TypeArch)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var mds []*arch.Metadata
|
|
|
|
for _, pkg := range pkgs {
|
|
versions, err := pkg_model.GetVersionsByPackageName(ctx, u.ID, pkg_model.TypeArch, pkg.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sort.Slice(versions, func(i, j int) bool {
|
|
return versions[i].CreatedUnix > versions[j].CreatedUnix
|
|
})
|
|
|
|
for _, version := range versions {
|
|
var md arch.Metadata
|
|
err = json.Unmarshal([]byte(version.MetadataJSON), &md)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if checkPackageCompatability(distro, architecture, md.DistroArch) {
|
|
mds = append(mds, &md)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return arch.CreatePacmanDb(mds)
|
|
}
|
|
|
|
// Remove specific package version related to provided user or organization.
|
|
func RemovePackage(ctx *context.Context, u *user.User, name, version string) error {
|
|
ver, err := pkg_model.GetVersionByNameAndVersion(ctx, u.ID, pkg_model.TypeArch, name, version)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return pkg_service.RemovePackageVersion(u, ver)
|
|
}
|
|
|
|
// This function will check, wether package should be added to resulting database.
|
|
func checkPackageCompatability(distro, arch string, distroarchs []string) bool {
|
|
for _, distroarch := range distroarchs {
|
|
if distroarch == distro+"-any" {
|
|
return true
|
|
}
|
|
if distroarch == distro+"-"+arch {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|