aboutsummaryrefslogtreecommitdiffstats
path: root/models/packages/debian/search.go
blob: 332a4f7040c51812e95fdbb65c5d3f2621efff0c (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
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package debian

import (
	"context"
	"strconv"

	"code.gitea.io/gitea/models/db"
	"code.gitea.io/gitea/models/packages"
	debian_module "code.gitea.io/gitea/modules/packages/debian"

	"xorm.io/builder"
)

type PackageSearchOptions struct {
	OwnerID      int64
	Distribution string
	Component    string
	Architecture string
}

// SearchLatestPackages gets the latest packages matching the search options
func SearchLatestPackages(ctx context.Context, opts *PackageSearchOptions) ([]*packages.PackageFileDescriptor, error) {
	var cond builder.Cond = builder.Eq{
		"package_file.is_lead":        true,
		"package.type":                packages.TypeDebian,
		"package.owner_id":            opts.OwnerID,
		"package.is_internal":         false,
		"package_version.is_internal": false,
	}

	props := make(map[string]string)
	if opts.Distribution != "" {
		props[debian_module.PropertyDistribution] = opts.Distribution
	}
	if opts.Component != "" {
		props[debian_module.PropertyComponent] = opts.Component
	}
	if opts.Architecture != "" {
		props[debian_module.PropertyArchitecture] = opts.Architecture
	}

	if len(props) > 0 {
		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 props {
			propsCondBlock = propsCondBlock.Or(builder.Eq{
				"package_property.name":  name,
				"package_property.value": value,
			})
		}
		propsCond = propsCond.And(propsCondBlock)

		cond = cond.And(builder.Eq{
			strconv.Itoa(len(props)): builder.Select("COUNT(*)").Where(propsCond).From("package_property"),
		})
	}

	cond = cond.
		And(builder.Expr("pv2.id IS NULL"))

	joinCond := builder.
		Expr("package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))").
		And(builder.Eq{"pv2.is_internal": false})

	pfs := make([]*packages.PackageFile, 0, 10)
	err := db.GetEngine(ctx).
		Table("package_file").
		Select("package_file.*").
		Join("INNER", "package_version", "package_version.id = package_file.version_id").
		Join("LEFT", "package_version pv2", joinCond).
		Join("INNER", "package", "package.id = package_version.package_id").
		Where(cond).
		Desc("package_version.created_unix").
		Find(&pfs)
	if err != nil {
		return nil, err
	}

	return packages.GetPackageFileDescriptors(ctx, pfs)
}

// GetDistributions gets all available distributions
func GetDistributions(ctx context.Context, ownerID int64) ([]string, error) {
	return getDistinctPropertyValues(ctx, ownerID, "", debian_module.PropertyDistribution)
}

// GetComponents gets all available components for the given distribution
func GetComponents(ctx context.Context, ownerID int64, distribution string) ([]string, error) {
	return getDistinctPropertyValues(ctx, ownerID, distribution, debian_module.PropertyComponent)
}

// GetArchitectures gets all available architectures for the given distribution
func GetArchitectures(ctx context.Context, ownerID int64, distribution string) ([]string, error) {
	return getDistinctPropertyValues(ctx, ownerID, distribution, debian_module.PropertyArchitecture)
}

func getDistinctPropertyValues(ctx context.Context, ownerID int64, distribution, propName string) ([]string, error) {
	var cond builder.Cond = builder.Eq{
		"package_property.ref_type": packages.PropertyTypeFile,
		"package_property.name":     propName,
		"package.type":              packages.TypeDebian,
		"package.owner_id":          ownerID,
	}
	if distribution != "" {
		innerCond := builder.
			Expr("pp.ref_id = package_property.ref_id").
			And(builder.Eq{
				"pp.ref_type": packages.PropertyTypeFile,
				"pp.name":     debian_module.PropertyDistribution,
				"pp.value":    distribution,
			})
		cond = cond.And(builder.Exists(builder.Select("pp.ref_id").From("package_property pp").Where(innerCond)))
	}

	values := make([]string, 0, 5)
	return values, db.GetEngine(ctx).
		Table("package_property").
		Distinct("package_property.value").
		Join("INNER", "package_file", "package_file.id = package_property.ref_id").
		Join("INNER", "package_version", "package_version.id = package_file.version_id").
		Join("INNER", "package", "package.id = package_version.package_id").
		Where(cond).
		Find(&values)
}