debian-forge-composer/internal/cloudapi/v2/search.go
Brian C. Lane 532f1b0396 cloudapi: Hook up the /search/packages handler
This connects all the pieces needed to implement the search.

If you POST a request to /search/packages like this:

    {
      "packages": [
        "tmux"
      ],
      "distribution": "fedora-41",
      "architecture": "x86_64"
    }

It will return details about the tmux packages that looks like this:

{
  "packages": [
    {
      "arch": "x86_64",
      "buildtime": "2024-10-10T00:19:06Z",
      "description": "tmux is ...",
      "license": "ISC AND BSD-2-Clause AND BSD-3-Clause AND SSH-short AND LicenseRef-Fedora-Public-Domain",
      "name": "tmux",
      "release": "2.fc41",
      "summary": "A terminal multiplexer",
      "url": "https://tmux.github.io/",
      "version": "3.5a"
    }
  ]
}

Resolves: RHEL-60136
2025-01-30 08:00:12 +01:00

85 lines
2.4 KiB
Go

package v2
// SearchPackagesRequest methods
import (
"context"
"fmt"
"time"
"github.com/osbuild/images/pkg/distrofactory"
"github.com/osbuild/images/pkg/reporegistry"
"github.com/osbuild/images/pkg/rpmmd"
"github.com/osbuild/osbuild-composer/internal/worker"
)
func (request *SearchPackagesRequest) Search(df *distrofactory.Factory, rr *reporegistry.RepoRegistry, workers *worker.Server) (rpmmd.PackageList, error) {
distro := df.GetDistro(request.Distribution)
if distro == nil {
return nil, HTTPError(ErrorUnsupportedDistribution)
}
distroArch, err := distro.GetArch(request.Architecture)
if err != nil {
return nil, HTTPErrorWithInternal(ErrorUnsupportedArchitecture, err)
}
var repos []rpmmd.RepoConfig
if request.Repositories != nil {
repos, err = convertRepos(*request.Repositories, []Repository{}, []string{})
if err != nil {
// Error comes from genRepoConfig and is already an HTTPError
return nil, err
}
} else {
repos, err = rr.ReposByArchName(request.Distribution, distroArch.Name(), false)
if err != nil {
return nil, HTTPErrorWithInternal(ErrorInvalidRepository, err)
}
}
// Send the search request to the worker
searchJobID, err := workers.EnqueueSearchPackages(&worker.SearchPackagesJob{
Packages: request.Packages,
Repositories: repos,
ModulePlatformID: distro.ModulePlatformID(),
Arch: distroArch.Name(),
Releasever: distro.Releasever(),
}, "")
if err != nil {
return nil, HTTPErrorWithInternal(ErrorEnqueueingJob, err)
}
// Limit how long a search can take
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*depsolveTimeoutMin)
defer cancel()
// Wait until search job is finished, fails, or is canceled
var result worker.SearchPackagesJobResult
for {
time.Sleep(time.Millisecond * 50)
info, err := workers.SearchPackagesJobInfo(searchJobID, &result)
if err != nil {
return nil, HTTPErrorWithInternal(ErrorFailedToDepsolve, err)
}
if result.JobError != nil {
return nil, HTTPErrorWithInternal(ErrorFailedToDepsolve, err)
}
if info.JobStatus != nil {
if info.JobStatus.Canceled {
return nil, HTTPErrorWithInternal(ErrorFailedToDepsolve, err)
}
if !info.JobStatus.Finished.IsZero() {
break
}
}
select {
case <-ctx.Done():
return nil, HTTPErrorWithInternal(ErrorFailedToDepsolve, fmt.Errorf("Search job %q timed out", searchJobID))
default:
}
}
return result.Packages, nil
}