summaryrefslogtreecommitdiffstats
path: root/models/packages/conan/references.go
blob: 0d888a1ec88cb59d2e5f79324358af20298a24f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package conan

import (
	"context"
	"strconv"
	"strings"

	"code.gitea.io/gitea/models/db"
	"code.gitea.io/gitea/models/packages"
	conan_module "code.gitea.io/gitea/modules/packages/conan"
	"code.gitea.io/gitea/modules/timeutil"
	"code.gitea.io/gitea/modules/util"

	"xorm.io/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
}