|
|
|
@ -12,16 +12,13 @@ import ( |
|
|
|
|
|
|
|
|
|
"code.gitea.io/gitea/models/db" |
|
|
|
|
"code.gitea.io/gitea/modules/timeutil" |
|
|
|
|
"code.gitea.io/gitea/modules/util" |
|
|
|
|
|
|
|
|
|
"xorm.io/builder" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
// ErrDuplicatePackageVersion indicates a duplicated package version error
|
|
|
|
|
ErrDuplicatePackageVersion = errors.New("Package version does exist already") |
|
|
|
|
// ErrPackageVersionNotExist indicates a package version not exist error
|
|
|
|
|
ErrPackageVersionNotExist = errors.New("Package version does not exist") |
|
|
|
|
) |
|
|
|
|
// ErrDuplicatePackageVersion indicates a duplicated package version error
|
|
|
|
|
var ErrDuplicatePackageVersion = errors.New("Package version already exists") |
|
|
|
|
|
|
|
|
|
func init() { |
|
|
|
|
db.RegisterModel(new(PackageVersion)) |
|
|
|
@ -99,75 +96,49 @@ func GetInternalVersionByNameAndVersion(ctx context.Context, ownerID int64, pack |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func getVersionByNameAndVersion(ctx context.Context, ownerID int64, packageType Type, name, version string, isInternal bool) (*PackageVersion, error) { |
|
|
|
|
var cond builder.Cond = builder.Eq{ |
|
|
|
|
"package.owner_id": ownerID, |
|
|
|
|
"package.type": packageType, |
|
|
|
|
"package.lower_name": strings.ToLower(name), |
|
|
|
|
"package_version.is_internal": isInternal, |
|
|
|
|
} |
|
|
|
|
pv := &PackageVersion{ |
|
|
|
|
LowerVersion: strings.ToLower(version), |
|
|
|
|
} |
|
|
|
|
has, err := db.GetEngine(ctx). |
|
|
|
|
Join("INNER", "package", "package.id = package_version.package_id"). |
|
|
|
|
Where(cond). |
|
|
|
|
Get(pv) |
|
|
|
|
pvs, _, err := SearchVersions(ctx, &PackageSearchOptions{ |
|
|
|
|
OwnerID: ownerID, |
|
|
|
|
Type: packageType, |
|
|
|
|
Name: SearchValue{ |
|
|
|
|
ExactMatch: true, |
|
|
|
|
Value: name, |
|
|
|
|
}, |
|
|
|
|
Version: SearchValue{ |
|
|
|
|
ExactMatch: true, |
|
|
|
|
Value: version, |
|
|
|
|
}, |
|
|
|
|
IsInternal: isInternal, |
|
|
|
|
Paginator: db.NewAbsoluteListOptions(0, 1), |
|
|
|
|
}) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
if !has { |
|
|
|
|
if len(pvs) == 0 { |
|
|
|
|
return nil, ErrPackageNotExist |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return pv, nil |
|
|
|
|
return pvs[0], nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// GetVersionsByPackageType gets all versions of a specific type
|
|
|
|
|
func GetVersionsByPackageType(ctx context.Context, ownerID int64, packageType Type) ([]*PackageVersion, error) { |
|
|
|
|
var cond builder.Cond = builder.Eq{ |
|
|
|
|
"package.owner_id": ownerID, |
|
|
|
|
"package.type": packageType, |
|
|
|
|
"package_version.is_internal": false, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pvs := make([]*PackageVersion, 0, 10) |
|
|
|
|
return pvs, db.GetEngine(ctx). |
|
|
|
|
Where(cond). |
|
|
|
|
Join("INNER", "package", "package.id = package_version.package_id"). |
|
|
|
|
Find(&pvs) |
|
|
|
|
pvs, _, err := SearchVersions(ctx, &PackageSearchOptions{ |
|
|
|
|
OwnerID: ownerID, |
|
|
|
|
Type: packageType, |
|
|
|
|
}) |
|
|
|
|
return pvs, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// GetVersionsByPackageName gets all versions of a specific package
|
|
|
|
|
func GetVersionsByPackageName(ctx context.Context, ownerID int64, packageType Type, name string) ([]*PackageVersion, error) { |
|
|
|
|
var cond builder.Cond = builder.Eq{ |
|
|
|
|
"package.owner_id": ownerID, |
|
|
|
|
"package.type": packageType, |
|
|
|
|
"package.lower_name": strings.ToLower(name), |
|
|
|
|
"package_version.is_internal": false, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pvs := make([]*PackageVersion, 0, 10) |
|
|
|
|
return pvs, db.GetEngine(ctx). |
|
|
|
|
Where(cond). |
|
|
|
|
Join("INNER", "package", "package.id = package_version.package_id"). |
|
|
|
|
Find(&pvs) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// GetVersionsByFilename gets all versions which are linked to a filename
|
|
|
|
|
func GetVersionsByFilename(ctx context.Context, ownerID int64, packageType Type, filename string) ([]*PackageVersion, error) { |
|
|
|
|
var cond builder.Cond = builder.Eq{ |
|
|
|
|
"package.owner_id": ownerID, |
|
|
|
|
"package.type": packageType, |
|
|
|
|
"package_file.lower_name": strings.ToLower(filename), |
|
|
|
|
"package_version.is_internal": false, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pvs := make([]*PackageVersion, 0, 10) |
|
|
|
|
return pvs, db.GetEngine(ctx). |
|
|
|
|
Where(cond). |
|
|
|
|
Join("INNER", "package_file", "package_file.version_id = package_version.id"). |
|
|
|
|
Join("INNER", "package", "package.id = package_version.package_id"). |
|
|
|
|
Find(&pvs) |
|
|
|
|
pvs, _, err := SearchVersions(ctx, &PackageSearchOptions{ |
|
|
|
|
OwnerID: ownerID, |
|
|
|
|
Type: packageType, |
|
|
|
|
Name: SearchValue{ |
|
|
|
|
ExactMatch: true, |
|
|
|
|
Value: name, |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
return pvs, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// DeleteVersionByID deletes a version by id
|
|
|
|
@ -183,21 +154,32 @@ func HasVersionFileReferences(ctx context.Context, versionID int64) (bool, error |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// SearchValue describes a value to search
|
|
|
|
|
// If ExactMatch is true, the field must match the value otherwise a LIKE search is performed.
|
|
|
|
|
type SearchValue struct { |
|
|
|
|
Value string |
|
|
|
|
ExactMatch bool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// PackageSearchOptions are options for SearchXXX methods
|
|
|
|
|
// Besides IsInternal are all fields optional and are not used if they have their default value (nil, "", 0)
|
|
|
|
|
type PackageSearchOptions struct { |
|
|
|
|
OwnerID int64 |
|
|
|
|
RepoID int64 |
|
|
|
|
Type string |
|
|
|
|
PackageID int64 |
|
|
|
|
QueryName string |
|
|
|
|
QueryVersion string |
|
|
|
|
Properties map[string]string |
|
|
|
|
Sort string |
|
|
|
|
OwnerID int64 |
|
|
|
|
RepoID int64 |
|
|
|
|
Type Type |
|
|
|
|
PackageID int64 |
|
|
|
|
Name SearchValue // only results with the specific name are found
|
|
|
|
|
Version SearchValue // only results with the specific version are found
|
|
|
|
|
Properties map[string]string // only results are found which contain all listed version properties with the specific value
|
|
|
|
|
IsInternal bool |
|
|
|
|
HasFileWithName string // only results are found which are associated with a file with the specific name
|
|
|
|
|
HasFiles util.OptionalBool // only results are found which have associated files
|
|
|
|
|
Sort string |
|
|
|
|
db.Paginator |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (opts *PackageSearchOptions) toConds() builder.Cond { |
|
|
|
|
var cond builder.Cond = builder.Eq{"package_version.is_internal": false} |
|
|
|
|
var cond builder.Cond = builder.Eq{"package_version.is_internal": opts.IsInternal} |
|
|
|
|
|
|
|
|
|
if opts.OwnerID != 0 { |
|
|
|
|
cond = cond.And(builder.Eq{"package.owner_id": opts.OwnerID}) |
|
|
|
@ -211,11 +193,19 @@ func (opts *PackageSearchOptions) toConds() builder.Cond { |
|
|
|
|
if opts.PackageID != 0 { |
|
|
|
|
cond = cond.And(builder.Eq{"package.id": opts.PackageID}) |
|
|
|
|
} |
|
|
|
|
if opts.QueryName != "" { |
|
|
|
|
cond = cond.And(builder.Like{"package.lower_name", strings.ToLower(opts.QueryName)}) |
|
|
|
|
if opts.Name.Value != "" { |
|
|
|
|
if opts.Name.ExactMatch { |
|
|
|
|
cond = cond.And(builder.Eq{"package.lower_name": strings.ToLower(opts.Name.Value)}) |
|
|
|
|
} else { |
|
|
|
|
cond = cond.And(builder.Like{"package.lower_name", strings.ToLower(opts.Name.Value)}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if opts.QueryVersion != "" { |
|
|
|
|
cond = cond.And(builder.Like{"package_version.lower_version", strings.ToLower(opts.QueryVersion)}) |
|
|
|
|
if opts.Version.Value != "" { |
|
|
|
|
if opts.Version.ExactMatch { |
|
|
|
|
cond = cond.And(builder.Eq{"package_version.lower_version": strings.ToLower(opts.Version.Value)}) |
|
|
|
|
} else { |
|
|
|
|
cond = cond.And(builder.Like{"package_version.lower_version", strings.ToLower(opts.Version.Value)}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(opts.Properties) != 0 { |
|
|
|
@ -238,6 +228,22 @@ func (opts *PackageSearchOptions) toConds() builder.Cond { |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if opts.HasFileWithName != "" { |
|
|
|
|
fileCond := builder.Expr("package_file.version_id = package_version.id").And(builder.Eq{"package_file.lower_name": strings.ToLower(opts.HasFileWithName)}) |
|
|
|
|
|
|
|
|
|
cond = cond.And(builder.Exists(builder.Select("package_file.id").From("package_file").Where(fileCond))) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !opts.HasFiles.IsNone() { |
|
|
|
|
var filesCond builder.Cond = builder.Exists(builder.Select("package_file.id").From("package_file").Where(builder.Expr("package_file.version_id = package_version.id"))) |
|
|
|
|
|
|
|
|
|
if opts.HasFiles.IsFalse() { |
|
|
|
|
filesCond = builder.Not{filesCond} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cond = cond.And(filesCond) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return cond |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -297,20 +303,3 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P |
|
|
|
|
count, err := sess.FindAndCount(&pvs) |
|
|
|
|
return pvs, count, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// FindVersionsByPropertyNameAndValue gets all package versions which are associated with a specific property + value
|
|
|
|
|
func FindVersionsByPropertyNameAndValue(ctx context.Context, packageID int64, name, value string) ([]*PackageVersion, error) { |
|
|
|
|
var cond builder.Cond = builder.Eq{ |
|
|
|
|
"package_property.ref_type": PropertyTypeVersion, |
|
|
|
|
"package_property.name": name, |
|
|
|
|
"package_property.value": value, |
|
|
|
|
"package_version.package_id": packageID, |
|
|
|
|
"package_version.is_internal": false, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pvs := make([]*PackageVersion, 0, 5) |
|
|
|
|
return pvs, db.GetEngine(ctx). |
|
|
|
|
Where(cond). |
|
|
|
|
Join("INNER", "package_property", "package_property.ref_id = package_version.id"). |
|
|
|
|
Find(&pvs) |
|
|
|
|
} |
|
|
|
|