Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List all Debian package versions in Packages #27786

Merged
merged 11 commits into from
Oct 29, 2023
3 changes: 3 additions & 0 deletions models/packages/container/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ func (opts *ImageTagsSearchOptions) configureOrderBy(e db.Engine) {
default:
e.Desc("package_version.created_unix")
}

// Sort by id for stable order with duplicates in the other field
e.Asc("package_version.id")
}

// SearchImageTags gets a sorted list of the tags of an image
Expand Down
45 changes: 28 additions & 17 deletions models/packages/debian/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ type PackageSearchOptions struct {
Architecture string
}

// SearchLatestPackages gets the latest packages matching the search options
func SearchLatestPackages(ctx context.Context, opts *PackageSearchOptions) ([]*packages.PackageFileDescriptor, error) {
func (opts *PackageSearchOptions) toCond() builder.Cond {
var cond builder.Cond = builder.Eq{
"package_file.is_lead": true,
"package.type": packages.TypeDebian,
Expand Down Expand Up @@ -62,28 +61,40 @@ func SearchLatestPackages(ctx context.Context, opts *PackageSearchOptions) ([]*p
})
}

cond = cond.
And(builder.Expr("pv2.id IS NULL"))
KN4CK3R marked this conversation as resolved.
Show resolved Hide resolved
return cond
}

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})
// ExistPackages tests if there are packages matching the search options
func ExistPackages(ctx context.Context, opts *PackageSearchOptions) (bool, error) {
return db.GetEngine(ctx).
Table("package_file").
Join("INNER", "package_version", "package_version.id = package_file.version_id").
Join("INNER", "package", "package.id = package_version.package_id").
Where(opts.toCond()).
Exist(new(packages.PackageFile))
}

pfs := make([]*packages.PackageFile, 0, 10)
err := db.GetEngine(ctx).
// SearchPackages gets the packages matching the search options
func SearchPackages(ctx context.Context, opts *PackageSearchOptions, iter func(*packages.PackageFileDescriptor)) error {
return 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
}
Where(opts.toCond()).
Asc("package.lower_name", "package_version.created_unix").
delvh marked this conversation as resolved.
Show resolved Hide resolved
Iterate(new(packages.PackageFile), func(_ int, bean any) error {
pf := bean.(*packages.PackageFile)

pfd, err := packages.GetPackageFileDescriptor(ctx, pf)
if err != nil {
return err
}

return packages.GetPackageFileDescriptors(ctx, pfs)
iter(pfd)

return nil
})
}

// GetDistributions gets all available distributions
Expand Down
3 changes: 3 additions & 0 deletions models/packages/package_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ func (opts *PackageSearchOptions) configureOrderBy(e db.Engine) {
default:
e.Desc("package_version.created_unix")
}

// Sort by id for stable order with duplicates in the other field
e.Asc("package_version.id")
}

// SearchVersions gets all versions of packages matching the search options
Expand Down
15 changes: 8 additions & 7 deletions services/packages/debian/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,17 @@ func buildRepositoryFiles(ctx context.Context, ownerID int64, repoVersion *packa

// https://wiki.debian.org/DebianRepository/Format#A.22Packages.22_Indices
func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packages_model.PackageVersion, distribution, component, architecture string) error {
pfds, err := debian_model.SearchLatestPackages(ctx, &debian_model.PackageSearchOptions{
opts := &debian_model.PackageSearchOptions{
OwnerID: ownerID,
Distribution: distribution,
Component: component,
Architecture: architecture,
})
if err != nil {
return err
}

// Delete the package indices if there are no packages
if len(pfds) == 0 {
if has, err := debian_model.ExistPackages(ctx, opts); err != nil {
return err
} else if !has {
key := fmt.Sprintf("%s|%s|%s", distribution, component, architecture)
for _, filename := range []string{"Packages", "Packages.gz", "Packages.xz"} {
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, filename, key)
Expand Down Expand Up @@ -206,7 +205,7 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa
w := io.MultiWriter(packagesContent, gzw, xzw)

addSeparator := false
for _, pfd := range pfds {
if err := debian_model.SearchPackages(ctx, opts, func(pfd *packages_model.PackageFileDescriptor) {
if addSeparator {
fmt.Fprintln(w)
}
Expand All @@ -220,6 +219,8 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa
fmt.Fprintf(w, "SHA1: %s\n", pfd.Blob.HashSHA1)
fmt.Fprintf(w, "SHA256: %s\n", pfd.Blob.HashSHA256)
fmt.Fprintf(w, "SHA512: %s\n", pfd.Blob.HashSHA512)
}); err != nil {
return err
}

gzw.Close()
Expand All @@ -233,7 +234,7 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa
{"Packages.gz", packagesGzipContent},
{"Packages.xz", packagesXzContent},
} {
_, err = packages_service.AddFileToPackageVersionInternal(
_, err := packages_service.AddFileToPackageVersionInternal(
ctx,
repoVersion,
&packages_service.PackageFileCreationInfo{
Expand Down
41 changes: 26 additions & 15 deletions tests/integration/api_packages_debian_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func TestPackageDebian(t *testing.T) {

packageName := "gitea"
packageVersion := "1.0.3"
packageVersion2 := "1.0.4"
packageDescription := "Package Description"

createArchive := func(name, version, architecture string) io.Reader {
Expand Down Expand Up @@ -80,11 +81,11 @@ func TestPackageDebian(t *testing.T) {
for _, component := range components {
for _, architecture := range architectures {
t.Run(fmt.Sprintf("[Component:%s,Architecture:%s]", component, architecture), func(t *testing.T) {
uploadURL := fmt.Sprintf("%s/pool/%s/%s/upload", rootURL, distribution, component)

t.Run("Upload", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

uploadURL := fmt.Sprintf("%s/pool/%s/%s/upload", rootURL, distribution, component)

req := NewRequestWithBody(t, "PUT", uploadURL, bytes.NewReader([]byte{}))
MakeRequest(t, req, http.StatusUnauthorized)

Expand All @@ -102,7 +103,7 @@ func TestPackageDebian(t *testing.T) {

pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeDebian)
assert.NoError(t, err)
assert.Len(t, pvs, 1)
assert.NotEmpty(t, pvs)

pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
assert.NoError(t, err)
Expand Down Expand Up @@ -162,17 +163,23 @@ func TestPackageDebian(t *testing.T) {
t.Run("Packages", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()

req := NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, packageVersion2, architecture))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusCreated)

url := fmt.Sprintf("%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture)

req := NewRequest(t, "GET", url)
req = NewRequest(t, "GET", url)
resp := MakeRequest(t, req, http.StatusOK)

body := resp.Body.String()

assert.Contains(t, body, "Package: "+packageName)
assert.Contains(t, body, "Version: "+packageVersion)
assert.Contains(t, body, "Architecture: "+architecture)
assert.Contains(t, body, fmt.Sprintf("Filename: pool/%s/%s/%s_%s_%s.deb", distribution, component, packageName, packageVersion, architecture))
assert.Contains(t, body, "Package: "+packageName+"\n")
assert.Contains(t, body, "Version: "+packageVersion+"\n")
assert.Contains(t, body, "Version: "+packageVersion2+"\n")
assert.Contains(t, body, "Architecture: "+architecture+"\n")
assert.Contains(t, body, fmt.Sprintf("Filename: pool/%s/%s/%s_%s_%s.deb\n", distribution, component, packageName, packageVersion, architecture))
assert.Contains(t, body, fmt.Sprintf("Filename: pool/%s/%s/%s_%s_%s.deb\n", distribution, component, packageName, packageVersion2, architecture))

req = NewRequest(t, "GET", url+".gz")
MakeRequest(t, req, http.StatusOK)
Expand All @@ -198,14 +205,14 @@ func TestPackageDebian(t *testing.T) {

body := resp.Body.String()

assert.Contains(t, body, "Components: "+strings.Join(components, " "))
assert.Contains(t, body, "Architectures: "+strings.Join(architectures, " "))
assert.Contains(t, body, "Components: "+strings.Join(components, " ")+"\n")
assert.Contains(t, body, "Architectures: "+strings.Join(architectures, " ")+"\n")

for _, component := range components {
for _, architecture := range architectures {
assert.Contains(t, body, fmt.Sprintf("%s/binary-%s/Packages", component, architecture))
assert.Contains(t, body, fmt.Sprintf("%s/binary-%s/Packages.gz", component, architecture))
assert.Contains(t, body, fmt.Sprintf("%s/binary-%s/Packages.xz", component, architecture))
assert.Contains(t, body, fmt.Sprintf("%s/binary-%s/Packages\n", component, architecture))
assert.Contains(t, body, fmt.Sprintf("%s/binary-%s/Packages.gz\n", component, architecture))
assert.Contains(t, body, fmt.Sprintf("%s/binary-%s/Packages.xz\n", component, architecture))
}
}

Expand Down Expand Up @@ -241,6 +248,10 @@ func TestPackageDebian(t *testing.T) {
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusNoContent)

req = NewRequest(t, "DELETE", fmt.Sprintf("%s/pool/%s/%s/%s/%s/%s", rootURL, distribution, component, packageName, packageVersion2, architecture))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusNoContent)

req = NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/%s/binary-%s/Packages", rootURL, distribution, component, architecture))
MakeRequest(t, req, http.StatusNotFound)
}
Expand All @@ -250,7 +261,7 @@ func TestPackageDebian(t *testing.T) {

body := resp.Body.String()

assert.Contains(t, body, "Components: "+strings.Join(components, " "))
assert.Contains(t, body, "Architectures: "+architectures[1])
assert.Contains(t, body, "Components: "+strings.Join(components, " ")+"\n")
assert.Contains(t, body, "Architectures: "+architectures[1]+"\n")
})
}