362 lines · 8.6 KB · Go
RawDownload
// Copyright 2021 The Gitea Authors. All rights reserved.// Copyright 2024 The Forgejo Authors. All rights reserved.// SPDX-License-Identifier: MIT package packages import (	"context"	"fmt"	"strings" 	"forgejo.org/models/db"	"forgejo.org/modules/util" 	"xorm.io/builder"	"xorm.io/xorm") func init() {	db.RegisterModel(new(Package))} var (	// ErrDuplicatePackage indicates a duplicated package error	ErrDuplicatePackage = util.NewAlreadyExistErrorf("package already exists")	// ErrPackageNotExist indicates a package not exist error	ErrPackageNotExist = util.NewNotExistErrorf("package does not exist")) // Type of a packagetype Type string // List of supported packagesconst (	TypeAlpine    Type = "alpine"	TypeArch      Type = "arch"	TypeCargo     Type = "cargo"	TypeChef      Type = "chef"	TypeComposer  Type = "composer"	TypeConan     Type = "conan"	TypeConda     Type = "conda"	TypeContainer Type = "container"	TypeCran      Type = "cran"	TypeDebian    Type = "debian"	TypeGeneric   Type = "generic"	TypeGo        Type = "go"	TypeHelm      Type = "helm"	TypeMaven     Type = "maven"	TypeNpm       Type = "npm"	TypeNuGet     Type = "nuget"	TypePub       Type = "pub"	TypePyPI      Type = "pypi"	TypeRpm       Type = "rpm"	TypeAlt       Type = "alt"	TypeRubyGems  Type = "rubygems"	TypeSwift     Type = "swift"	TypeVagrant   Type = "vagrant") var TypeList = []Type{	TypeAlpine,	TypeArch,	TypeCargo,	TypeChef,	TypeComposer,	TypeConan,	TypeConda,	TypeContainer,	TypeCran,	TypeDebian,	TypeGeneric,	TypeGo,	TypeHelm,	TypeMaven,	TypeNpm,	TypeNuGet,	TypePub,	TypePyPI,	TypeRpm,	TypeAlt,	TypeRubyGems,	TypeSwift,	TypeVagrant,} // Name gets the name of the package typefunc (pt Type) Name() string {	switch pt {	case TypeAlpine:		return "Alpine"	case TypeArch:		return "Arch"	case TypeCargo:		return "Cargo"	case TypeChef:		return "Chef"	case TypeComposer:		return "Composer"	case TypeConan:		return "Conan"	case TypeConda:		return "Conda"	case TypeContainer:		return "Container"	case TypeCran:		return "CRAN"	case TypeDebian:		return "Debian"	case TypeGeneric:		return "Generic"	case TypeGo:		return "Go"	case TypeHelm:		return "Helm"	case TypeMaven:		return "Maven"	case TypeNpm:		return "npm"	case TypeNuGet:		return "NuGet"	case TypePub:		return "Pub"	case TypePyPI:		return "PyPI"	case TypeRpm:		return "RPM"	case TypeAlt:		return "Alt"	case TypeRubyGems:		return "RubyGems"	case TypeSwift:		return "Swift"	case TypeVagrant:		return "Vagrant"	}	panic(fmt.Sprintf("unknown package type: %s", string(pt)))} // SVGName gets the name of the package type svg imagefunc (pt Type) SVGName() string {	switch pt {	case TypeAlpine:		return "gitea-alpine"	case TypeArch:		return "gitea-arch"	case TypeCargo:		return "gitea-cargo"	case TypeChef:		return "gitea-chef"	case TypeComposer:		return "gitea-composer"	case TypeConan:		return "gitea-conan"	case TypeConda:		return "gitea-conda"	case TypeContainer:		return "octicon-container"	case TypeCran:		return "gitea-cran"	case TypeDebian:		return "gitea-debian"	case TypeGeneric:		return "octicon-package"	case TypeGo:		return "gitea-go"	case TypeHelm:		return "gitea-helm"	case TypeMaven:		return "gitea-maven"	case TypeNpm:		return "gitea-npm"	case TypeNuGet:		return "gitea-nuget"	case TypePub:		return "gitea-pub"	case TypePyPI:		return "gitea-python"	case TypeRpm:		return "gitea-rpm"	case TypeAlt:		return "gitea-alt"	case TypeRubyGems:		return "gitea-rubygems"	case TypeSwift:		return "gitea-swift"	case TypeVagrant:		return "gitea-vagrant"	}	panic(fmt.Sprintf("unknown package type: %s", string(pt)))} // Package represents a packagetype Package struct {	ID               int64  `xorm:"pk autoincr"`	OwnerID          int64  `xorm:"UNIQUE(s) INDEX NOT NULL"`	RepoID           int64  `xorm:"INDEX"`	Type             Type   `xorm:"UNIQUE(s) INDEX NOT NULL"`	Name             string `xorm:"NOT NULL"`	LowerName        string `xorm:"UNIQUE(s) INDEX NOT NULL"`	SemverCompatible bool   `xorm:"NOT NULL DEFAULT false"`	IsInternal       bool   `xorm:"NOT NULL DEFAULT false"`} // TryInsertPackage inserts a package. If a package exists already, ErrDuplicatePackage is returnedfunc TryInsertPackage(ctx context.Context, p *Package) (*Package, error) {	e := db.GetEngine(ctx) 	existing := &Package{} 	has, err := e.Where(builder.Eq{		"owner_id":   p.OwnerID,		"type":       p.Type,		"lower_name": p.LowerName,	}).Get(existing)	if err != nil {		return nil, err	}	if has {		return existing, ErrDuplicatePackage	}	if _, err = e.Insert(p); err != nil {		return nil, err	}	return p, nil} // DeletePackageByID deletes a package by idfunc DeletePackageByID(ctx context.Context, packageID int64) error {	n, err := db.GetEngine(ctx).ID(packageID).Delete(&Package{})	if n == 0 && err == nil {		return ErrPackageNotExist	}	return err} // SetRepositoryLink sets the linked repositoryfunc SetRepositoryLink(ctx context.Context, packageID, repoID int64) error {	n, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: repoID})	if n == 0 && err == nil {		return ErrPackageNotExist	}	return err} func UnlinkRepository(ctx context.Context, packageID int64) error {	_, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: 0})	return err} // UnlinkRepositoryFromAllPackages unlinks every package from the repositoryfunc UnlinkRepositoryFromAllPackages(ctx context.Context, repoID int64) error {	_, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Cols("repo_id").Update(&Package{})	return err} // GetPackageByID gets a package by idfunc GetPackageByID(ctx context.Context, packageID int64) (*Package, error) {	p := &Package{} 	has, err := db.GetEngine(ctx).ID(packageID).Get(p)	if err != nil {		return nil, err	}	if !has {		return nil, ErrPackageNotExist	}	return p, nil} // GetPackageByName gets a package by namefunc GetPackageByName(ctx context.Context, ownerID int64, packageType Type, name string) (*Package, error) {	var cond builder.Cond = builder.Eq{		"package.owner_id":    ownerID,		"package.type":        packageType,		"package.lower_name":  strings.ToLower(name),		"package.is_internal": false,	} 	p := &Package{} 	has, err := db.GetEngine(ctx).		Where(cond).		Get(p)	if err != nil {		return nil, err	}	if !has {		return nil, ErrPackageNotExist	}	return p, nil} // GetPackagesByType gets all packages of a specific typefunc GetPackagesByType(ctx context.Context, ownerID int64, packageType Type) ([]*Package, error) {	var cond builder.Cond = builder.Eq{		"package.owner_id":    ownerID,		"package.type":        packageType,		"package.is_internal": false,	} 	ps := make([]*Package, 0, 10)	return ps, db.GetEngine(ctx).		Where(cond).		Find(&ps)} // FindUnreferencedPackages gets all packages without associated versionsfunc FindUnreferencedPackages(ctx context.Context) ([]int64, error) {	var pIDs []int64	if err := db.GetEngine(ctx).		Select("package.id").		Table("package").		Join("LEFT", "package_version", "package_version.package_id = package.id").		Where("package_version.id IS NULL").		Find(&pIDs); err != nil {		return nil, err	}	return pIDs, nil} func getPackages(ctx context.Context) *xorm.Session {	return db.GetEngine(ctx).		Table("package_version").		Join("INNER", "package", "package.id = package_version.package_id").		Where("package_version.is_internal = ?", false)} func getOwnerPackages(ctx context.Context, ownerID int64) *xorm.Session {	return getPackages(ctx).		Where("package.owner_id = ?", ownerID)} // HasOwnerPackages tests if a user/org has accessible packagesfunc HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) {	return getOwnerPackages(ctx, ownerID).		Exist(&Package{})} // CountOwnerPackages counts user/org accessible packagesfunc CountOwnerPackages(ctx context.Context, ownerID int64) (int64, error) {	return getOwnerPackages(ctx, ownerID).		Distinct("package.id").		Count(&Package{})} func getRepositoryPackages(ctx context.Context, repositoryID int64) *xorm.Session {	return getPackages(ctx).		Where("package.repo_id = ?", repositoryID)} // HasRepositoryPackages tests if a repository has packagesfunc HasRepositoryPackages(ctx context.Context, repositoryID int64) (bool, error) {	return getRepositoryPackages(ctx, repositoryID).		Exist(&PackageVersion{})} // CountRepositoryPackages counts packages of a repositoryfunc CountRepositoryPackages(ctx context.Context, repositoryID int64) (int64, error) {	return getRepositoryPackages(ctx, repositoryID).		Distinct("package.id").		Count(&Package{})}