The list itself, read strictly (catalogue/predefined.go); the controller keeps a catalogue trunk build's list in its store when its commit's generation is larger than the one kept (migration 0098), so an older build's list heard later never replaces a newer one, and loads it with its store (hq ADR 0348 clause 7, issue 661). Part 2 of 2: the new files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
77 lines
2.7 KiB
Go
77 lines
2.7 KiB
Go
package inventory
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
|
|
"github.com/novox/mesh-controller/internal/catalogue"
|
|
)
|
|
|
|
// The list of predefined keys the mesh publishes (novox/hq ADR 0348 §7, design 57 package K2): the newest trunk
|
|
// build's of the catalogue, by the generation of the commit built.
|
|
|
|
// PredefinedRecord is the list kept, and the build it came from.
|
|
type PredefinedRecord struct {
|
|
Keys catalogue.PredefinedList
|
|
Repository string
|
|
Commit string
|
|
Generation int
|
|
Build string
|
|
KeptAt time.Time
|
|
}
|
|
|
|
// KeepPredefined keeps a trunk build's list when its commit is newer than the one kept — a larger generation —
|
|
// and answers whether it did. An older build's list, or one of the same generation, heard later is not kept: the
|
|
// newer one stands, whatever order the outcomes arrive in. One statement, so two builds heard at once cannot both
|
|
// win.
|
|
func (i *Inventory) KeepPredefined(ctx context.Context, r PredefinedRecord) (bool, error) {
|
|
if r.Keys == nil {
|
|
return false, errors.New("no list to keep")
|
|
}
|
|
if r.Generation <= 0 {
|
|
return false, fmt.Errorf("the build %s did not say its commit's generation, so whether its list is newer "+
|
|
"than the one kept cannot be said", r.Build)
|
|
}
|
|
if problems := catalogue.PredefinedProblems(r.Keys); len(problems) > 0 {
|
|
return false, fmt.Errorf("the list of %s is refused: %v", r.Build, problems)
|
|
}
|
|
text, err := r.Keys.Canonical()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
tag, err := i.store.Pool().Exec(ctx, `
|
|
insert into predefined_list (keys, repository, commit, generation, build)
|
|
values ($1, $2, $3, $4, $5)
|
|
on conflict (one) do update set keys = excluded.keys, repository = excluded.repository,
|
|
commit = excluded.commit, generation = excluded.generation, build = excluded.build, kept_at = now()
|
|
where predefined_list.generation < excluded.generation`,
|
|
text, r.Repository, r.Commit, r.Generation, r.Build)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return tag.RowsAffected() == 1, nil
|
|
}
|
|
|
|
// PredefinedKept is the list kept, and false when none is yet.
|
|
func (i *Inventory) PredefinedKept(ctx context.Context) (PredefinedRecord, bool, error) {
|
|
var r PredefinedRecord
|
|
var text []byte
|
|
err := i.store.Pool().QueryRow(ctx,
|
|
`select keys, repository, commit, generation, build, kept_at from predefined_list`).
|
|
Scan(&text, &r.Repository, &r.Commit, &r.Generation, &r.Build, &r.KeptAt)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return PredefinedRecord{}, false, nil
|
|
}
|
|
if err != nil {
|
|
return PredefinedRecord{}, false, err
|
|
}
|
|
if r.Keys, err = catalogue.ParsePredefined(text); err != nil {
|
|
return PredefinedRecord{}, false, fmt.Errorf("the list kept from %s cannot be read: %w", r.Build, err)
|
|
}
|
|
return r, true, nil
|
|
}
|