130 lines
2.8 KiB
Go
130 lines
2.8 KiB
Go
package module
|
|
|
|
import (
|
|
"aego/asset"
|
|
"aego/core/ids"
|
|
"aego/engine/problems"
|
|
"aego/schema"
|
|
"aego/vfs"
|
|
)
|
|
|
|
type AssetCheck struct {
|
|
ID ids.AssetID
|
|
Path string
|
|
Kind string
|
|
Source []byte
|
|
Schema *schema.Registry
|
|
Data asset.DataSource
|
|
Exists func(ids.AssetID) bool
|
|
Partial bool
|
|
}
|
|
|
|
type AssetValidator func(*AssetCheck) []problems.Diagnostic
|
|
|
|
type ownedValidator struct {
|
|
kind string
|
|
owner string
|
|
fn AssetValidator
|
|
}
|
|
|
|
type AssetStore interface {
|
|
Revision() uint64
|
|
Index() *asset.Index
|
|
Artifacts() vfs.FS
|
|
}
|
|
|
|
func (r *Registry) Validator(kind string, fn AssetValidator) {
|
|
if kind == "" || fn == nil {
|
|
r.fail("asset validator needs a kind and a function")
|
|
return
|
|
}
|
|
r.validators = append(r.validators, ownedValidator{kind: kind, owner: r.Owner(), fn: fn})
|
|
}
|
|
|
|
type storeData struct {
|
|
s AssetStore
|
|
}
|
|
|
|
func (d storeData) blob(id ids.AssetID, kind asset.ArtifactKind) ([]byte, bool) {
|
|
idx := d.s.Index()
|
|
if idx == nil {
|
|
return nil, false
|
|
}
|
|
e, ok := idx.Lookup(id)
|
|
if !ok || e.Missing || e.Kind != kind {
|
|
return nil, false
|
|
}
|
|
a, ok := e.Artifact(kind)
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
data, err := d.s.Artifacts().ReadFile(a.Path)
|
|
return data, err == nil
|
|
}
|
|
|
|
func (d storeData) Data(id ids.AssetID) ([]byte, bool) {
|
|
return d.blob(id, asset.ArtData)
|
|
}
|
|
|
|
func (d storeData) Table(id ids.AssetID) ([]byte, bool) {
|
|
return d.blob(id, asset.ArtTable)
|
|
}
|
|
|
|
func (m *Manifest) ValidateAssets(reg *schema.Registry, s AssetStore, partial bool, dst []problems.Diagnostic) []problems.Diagnostic {
|
|
idx := s.Index()
|
|
if len(m.validators) == 0 || idx == nil || s.Artifacts() == nil {
|
|
return dst
|
|
}
|
|
ds := storeData{s: s}
|
|
exists := func(id ids.AssetID) bool {
|
|
if asset.IsBuiltin(id) {
|
|
return true
|
|
}
|
|
e, ok := idx.Lookup(id)
|
|
return ok && !e.Missing
|
|
}
|
|
idx.Each(func(e *asset.Entry) {
|
|
if e.Missing {
|
|
return
|
|
}
|
|
kind := string(e.Kind)
|
|
var c *AssetCheck
|
|
for _, v := range m.validators {
|
|
if v.kind != kind {
|
|
continue
|
|
}
|
|
if c == nil {
|
|
c = &AssetCheck{ID: e.ID, Path: e.Source, Kind: kind, Schema: reg, Data: ds, Exists: exists, Partial: partial}
|
|
if a, ok := e.Artifact(e.Kind); ok {
|
|
c.Source, _ = s.Artifacts().ReadFile(a.Path)
|
|
}
|
|
}
|
|
for _, d := range v.fn(c) {
|
|
if d.Owner == "" {
|
|
d.Owner = v.owner
|
|
}
|
|
if d.Subject.Kind == problems.SubjectNone {
|
|
d.Subject.Kind = problems.SubjectAsset
|
|
}
|
|
if d.Subject.Asset.IsZero() {
|
|
d.Subject.Asset = e.ID
|
|
}
|
|
if d.Subject.File == "" {
|
|
d.Subject.File = e.Source
|
|
}
|
|
dst = append(dst, d)
|
|
}
|
|
}
|
|
})
|
|
return dst
|
|
}
|
|
|
|
func (m *Manifest) AssetProblems(reg *schema.Registry, s AssetStore) problems.Source {
|
|
return problems.Source{
|
|
Revision: s.Revision,
|
|
Append: func(dst []problems.Diagnostic) []problems.Diagnostic {
|
|
return m.ValidateAssets(reg, s, false, dst)
|
|
},
|
|
}
|
|
}
|