code.gitea.io/gitea@v1.22.3/models/packages/package.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package packages
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"strings"
    10  
    11  	"code.gitea.io/gitea/models/db"
    12  	"code.gitea.io/gitea/modules/util"
    13  
    14  	"xorm.io/builder"
    15  )
    16  
    17  func init() {
    18  	db.RegisterModel(new(Package))
    19  }
    20  
    21  var (
    22  	// ErrDuplicatePackage indicates a duplicated package error
    23  	ErrDuplicatePackage = util.NewAlreadyExistErrorf("package already exists")
    24  	// ErrPackageNotExist indicates a package not exist error
    25  	ErrPackageNotExist = util.NewNotExistErrorf("package does not exist")
    26  )
    27  
    28  // Type of a package
    29  type Type string
    30  
    31  // List of supported packages
    32  const (
    33  	TypeAlpine    Type = "alpine"
    34  	TypeCargo     Type = "cargo"
    35  	TypeChef      Type = "chef"
    36  	TypeComposer  Type = "composer"
    37  	TypeConan     Type = "conan"
    38  	TypeConda     Type = "conda"
    39  	TypeContainer Type = "container"
    40  	TypeCran      Type = "cran"
    41  	TypeDebian    Type = "debian"
    42  	TypeGeneric   Type = "generic"
    43  	TypeGo        Type = "go"
    44  	TypeHelm      Type = "helm"
    45  	TypeMaven     Type = "maven"
    46  	TypeNpm       Type = "npm"
    47  	TypeNuGet     Type = "nuget"
    48  	TypePub       Type = "pub"
    49  	TypePyPI      Type = "pypi"
    50  	TypeRpm       Type = "rpm"
    51  	TypeRubyGems  Type = "rubygems"
    52  	TypeSwift     Type = "swift"
    53  	TypeVagrant   Type = "vagrant"
    54  )
    55  
    56  var TypeList = []Type{
    57  	TypeAlpine,
    58  	TypeCargo,
    59  	TypeChef,
    60  	TypeComposer,
    61  	TypeConan,
    62  	TypeConda,
    63  	TypeContainer,
    64  	TypeCran,
    65  	TypeDebian,
    66  	TypeGeneric,
    67  	TypeGo,
    68  	TypeHelm,
    69  	TypeMaven,
    70  	TypeNpm,
    71  	TypeNuGet,
    72  	TypePub,
    73  	TypePyPI,
    74  	TypeRpm,
    75  	TypeRubyGems,
    76  	TypeSwift,
    77  	TypeVagrant,
    78  }
    79  
    80  // Name gets the name of the package type
    81  func (pt Type) Name() string {
    82  	switch pt {
    83  	case TypeAlpine:
    84  		return "Alpine"
    85  	case TypeCargo:
    86  		return "Cargo"
    87  	case TypeChef:
    88  		return "Chef"
    89  	case TypeComposer:
    90  		return "Composer"
    91  	case TypeConan:
    92  		return "Conan"
    93  	case TypeConda:
    94  		return "Conda"
    95  	case TypeContainer:
    96  		return "Container"
    97  	case TypeCran:
    98  		return "CRAN"
    99  	case TypeDebian:
   100  		return "Debian"
   101  	case TypeGeneric:
   102  		return "Generic"
   103  	case TypeGo:
   104  		return "Go"
   105  	case TypeHelm:
   106  		return "Helm"
   107  	case TypeMaven:
   108  		return "Maven"
   109  	case TypeNpm:
   110  		return "npm"
   111  	case TypeNuGet:
   112  		return "NuGet"
   113  	case TypePub:
   114  		return "Pub"
   115  	case TypePyPI:
   116  		return "PyPI"
   117  	case TypeRpm:
   118  		return "RPM"
   119  	case TypeRubyGems:
   120  		return "RubyGems"
   121  	case TypeSwift:
   122  		return "Swift"
   123  	case TypeVagrant:
   124  		return "Vagrant"
   125  	}
   126  	panic(fmt.Sprintf("unknown package type: %s", string(pt)))
   127  }
   128  
   129  // SVGName gets the name of the package type svg image
   130  func (pt Type) SVGName() string {
   131  	switch pt {
   132  	case TypeAlpine:
   133  		return "gitea-alpine"
   134  	case TypeCargo:
   135  		return "gitea-cargo"
   136  	case TypeChef:
   137  		return "gitea-chef"
   138  	case TypeComposer:
   139  		return "gitea-composer"
   140  	case TypeConan:
   141  		return "gitea-conan"
   142  	case TypeConda:
   143  		return "gitea-conda"
   144  	case TypeContainer:
   145  		return "octicon-container"
   146  	case TypeCran:
   147  		return "gitea-cran"
   148  	case TypeDebian:
   149  		return "gitea-debian"
   150  	case TypeGeneric:
   151  		return "octicon-package"
   152  	case TypeGo:
   153  		return "gitea-go"
   154  	case TypeHelm:
   155  		return "gitea-helm"
   156  	case TypeMaven:
   157  		return "gitea-maven"
   158  	case TypeNpm:
   159  		return "gitea-npm"
   160  	case TypeNuGet:
   161  		return "gitea-nuget"
   162  	case TypePub:
   163  		return "gitea-pub"
   164  	case TypePyPI:
   165  		return "gitea-python"
   166  	case TypeRpm:
   167  		return "gitea-rpm"
   168  	case TypeRubyGems:
   169  		return "gitea-rubygems"
   170  	case TypeSwift:
   171  		return "gitea-swift"
   172  	case TypeVagrant:
   173  		return "gitea-vagrant"
   174  	}
   175  	panic(fmt.Sprintf("unknown package type: %s", string(pt)))
   176  }
   177  
   178  // Package represents a package
   179  type Package struct {
   180  	ID               int64  `xorm:"pk autoincr"`
   181  	OwnerID          int64  `xorm:"UNIQUE(s) INDEX NOT NULL"`
   182  	RepoID           int64  `xorm:"INDEX"`
   183  	Type             Type   `xorm:"UNIQUE(s) INDEX NOT NULL"`
   184  	Name             string `xorm:"NOT NULL"`
   185  	LowerName        string `xorm:"UNIQUE(s) INDEX NOT NULL"`
   186  	SemverCompatible bool   `xorm:"NOT NULL DEFAULT false"`
   187  	IsInternal       bool   `xorm:"NOT NULL DEFAULT false"`
   188  }
   189  
   190  // TryInsertPackage inserts a package. If a package exists already, ErrDuplicatePackage is returned
   191  func TryInsertPackage(ctx context.Context, p *Package) (*Package, error) {
   192  	e := db.GetEngine(ctx)
   193  
   194  	existing := &Package{}
   195  
   196  	has, err := e.Where(builder.Eq{
   197  		"owner_id":   p.OwnerID,
   198  		"type":       p.Type,
   199  		"lower_name": p.LowerName,
   200  	}).Get(existing)
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  	if has {
   205  		return existing, ErrDuplicatePackage
   206  	}
   207  	if _, err = e.Insert(p); err != nil {
   208  		return nil, err
   209  	}
   210  	return p, nil
   211  }
   212  
   213  // DeletePackageByID deletes a package by id
   214  func DeletePackageByID(ctx context.Context, packageID int64) error {
   215  	_, err := db.GetEngine(ctx).ID(packageID).Delete(&Package{})
   216  	return err
   217  }
   218  
   219  // SetRepositoryLink sets the linked repository
   220  func SetRepositoryLink(ctx context.Context, packageID, repoID int64) error {
   221  	_, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: repoID})
   222  	return err
   223  }
   224  
   225  // UnlinkRepositoryFromAllPackages unlinks every package from the repository
   226  func UnlinkRepositoryFromAllPackages(ctx context.Context, repoID int64) error {
   227  	_, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Cols("repo_id").Update(&Package{})
   228  	return err
   229  }
   230  
   231  // GetPackageByID gets a package by id
   232  func GetPackageByID(ctx context.Context, packageID int64) (*Package, error) {
   233  	p := &Package{}
   234  
   235  	has, err := db.GetEngine(ctx).ID(packageID).Get(p)
   236  	if err != nil {
   237  		return nil, err
   238  	}
   239  	if !has {
   240  		return nil, ErrPackageNotExist
   241  	}
   242  	return p, nil
   243  }
   244  
   245  // GetPackageByName gets a package by name
   246  func GetPackageByName(ctx context.Context, ownerID int64, packageType Type, name string) (*Package, error) {
   247  	var cond builder.Cond = builder.Eq{
   248  		"package.owner_id":    ownerID,
   249  		"package.type":        packageType,
   250  		"package.lower_name":  strings.ToLower(name),
   251  		"package.is_internal": false,
   252  	}
   253  
   254  	p := &Package{}
   255  
   256  	has, err := db.GetEngine(ctx).
   257  		Where(cond).
   258  		Get(p)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  	if !has {
   263  		return nil, ErrPackageNotExist
   264  	}
   265  	return p, nil
   266  }
   267  
   268  // GetPackagesByType gets all packages of a specific type
   269  func GetPackagesByType(ctx context.Context, ownerID int64, packageType Type) ([]*Package, error) {
   270  	var cond builder.Cond = builder.Eq{
   271  		"package.owner_id":    ownerID,
   272  		"package.type":        packageType,
   273  		"package.is_internal": false,
   274  	}
   275  
   276  	ps := make([]*Package, 0, 10)
   277  	return ps, db.GetEngine(ctx).
   278  		Where(cond).
   279  		Find(&ps)
   280  }
   281  
   282  // FindUnreferencedPackages gets all packages without associated versions
   283  func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) {
   284  	in := builder.
   285  		Select("package.id").
   286  		From("package").
   287  		LeftJoin("package_version", "package_version.package_id = package.id").
   288  		Where(builder.Expr("package_version.id IS NULL"))
   289  
   290  	ps := make([]*Package, 0, 10)
   291  	return ps, db.GetEngine(ctx).
   292  		// double select workaround for MySQL
   293  		// https://stackoverflow.com/questions/4471277/mysql-delete-from-with-subquery-as-condition
   294  		Where(builder.In("package.id", builder.Select("id").From(in, "temp"))).
   295  		Find(&ps)
   296  }
   297  
   298  // HasOwnerPackages tests if a user/org has accessible packages
   299  func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) {
   300  	return db.GetEngine(ctx).
   301  		Table("package_version").
   302  		Join("INNER", "package", "package.id = package_version.package_id").
   303  		Where(builder.Eq{
   304  			"package_version.is_internal": false,
   305  			"package.owner_id":            ownerID,
   306  		}).
   307  		Exist(&PackageVersion{})
   308  }
   309  
   310  // HasRepositoryPackages tests if a repository has packages
   311  func HasRepositoryPackages(ctx context.Context, repositoryID int64) (bool, error) {
   312  	return db.GetEngine(ctx).Where("repo_id = ?", repositoryID).Exist(&Package{})
   313  }