edge/pkg/app/manifest.go

86 lines
2.0 KiB
Go

package app
import (
"strings"
"forge.cadoles.com/arcad/edge/pkg/bundle"
"github.com/pkg/errors"
"golang.org/x/mod/semver"
"gopkg.in/yaml.v2"
)
type ID string
type Manifest struct {
ID ID `yaml:"id" json:"id"`
Version string `yaml:"version" json:"version"`
Title string `yaml:"title" json:"title"`
Description string `yaml:"description" json:"description"`
Tags []string `yaml:"tags" json:"tags"`
Metadata map[string]any `yaml:"metadata" json:"metadata"`
}
type MetadataValidator func(map[string]any) (bool, error)
func (m *Manifest) Validate(validators ...MetadataValidator) (bool, error) {
if m.ID == "" {
return false, errors.New("'id' property should not be empty")
}
if m.Version == "" {
return false, errors.New("'version' property should not be empty")
}
version := m.Version
if !strings.HasPrefix(version, "v") {
version = "v" + version
}
if !semver.IsValid(version) {
return false, errors.Errorf("version '%s' does not respect semver format", m.Version)
}
if m.Title == "" {
return false, errors.New("'title' property should not be empty")
}
if m.Tags != nil {
for _, t := range m.Tags {
if strings.ContainsAny(t, " \t\n\r") {
return false, errors.Errorf("tag '%s' should not contain any space or new line", t)
}
}
}
for _, v := range validators {
valid, err := v(m.Metadata)
if !valid || err != nil {
return valid, errors.WithStack(err)
}
}
return true, nil
}
func LoadManifest(b bundle.Bundle) (*Manifest, error) {
reader, _, err := b.File("manifest.yml")
if err != nil {
return nil, errors.Wrap(err, "could not read manifest.yml")
}
defer func() {
if err := reader.Close(); err != nil {
panic(errors.WithStack(err))
}
}()
manifest := &Manifest{}
decoder := yaml.NewDecoder(reader)
if err := decoder.Decode(manifest); err != nil {
return nil, errors.Wrap(err, "could not decode manifest.yml")
}
return manifest, nil
}