mesh/merge-gate head f2379dfeea2d merged into trunk 113f7aa93385 — pass: builds mesh-delivery-view → shanks; no bus step; every machine composes with the c…
mesh/repo-check head f2379dfeea2d merged into trunk 113f7aa93385 — pass: its merge-check.sh passed
mesh/delivery delivered
mesh/check failed: g14: fetch of novox/mesh-delivery#18: build_go_fetch on g14: nats: no responders available for request | f2379dfeea2d on 113f7aa933…
193 lines
5.9 KiB
Go
193 lines
5.9 KiB
Go
package view
|
|
|
|
// The read tools of the indexer's modules (novox/hq issue 1562): what the indexer stored under modules.<m>, answered as
|
|
// stored. The new-form fingerprint (FP2, None2, Inputs2), the reason it has none, and the path and toolchains it was computed
|
|
// with are only there. The view reads the bucket through its reads; the reads write nothing.
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// The read tools, named as the module is: indexer_ and the verb.
|
|
const (
|
|
ModuleReadTool = "indexer_module"
|
|
ModulesReadTool = "indexer_modules"
|
|
)
|
|
|
|
// StateRead reads the indexer's modules state, as the view's reads grant it: its keys and a key's stored value (nil for a key with none).
|
|
type StateRead struct {
|
|
Keys func() ([]string, error)
|
|
Get func(key string) (json.RawMessage, error)
|
|
}
|
|
|
|
// Reader answers the read tools from a modules state.
|
|
type Reader struct {
|
|
State StateRead // the indexer's modules
|
|
Builds StateRead // the builder's builds
|
|
}
|
|
|
|
// Module is the stored value of modules.<module>, exactly as the indexer wrote it.
|
|
func (r Reader) Module(module string) (json.RawMessage, error) {
|
|
module = strings.TrimSpace(module)
|
|
key, err := delivery.ModulesKey(module)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if r.State.Get == nil {
|
|
return nil, fmt.Errorf("the modules state cannot be read here")
|
|
}
|
|
raw, err := r.State.Get(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(raw) == 0 {
|
|
return nil, fmt.Errorf("no module %s in the modules state", module)
|
|
}
|
|
return raw, nil
|
|
}
|
|
|
|
// Modules is every key of the modules state with its stored value; with none2 only the modules that have no new-form
|
|
// fingerprint and say why (a None2 reason), which is what the fingerprint's check reads live.
|
|
func (r Reader) Modules(none2 bool) (map[string]json.RawMessage, error) {
|
|
if r.State.Keys == nil || r.State.Get == nil {
|
|
return nil, fmt.Errorf("the modules state cannot be read here")
|
|
}
|
|
keys, err := r.State.Keys()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sort.Strings(keys)
|
|
out := map[string]json.RawMessage{}
|
|
for _, k := range keys {
|
|
raw, err := r.State.Get(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(raw) == 0 {
|
|
continue
|
|
}
|
|
if none2 {
|
|
var m struct {
|
|
None2 string `json:"none2"`
|
|
}
|
|
if json.Unmarshal(raw, &m) != nil || m.None2 == "" {
|
|
continue
|
|
}
|
|
}
|
|
out[k] = raw
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// The read tools of the builder's builds (novox/hq issue 1723): what the builder stored under `<module>.<fingerprint hex>`
|
|
// in mesh-delivery-builder_builds, answered as stored, so its states, nodes (in the step) and digests can be checked live.
|
|
const (
|
|
BuilderBuildReadTool = "builder_build"
|
|
BuilderBuildsReadTool = "builder_builds"
|
|
)
|
|
|
|
// BuilderRow is one key of the builder's builds: the key, the module and the fingerprint it parses to, and the stored value
|
|
// as the builder wrote it (state, by, step, manifest, artifacts with digests, toolchains, error).
|
|
type BuilderRow struct {
|
|
Key string `json:"key"`
|
|
Module string `json:"module"`
|
|
Fingerprint string `json:"fingerprint"`
|
|
Build json.RawMessage `json:"build"`
|
|
}
|
|
|
|
func (r Reader) builderRow(key string) (BuilderRow, bool, error) {
|
|
module, fp, err := delivery.ParseBuilderBuildKey(key)
|
|
if err != nil {
|
|
return BuilderRow{}, false, nil // a key that is no build key is not a build
|
|
}
|
|
raw, err := r.Builds.Get(key)
|
|
if err != nil {
|
|
return BuilderRow{}, false, err
|
|
}
|
|
if len(raw) == 0 {
|
|
return BuilderRow{}, false, nil
|
|
}
|
|
return BuilderRow{Key: key, Module: module, Fingerprint: fp, Build: raw}, true, nil
|
|
}
|
|
|
|
// BuilderBuilds lists the builder's keys, each as stored, sorted by key; module and state, when given, keep only the builds
|
|
// of that module or in that state.
|
|
func (r Reader) BuilderBuilds(module, state string) ([]BuilderRow, error) {
|
|
if r.Builds.Keys == nil || r.Builds.Get == nil {
|
|
return nil, fmt.Errorf("the builder's builds cannot be read here")
|
|
}
|
|
keys, err := r.Builds.Keys()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sort.Strings(keys)
|
|
rows := []BuilderRow{}
|
|
for _, k := range keys {
|
|
row, ok, err := r.builderRow(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !ok || (module != "" && row.Module != module) {
|
|
continue
|
|
}
|
|
if state != "" {
|
|
var b struct {
|
|
State string `json:"state"`
|
|
}
|
|
if json.Unmarshal(row.Build, &b) != nil || b.State != state {
|
|
continue
|
|
}
|
|
}
|
|
rows = append(rows, row)
|
|
}
|
|
return rows, nil
|
|
}
|
|
|
|
// BuilderBuild is the build of module at the new-form fingerprint fp2; with an empty fp2 it is the build at the fingerprint
|
|
// the indexer holds for the module now (its fp2), joined through modules.<module>; commit, when given, must be the commit
|
|
// the indexer holds that fp2 for, or the answer says which commit it holds (the fingerprint of another commit is not guessed).
|
|
func (r Reader) BuilderBuild(module, fp2, commit string) (BuilderRow, error) {
|
|
module = strings.TrimSpace(module)
|
|
if r.Builds.Get == nil {
|
|
return BuilderRow{}, fmt.Errorf("the builder's builds cannot be read here")
|
|
}
|
|
if fp2 == "" {
|
|
raw, err := r.Module(module)
|
|
if err != nil {
|
|
return BuilderRow{}, err
|
|
}
|
|
var m struct {
|
|
FP2 string `json:"fp2"`
|
|
None2 string `json:"none2"`
|
|
Commit string `json:"commit"`
|
|
}
|
|
if err := json.Unmarshal(raw, &m); err != nil {
|
|
return BuilderRow{}, fmt.Errorf("the indexer's value of %s is not readable: %w", module, err)
|
|
}
|
|
if commit != "" && m.Commit != commit {
|
|
return BuilderRow{}, fmt.Errorf("the indexer holds %s at commit %s, not %s, so its fingerprint is not the one of that commit", module, m.Commit, commit)
|
|
}
|
|
if m.FP2 == "" {
|
|
return BuilderRow{}, fmt.Errorf("the indexer holds no new-form fingerprint of %s: %s", module, m.None2)
|
|
}
|
|
fp2 = m.FP2
|
|
}
|
|
key, err := delivery.BuilderBuildKey(module, fp2)
|
|
if err != nil {
|
|
return BuilderRow{}, err
|
|
}
|
|
row, ok, err := r.builderRow(key)
|
|
if err != nil {
|
|
return BuilderRow{}, err
|
|
}
|
|
if !ok {
|
|
return BuilderRow{}, fmt.Errorf("the builder holds no build %s", key)
|
|
}
|
|
return row, nil
|
|
}
|