package catalogue import ( "errors" "regexp" ) // A key this controller does not know, in a manifest (novox/hq ADR 0262). // // Registration refuses it, as it always has. A manifest the store already holds was registered by a newer // controller, and is read by this one after a rollback: refusing it there failed the whole catalogue, and // with it every plan and every send. Dropping the key silently would be worse — a module running without // something its manifest says. So the manifest is read, the module is left out of every machine's // declaration by name, and the controller raises a condition until it is updated. // UnknownFieldError is a key a manifest has that this controller does not know, wherever it is: at the // top of the manifest or inside a block (a state, an offer, a data item's backup, an own secret, a verb). // Typed, because the blocks' decoders wrap the decoder's words in their own. type UnknownFieldError struct { Field string err error } func (e *UnknownFieldError) Error() string { return e.err.Error() } func (e *UnknownFieldError) Unwrap() error { return e.err } // unknownFieldText is how the JSON decoder words a key its target does not have. var unknownFieldText = regexp.MustCompile(`^json: unknown field "([^"]*)"$`) // typedUnknown is err as an UnknownFieldError when it is the decoder refusing an unknown key, else err. func typedUnknown(err error) error { if err == nil { return nil } if m := unknownFieldText.FindStringSubmatch(err.Error()); m != nil { return &UnknownFieldError{Field: m[1], err: err} } return err } // asUnknownField is the unknown key err is about, at any depth, or nil. func asUnknownField(err error) *UnknownFieldError { var u *UnknownFieldError if errors.As(typedUnknown(err), &u) { return u } return nil } // UnknownFieldReason is why a module whose stored manifest has a key this controller does not know is // left out of a machine's declaration, or "" when it has none. func UnknownFieldReason(m Manifest) string { if m.unknown == "" { return "" } return m.Module + " uses a field this controller does not know (" + m.unknown + "); it is left out " + "until the controller is updated (novox/hq ADR 0262)" }