From c4088caee11a6fbca922532d0d2c370cab084ca8 Mon Sep 17 00:00:00 2001 From: Jacob Kozol Date: Thu, 14 Nov 2019 16:53:39 +0100 Subject: [PATCH] api: add blueprint freeze route The blueprint freeze route returns the blueprint info but each package will be the package selected by depsolving. So, instead of the version being the version number with optional wildcards as /blueprints/info would provide, the version is of the form `Version-Release.Arch`. --- internal/weldr/api.go | 79 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/internal/weldr/api.go b/internal/weldr/api.go index c6ac18446..2a941dcb9 100644 --- a/internal/weldr/api.go +++ b/internal/weldr/api.go @@ -7,6 +7,7 @@ import ( "log" "net" "net/http" + "sort" "strings" "github.com/google/uuid" @@ -68,6 +69,7 @@ func New(rpmmd rpmmd.RPMMD, repo rpmmd.RepoConfig, logger *log.Logger, store *st api.router.GET("/api/v0/blueprints/list", api.blueprintsListHandler) api.router.GET("/api/v0/blueprints/info/*blueprints", api.blueprintsInfoHandler) api.router.GET("/api/v0/blueprints/depsolve/*blueprints", api.blueprintsDepsolveHandler) + api.router.GET("/api/v0/blueprints/freeze/*blueprints", api.blueprintsFreezeHandler) api.router.GET("/api/v0/blueprints/diff/:blueprint/:from/:to", api.blueprintsDiffHandler) api.router.GET("/api/v0/blueprints/changes/*blueprints", api.blueprintsChangesHandler) api.router.POST("/api/v0/blueprints/new", api.blueprintsNewHandler) @@ -689,6 +691,83 @@ func (api *API) blueprintsDepsolveHandler(writer http.ResponseWriter, request *h }) } +func (api *API) blueprintsFreezeHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) { + type blueprintFrozen struct { + Blueprint blueprint.Blueprint `json:"blueprint"` + } + + type reply struct { + Blueprints []blueprintFrozen `json:"blueprints"` + Errors []responseError `json:"errors"` + } + + names := strings.Split(params.ByName("blueprints"), ",") + if names[0] == "/" { + errors := responseError{ + Code: http.StatusNotFound, + ID: "HTTPError", + Msg: "Not Found", + } + statusResponseError(writer, http.StatusNotFound, errors) + return + } + + blueprints := []blueprintFrozen{} + errors := []responseError{} + for i, name := range names { + // remove leading / from first name + if i == 0 { + name = name[1:] + } + var blueprint blueprint.Blueprint + var changed bool + if !api.store.GetBlueprint(name, &blueprint, &changed) { + err := responseError{ + ID: "UnknownBlueprint", + Msg: fmt.Sprintf("%s: blueprint_not_found", name), + } + errors = append(errors, err) + return + } + + specs := make([]string, len(blueprint.Packages)) + for i, pkg := range blueprint.Packages { + specs[i] = pkg.Name + // If a package has version "*" the package name suffix must be equal to "-*-*.*" + // Using just "-*" would find any other package containing the package name + if pkg.Version != "" && pkg.Version != "*" { + specs[i] += "-" + pkg.Version + } else if pkg.Version == "*" { + specs[i] += "-*-*.*" + } + } + + var repos []rpmmd.RepoConfig + repos = append(repos, api.repo) + for _, source := range api.store.GetAllSources() { + repos = append(repos, rpmmd.SourceToRepo(source)) + } + + dependencies, _ := api.rpmmd.Depsolve(specs, repos) + + for pkgIndex, pkg := range blueprint.Packages { + i := sort.Search(len(dependencies), func(i int) bool { + return dependencies[i].Name >= pkg.Name + }) + if i < len(dependencies) && dependencies[i].Name == pkg.Name { + blueprint.Packages[pkgIndex].Version = dependencies[i].Version + "-" + dependencies[i].Release + "." + dependencies[i].Arch + } + } + + blueprints = append(blueprints, blueprintFrozen{blueprint}) + } + + json.NewEncoder(writer).Encode(reply{ + Blueprints: blueprints, + Errors: errors, + }) +} + func (api *API) blueprintsDiffHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) { type pack struct { Package blueprint.Package `json:"Package"`