mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
171 lines
5.0 KiB
Go
171 lines
5.0 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package conan
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/hanzoai/git/models/db"
|
|
"github.com/hanzoai/git/models/packages"
|
|
conan_module "github.com/hanzoai/git/modules/packages/conan"
|
|
"github.com/hanzoai/git/modules/timeutil"
|
|
"github.com/hanzoai/git/modules/util"
|
|
|
|
"github.com/hanzoai/builder"
|
|
)
|
|
|
|
var (
|
|
ErrRecipeReferenceNotExist = util.NewNotExistErrorf("recipe reference does not exist")
|
|
ErrPackageReferenceNotExist = util.NewNotExistErrorf("package reference does not exist")
|
|
)
|
|
|
|
// RecipeExists checks if a recipe exists
|
|
func RecipeExists(ctx context.Context, ownerID int64, ref *conan_module.RecipeReference) (bool, error) {
|
|
revisions, err := GetRecipeRevisions(ctx, ownerID, ref)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return len(revisions) != 0, nil
|
|
}
|
|
|
|
type PropertyValue struct {
|
|
Value string
|
|
CreatedUnix timeutil.TimeStamp
|
|
}
|
|
|
|
func findPropertyValues(ctx context.Context, propertyName string, ownerID int64, name, version string, propertyFilter map[string]string) ([]*PropertyValue, error) {
|
|
var propsCond builder.Cond = builder.Eq{
|
|
"package_property.ref_type": packages.PropertyTypeFile,
|
|
}
|
|
propsCond = propsCond.And(builder.Expr("package_property.ref_id = package_file.id"))
|
|
|
|
propsCondBlock := builder.NewCond()
|
|
for name, value := range propertyFilter {
|
|
propsCondBlock = propsCondBlock.Or(builder.Eq{
|
|
"package_property.name": name,
|
|
"package_property.value": value,
|
|
})
|
|
}
|
|
propsCond = propsCond.And(propsCondBlock)
|
|
|
|
var cond builder.Cond = builder.Eq{
|
|
"package.type": packages.TypeConan,
|
|
"package.owner_id": ownerID,
|
|
"package.lower_name": strings.ToLower(name),
|
|
"package_version.lower_version": strings.ToLower(version),
|
|
"package_version.is_internal": false,
|
|
strconv.Itoa(len(propertyFilter)): builder.Select("COUNT(*)").Where(propsCond).From("package_property"),
|
|
}
|
|
|
|
in2 := builder.
|
|
Select("package_file.id").
|
|
From("package_file").
|
|
InnerJoin("package_version", "package_version.id = package_file.version_id").
|
|
InnerJoin("package", "package.id = package_version.package_id").
|
|
Where(cond)
|
|
|
|
query := builder.
|
|
Select("package_property.value, MAX(package_file.created_unix) AS created_unix").
|
|
From("package_property").
|
|
InnerJoin("package_file", "package_file.id = package_property.ref_id").
|
|
Where(builder.Eq{"package_property.name": propertyName}.And(builder.In("package_property.ref_id", in2))).
|
|
GroupBy("package_property.value").
|
|
OrderBy("created_unix DESC")
|
|
|
|
var values []*PropertyValue
|
|
return values, db.GetEngine(ctx).SQL(query).Find(&values)
|
|
}
|
|
|
|
// GetRecipeRevisions gets all revisions of a recipe
|
|
func GetRecipeRevisions(ctx context.Context, ownerID int64, ref *conan_module.RecipeReference) ([]*PropertyValue, error) {
|
|
values, err := findPropertyValues(
|
|
ctx,
|
|
conan_module.PropertyRecipeRevision,
|
|
ownerID,
|
|
ref.Name,
|
|
ref.Version,
|
|
map[string]string{
|
|
conan_module.PropertyRecipeUser: ref.User,
|
|
conan_module.PropertyRecipeChannel: ref.Channel,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return values, nil
|
|
}
|
|
|
|
// GetLastRecipeRevision gets the latest recipe revision
|
|
func GetLastRecipeRevision(ctx context.Context, ownerID int64, ref *conan_module.RecipeReference) (*PropertyValue, error) {
|
|
revisions, err := GetRecipeRevisions(ctx, ownerID, ref)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(revisions) == 0 {
|
|
return nil, ErrRecipeReferenceNotExist
|
|
}
|
|
return revisions[0], nil
|
|
}
|
|
|
|
// GetPackageReferences gets all package references of a recipe
|
|
func GetPackageReferences(ctx context.Context, ownerID int64, ref *conan_module.RecipeReference) ([]*PropertyValue, error) {
|
|
values, err := findPropertyValues(
|
|
ctx,
|
|
conan_module.PropertyPackageReference,
|
|
ownerID,
|
|
ref.Name,
|
|
ref.Version,
|
|
map[string]string{
|
|
conan_module.PropertyRecipeUser: ref.User,
|
|
conan_module.PropertyRecipeChannel: ref.Channel,
|
|
conan_module.PropertyRecipeRevision: ref.Revision,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return values, nil
|
|
}
|
|
|
|
// GetPackageRevisions gets all revision of a package
|
|
func GetPackageRevisions(ctx context.Context, ownerID int64, ref *conan_module.PackageReference) ([]*PropertyValue, error) {
|
|
values, err := findPropertyValues(
|
|
ctx,
|
|
conan_module.PropertyPackageRevision,
|
|
ownerID,
|
|
ref.Recipe.Name,
|
|
ref.Recipe.Version,
|
|
map[string]string{
|
|
conan_module.PropertyRecipeUser: ref.Recipe.User,
|
|
conan_module.PropertyRecipeChannel: ref.Recipe.Channel,
|
|
conan_module.PropertyRecipeRevision: ref.Recipe.Revision,
|
|
conan_module.PropertyPackageReference: ref.Reference,
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return values, nil
|
|
}
|
|
|
|
// GetLastPackageRevision gets the latest package revision
|
|
func GetLastPackageRevision(ctx context.Context, ownerID int64, ref *conan_module.PackageReference) (*PropertyValue, error) {
|
|
revisions, err := GetPackageRevisions(ctx, ownerID, ref)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(revisions) == 0 {
|
|
return nil, ErrPackageReferenceNotExist
|
|
}
|
|
return revisions[0], nil
|
|
}
|