api: improve parity of /{modules,projects}/{list,info} routes
These endpoint are similar in many ways, therefore just one commit. Their functionality is basically same as in lorax except for error messages and weird edge cases when handling trailing slashes. closes #64, closes #65
This commit is contained in:
parent
2ed070b218
commit
dd9a815c40
6 changed files with 441 additions and 232 deletions
|
|
@ -1,14 +1,47 @@
|
|||
package rpmmd_mock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
||||
"time"
|
||||
)
|
||||
|
||||
func generatePackageList() rpmmd.PackageList {
|
||||
baseTime, err := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var packageList rpmmd.PackageList
|
||||
|
||||
for i := 0; i < 22; i++ {
|
||||
basePackage := rpmmd.Package{
|
||||
Name: fmt.Sprintf("package%d", i),
|
||||
Summary: fmt.Sprintf("pkg%d sum", i),
|
||||
Description: fmt.Sprintf("pkg%d desc", i),
|
||||
URL: fmt.Sprintf("https://pkg%d.example.com", i),
|
||||
Epoch: 0,
|
||||
Version: fmt.Sprintf("%d.0", i),
|
||||
Release: fmt.Sprintf("%d.fc30", i),
|
||||
Arch: "x86_64",
|
||||
BuildTime: baseTime.AddDate(0, i, 0),
|
||||
License: "MIT",
|
||||
}
|
||||
|
||||
secondBuild := basePackage
|
||||
|
||||
secondBuild.Version = fmt.Sprintf("%d.1", i)
|
||||
secondBuild.BuildTime = basePackage.BuildTime.AddDate(0, 0, 1)
|
||||
|
||||
packageList = append(packageList, basePackage, secondBuild)
|
||||
}
|
||||
|
||||
return packageList
|
||||
}
|
||||
|
||||
var basePackageList = fetchPackageList{
|
||||
rpmmd.PackageList{
|
||||
{Name: "package1"},
|
||||
{Name: "package2"},
|
||||
},
|
||||
generatePackageList(),
|
||||
nil,
|
||||
}
|
||||
|
||||
|
|
@ -17,14 +50,14 @@ var BaseFixture = Fixture{
|
|||
depsolve{
|
||||
[]rpmmd.PackageSpec{
|
||||
{
|
||||
Name: "libgpg-error",
|
||||
Name: "dep-package1",
|
||||
Epoch: 0,
|
||||
Version: "1.33",
|
||||
Release: "2.fc30",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
{
|
||||
Name: "libsemanage",
|
||||
Name: "dep-package2",
|
||||
Epoch: 0,
|
||||
Version: "2.9",
|
||||
Release: "1.fc30",
|
||||
|
|
@ -56,3 +89,20 @@ var BadDepsolve = Fixture{
|
|||
},
|
||||
},
|
||||
}
|
||||
|
||||
var BadFetch = Fixture{
|
||||
fetchPackageList{
|
||||
ret: nil,
|
||||
err: &rpmmd.DNFError{
|
||||
Kind: "FetchError",
|
||||
Reason: "There was a problem when fetching packages.",
|
||||
},
|
||||
},
|
||||
depsolve{
|
||||
nil,
|
||||
&rpmmd.DNFError{
|
||||
Kind: "DepsolveError",
|
||||
Reason: "There was a problem depsolving ['go2rpm']: \n Problem: conflicting requests\n - nothing provides askalono-cli needed by go2rpm-1-4.fc31.noarch",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import (
|
|||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/store"
|
||||
)
|
||||
|
||||
|
|
@ -35,6 +37,30 @@ type Package struct {
|
|||
License string
|
||||
}
|
||||
|
||||
func (pkg Package) ToPackageBuild() PackageBuild {
|
||||
return PackageBuild{
|
||||
Arch: pkg.Arch,
|
||||
BuildTime: pkg.BuildTime,
|
||||
Epoch: pkg.Epoch,
|
||||
Release: pkg.Release,
|
||||
Source: PackageSource{
|
||||
License: pkg.License,
|
||||
Version: pkg.Version,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (pkg Package) ToPackageInfo() PackageInfo {
|
||||
return PackageInfo{
|
||||
Name: pkg.Name,
|
||||
Summary: pkg.Summary,
|
||||
Description: pkg.Description,
|
||||
Homepage: pkg.URL,
|
||||
Builds: []PackageBuild{pkg.ToPackageBuild()},
|
||||
Dependencies: nil,
|
||||
}
|
||||
}
|
||||
|
||||
type PackageSpec struct {
|
||||
Name string `json:"name"`
|
||||
Epoch uint `json:"epoch"`
|
||||
|
|
@ -43,6 +69,29 @@ type PackageSpec struct {
|
|||
Arch string `json:"arch,omitempty"`
|
||||
}
|
||||
|
||||
type PackageSource struct {
|
||||
License string `json:"license"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type PackageBuild struct {
|
||||
Arch string `json:"arch"`
|
||||
BuildTime time.Time `json:"build_time"`
|
||||
Epoch uint `json:"epoch"`
|
||||
Release string `json:"release"`
|
||||
Source PackageSource `json:"source"`
|
||||
}
|
||||
|
||||
type PackageInfo struct {
|
||||
Name string `json:"name"`
|
||||
Summary string `json:"summary"`
|
||||
Description string `json:"description"`
|
||||
Homepage string `json:"homepage"`
|
||||
UpstreamVCS string `json:"upstream_vcs"`
|
||||
Builds []PackageBuild `json:"builds"`
|
||||
Dependencies []PackageSpec `json:"dependencies,omitempty"`
|
||||
}
|
||||
|
||||
type RPMMD interface {
|
||||
FetchPackageList(repos []RepoConfig) (PackageList, error)
|
||||
Depsolve(specs []string, repos []RepoConfig) ([]PackageSpec, error)
|
||||
|
|
@ -145,21 +194,61 @@ func (*rpmmdImpl) Depsolve(specs []string, repos []RepoConfig) ([]PackageSpec, e
|
|||
return dependencies, err
|
||||
}
|
||||
|
||||
func (packages PackageList) Search(name string) (int, int) {
|
||||
first := sort.Search(len(packages), func(i int) bool {
|
||||
return packages[i].Name >= name
|
||||
func (packages PackageList) Search(globPatterns ...string) (PackageList, error) {
|
||||
var globs []glob.Glob
|
||||
|
||||
for _, globPattern := range globPatterns {
|
||||
g, err := glob.Compile(globPattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
globs = append(globs, g)
|
||||
}
|
||||
|
||||
var foundPackages PackageList
|
||||
|
||||
for _, pkg := range packages {
|
||||
for _, g := range globs {
|
||||
if g.Match(pkg.Name) {
|
||||
foundPackages = append(foundPackages, pkg)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(packages, func(i, j int) bool {
|
||||
return packages[i].Name < packages[j].Name
|
||||
})
|
||||
|
||||
if first == len(packages) || packages[first].Name != name {
|
||||
return first, 0
|
||||
return foundPackages, nil
|
||||
}
|
||||
|
||||
func (packages PackageList) ToPackageInfos() []PackageInfo {
|
||||
resultsNames := make(map[string]int)
|
||||
var results []PackageInfo
|
||||
|
||||
for _, pkg := range packages {
|
||||
if index, ok := resultsNames[pkg.Name]; ok {
|
||||
foundPkg := &results[index]
|
||||
|
||||
foundPkg.Builds = append(foundPkg.Builds, pkg.ToPackageBuild())
|
||||
} else {
|
||||
newIndex := len(results)
|
||||
resultsNames[pkg.Name] = newIndex
|
||||
|
||||
packageInfo := pkg.ToPackageInfo()
|
||||
|
||||
results = append(results, packageInfo)
|
||||
}
|
||||
}
|
||||
|
||||
last := first + 1
|
||||
for last < len(packages) && packages[last].Name == name {
|
||||
last++
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
return first, last - first
|
||||
func (pkg *PackageInfo) FillDependencies(rpmmd RPMMD, repos []RepoConfig) (err error) {
|
||||
pkg.Dependencies, err = rpmmd.Depsolve([]string{pkg.Name}, repos)
|
||||
return
|
||||
}
|
||||
|
||||
func SourceToRepo(source store.SourceConfig) RepoConfig {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
|
|
@ -55,11 +54,15 @@ func New(rpmmd rpmmd.RPMMD, repo rpmmd.RepoConfig, logger *log.Logger, store *st
|
|||
|
||||
api.router.GET("/api/v0/projects/depsolve/:projects", api.projectsDepsolveHandler)
|
||||
|
||||
api.router.GET("/api/v0/modules/list", api.modulesListAllHandler)
|
||||
api.router.GET("/api/v0/modules/list/:modules", api.modulesListHandler)
|
||||
api.router.GET("/api/v0/modules/list", api.modulesListHandler)
|
||||
api.router.GET("/api/v0/modules/list/*modules", api.modulesListHandler)
|
||||
api.router.GET("/api/v0/projects/list", api.projectsListHandler)
|
||||
api.router.GET("/api/v0/projects/list/", api.projectsListHandler)
|
||||
|
||||
// these are the same, except that modules/info also includes dependencies
|
||||
api.router.GET("/api/v0/modules/info", api.modulesInfoHandler)
|
||||
api.router.GET("/api/v0/modules/info/*modules", api.modulesInfoHandler)
|
||||
api.router.GET("/api/v0/projects/info", api.modulesInfoHandler)
|
||||
api.router.GET("/api/v0/projects/info/*modules", api.modulesInfoHandler)
|
||||
|
||||
api.router.GET("/api/v0/blueprints/list", api.blueprintsListHandler)
|
||||
|
|
@ -288,67 +291,17 @@ func (api *API) sourceDeleteHandler(writer http.ResponseWriter, request *http.Re
|
|||
statusResponseOK(writer)
|
||||
}
|
||||
|
||||
type modulesListModule struct {
|
||||
Name string `json:"name"`
|
||||
GroupType string `json:"group_type"`
|
||||
}
|
||||
|
||||
type modulesListReply struct {
|
||||
Total uint `json:"total"`
|
||||
Offset uint `json:"offset"`
|
||||
Limit uint `json:"limit"`
|
||||
Modules []modulesListModule `json:"modules"`
|
||||
}
|
||||
|
||||
func (api *API) modulesListAllHandler(writer http.ResponseWriter, request *http.Request, _ httprouter.Params) {
|
||||
offset, limit, err := parseOffsetAndLimit(request.URL.Query())
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: "BadLimitOrOffset",
|
||||
Msg: fmt.Sprintf("BadRequest: %s", err.Error()),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
var repos []rpmmd.RepoConfig
|
||||
repos = append(repos, api.repo)
|
||||
for _, source := range api.store.GetAllSources() {
|
||||
repos = append(repos, rpmmd.SourceToRepo(source))
|
||||
}
|
||||
|
||||
packages, err := api.rpmmd.FetchPackageList(repos)
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: "ModulesError",
|
||||
Msg: fmt.Sprintf("msg: %s", err.Error()),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
total := uint(len(packages))
|
||||
start := min(offset, total)
|
||||
n := min(limit, total-start)
|
||||
|
||||
modules := make([]modulesListModule, n)
|
||||
for i := uint(0); i < n; i++ {
|
||||
modules[i] = modulesListModule{packages[start+i].Name, "rpm"}
|
||||
}
|
||||
|
||||
json.NewEncoder(writer).Encode(modulesListReply{
|
||||
Total: total,
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Modules: modules,
|
||||
})
|
||||
}
|
||||
|
||||
func (api *API) modulesListHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
names := strings.Split(params.ByName("modules"), ",")
|
||||
if names[0] == "" || names[0] == "*" {
|
||||
api.modulesListAllHandler(writer, request, params)
|
||||
return
|
||||
type module struct {
|
||||
Name string `json:"name"`
|
||||
GroupType string `json:"group_type"`
|
||||
}
|
||||
|
||||
type reply struct {
|
||||
Total uint `json:"total"`
|
||||
Offset uint `json:"offset"`
|
||||
Limit uint `json:"limit"`
|
||||
Modules []module `json:"modules"`
|
||||
}
|
||||
|
||||
offset, limit, err := parseOffsetAndLimit(request.URL.Query())
|
||||
|
|
@ -362,13 +315,10 @@ func (api *API) modulesListHandler(writer http.ResponseWriter, request *http.Req
|
|||
return
|
||||
}
|
||||
|
||||
var repos []rpmmd.RepoConfig
|
||||
repos = append(repos, api.repo)
|
||||
for _, source := range api.store.GetAllSources() {
|
||||
repos = append(repos, rpmmd.SourceToRepo(source))
|
||||
}
|
||||
modulesParam := params.ByName("modules")
|
||||
|
||||
availablePackages, err := api.fetchPackageList()
|
||||
|
||||
packages, err := api.rpmmd.FetchPackageList(repos)
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: "ModulesError",
|
||||
|
|
@ -378,156 +328,193 @@ func (api *API) modulesListHandler(writer http.ResponseWriter, request *http.Req
|
|||
return
|
||||
}
|
||||
|
||||
// we don't support glob-matching, but cockpit-composer surrounds some
|
||||
// queries with asterisks; this is crude, but solves that case
|
||||
for i := range names {
|
||||
names[i] = strings.ReplaceAll(names[i], "*", "")
|
||||
}
|
||||
var packages rpmmd.PackageList
|
||||
if modulesParam != "" && modulesParam != "/" {
|
||||
// we have modules for search
|
||||
|
||||
modules := make([]modulesListModule, 0)
|
||||
total := uint(0)
|
||||
end := offset + limit
|
||||
for i, name := range names {
|
||||
for _, pkg := range packages {
|
||||
if strings.Contains(pkg.Name, name) {
|
||||
total++
|
||||
if total > offset && total < end {
|
||||
modules = append(modules, modulesListModule{pkg.Name, "rpm"})
|
||||
// this removes names that have been found from the list of names
|
||||
if len(names) < i-1 {
|
||||
names = append(names[:i], names[i+1:]...)
|
||||
} else {
|
||||
names = names[:i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// remove leading /
|
||||
modulesParam = modulesParam[1:]
|
||||
|
||||
// if a name remains in the list it was not found
|
||||
if len(names) > 0 {
|
||||
errors := responseError{
|
||||
ID: "UnknownModule",
|
||||
Msg: fmt.Sprintf("one of the requested modules does not exist: ['%s']", names[0]),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
names := strings.Split(modulesParam, ",")
|
||||
|
||||
json.NewEncoder(writer).Encode(modulesListReply{
|
||||
Total: total,
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Modules: modules,
|
||||
})
|
||||
}
|
||||
packages, err = availablePackages.Search(names...)
|
||||
|
||||
func (api *API) modulesInfoHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
type source struct {
|
||||
License string `json:"license"`
|
||||
Version string `json:"version"`
|
||||
}
|
||||
type build struct {
|
||||
Arch string `json:"arch"`
|
||||
BuildTime time.Time `json:"build_time"`
|
||||
Epoch uint `json:"epoch"`
|
||||
Release string `json:"release"`
|
||||
Source source `json:"source"`
|
||||
}
|
||||
type project struct {
|
||||
Name string `json:"name"`
|
||||
Summary string `json:"summary"`
|
||||
Description string `json:"description"`
|
||||
Homepage string `json:"homepage"`
|
||||
Builds []build `json:"builds"`
|
||||
Dependencies []rpmmd.PackageSpec `json:"dependencies,omitempty"`
|
||||
}
|
||||
type projectsReply struct {
|
||||
Projects []project `json:"projects"`
|
||||
}
|
||||
type modulesReply struct {
|
||||
Modules []project `json:"modules"`
|
||||
}
|
||||
|
||||
// handle both projects/info and modules/info, the latter includes dependencies
|
||||
modulesRequested := strings.HasPrefix(request.URL.Path, "/api/v0/modules")
|
||||
|
||||
names := strings.Split(params.ByName("modules"), ",")
|
||||
if names[0] == "/" {
|
||||
errors := responseError{
|
||||
Code: http.StatusNotFound,
|
||||
ID: "HTTPError",
|
||||
Msg: "Not Found",
|
||||
}
|
||||
statusResponseError(writer, http.StatusNotFound, errors)
|
||||
return
|
||||
}
|
||||
|
||||
var repos []rpmmd.RepoConfig
|
||||
repos = append(repos, api.repo)
|
||||
for _, source := range api.store.GetAllSources() {
|
||||
repos = append(repos, rpmmd.SourceToRepo(source))
|
||||
}
|
||||
|
||||
packages, err := api.rpmmd.FetchPackageList(repos)
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: "ModulesError",
|
||||
Msg: fmt.Sprintf("msg: %s", err.Error()),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
projects := make([]project, 0)
|
||||
for i, name := range names {
|
||||
// remove leading / from first name
|
||||
if i == 0 {
|
||||
name = name[1:]
|
||||
}
|
||||
|
||||
first, n := packages.Search(name)
|
||||
if n == 0 {
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: "UnknownModule",
|
||||
Msg: fmt.Sprintf("one of the requested modules does not exist: %s", name),
|
||||
ID: "ModulesError",
|
||||
Msg: fmt.Sprintf("Wrong glob pattern: %s", err.Error()),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
// get basic info from the first package, but collect build
|
||||
// information from all that have the same name
|
||||
pkg := packages[first]
|
||||
project := project{
|
||||
Name: pkg.Name,
|
||||
Summary: pkg.Summary,
|
||||
Description: pkg.Description,
|
||||
Homepage: pkg.URL,
|
||||
if len(packages) == 0 {
|
||||
errors := responseError{
|
||||
ID: "UnknownModule",
|
||||
Msg: "No packages have been found.",
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// just return all available packages
|
||||
packages = availablePackages
|
||||
}
|
||||
|
||||
project.Builds = make([]build, n)
|
||||
for i, pkg := range packages[first : first+n] {
|
||||
project.Builds[i] = build{
|
||||
Arch: pkg.Arch,
|
||||
BuildTime: pkg.BuildTime,
|
||||
Epoch: pkg.Epoch,
|
||||
Release: pkg.Release,
|
||||
Source: source{pkg.License, pkg.Version},
|
||||
packageInfos := packages.ToPackageInfos()
|
||||
|
||||
total := uint(len(packageInfos))
|
||||
start := min(offset, total)
|
||||
n := min(limit, total-start)
|
||||
|
||||
modules := make([]module, n)
|
||||
for i := uint(0); i < n; i++ {
|
||||
modules[i] = module{packageInfos[start+i].Name, "rpm"}
|
||||
}
|
||||
|
||||
json.NewEncoder(writer).Encode(reply{
|
||||
Total: total,
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Modules: modules,
|
||||
})
|
||||
}
|
||||
|
||||
func (api *API) projectsListHandler(writer http.ResponseWriter, request *http.Request, _ httprouter.Params) {
|
||||
type reply struct {
|
||||
Total uint `json:"total"`
|
||||
Offset uint `json:"offset"`
|
||||
Limit uint `json:"limit"`
|
||||
Projects []rpmmd.PackageInfo `json:"projects"`
|
||||
}
|
||||
|
||||
offset, limit, err := parseOffsetAndLimit(request.URL.Query())
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: "BadLimitOrOffset",
|
||||
Msg: fmt.Sprintf("BadRequest: %s", err.Error()),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
availablePackages, err := api.fetchPackageList()
|
||||
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: "ProjectsError",
|
||||
Msg: fmt.Sprintf("msg: %s", err.Error()),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
packageInfos := availablePackages.ToPackageInfos()
|
||||
|
||||
total := uint(len(packageInfos))
|
||||
start := min(offset, total)
|
||||
n := min(limit, total-start)
|
||||
|
||||
packages := make([]rpmmd.PackageInfo, n)
|
||||
for i := uint(0); i < n; i++ {
|
||||
packages[i] = packageInfos[start+i]
|
||||
}
|
||||
|
||||
json.NewEncoder(writer).Encode(reply{
|
||||
Total: total,
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Projects: packages,
|
||||
})
|
||||
}
|
||||
|
||||
func (api *API) modulesInfoHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
type projectsReply struct {
|
||||
Projects []rpmmd.PackageInfo `json:"projects"`
|
||||
}
|
||||
type modulesReply struct {
|
||||
Modules []rpmmd.PackageInfo `json:"modules"`
|
||||
}
|
||||
|
||||
// handle both projects/info and modules/info, the latter includes dependencies
|
||||
modulesRequested := strings.HasPrefix(request.URL.Path, "/api/v0/modules")
|
||||
|
||||
var errorId, unknownErrorId string
|
||||
if modulesRequested {
|
||||
errorId = "ModulesError"
|
||||
unknownErrorId = "UnknownModule"
|
||||
} else {
|
||||
errorId = "ProjectsError"
|
||||
unknownErrorId = "UnknownProject"
|
||||
}
|
||||
|
||||
modules := params.ByName("modules")
|
||||
|
||||
if modules == "" || modules == "/" {
|
||||
errors := responseError{
|
||||
ID: unknownErrorId,
|
||||
Msg: "No packages specified.",
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
// remove leading /
|
||||
modules = modules[1:]
|
||||
|
||||
names := strings.Split(modules, ",")
|
||||
|
||||
availablePackages, err := api.fetchPackageList()
|
||||
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: "ModulesError",
|
||||
Msg: fmt.Sprintf("msg: %s", err.Error()),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
foundPackages, err := availablePackages.Search(names...)
|
||||
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: errorId,
|
||||
Msg: fmt.Sprintf("Wrong glob pattern: %s", err.Error()),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
if len(foundPackages) == 0 {
|
||||
errors := responseError{
|
||||
ID: unknownErrorId,
|
||||
Msg: "No packages have been found.",
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
|
||||
packageInfos := foundPackages.ToPackageInfos()
|
||||
|
||||
if modulesRequested {
|
||||
for i, _ := range packageInfos {
|
||||
err := packageInfos[i].FillDependencies(api.rpmmd, []rpmmd.RepoConfig{api.repo})
|
||||
if err != nil {
|
||||
errors := responseError{
|
||||
ID: errorId,
|
||||
Msg: fmt.Sprintf("Cannot depsolve package %s: %s", packageInfos[i].Name, err.Error()),
|
||||
}
|
||||
statusResponseError(writer, http.StatusBadRequest, errors)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if modulesRequested {
|
||||
project.Dependencies, _ = api.rpmmd.Depsolve([]string{pkg.Name}, repos)
|
||||
}
|
||||
|
||||
projects = append(projects, project)
|
||||
}
|
||||
|
||||
if modulesRequested {
|
||||
json.NewEncoder(writer).Encode(modulesReply{projects})
|
||||
json.NewEncoder(writer).Encode(modulesReply{packageInfos})
|
||||
} else {
|
||||
json.NewEncoder(writer).Encode(projectsReply{projects})
|
||||
json.NewEncoder(writer).Encode(projectsReply{packageInfos})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1112,3 +1099,13 @@ func (api *API) composeFailedHandler(writer http.ResponseWriter, request *http.R
|
|||
|
||||
json.NewEncoder(writer).Encode(reply)
|
||||
}
|
||||
|
||||
func (api *API) fetchPackageList() (rpmmd.PackageList, error) {
|
||||
var repos []rpmmd.RepoConfig
|
||||
repos = append(repos, api.repo)
|
||||
for _, source := range api.store.GetAllSources() {
|
||||
repos = append(repos, rpmmd.SourceToRepo(source))
|
||||
}
|
||||
|
||||
return api.rpmmd.FetchPackageList(repos)
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue