drone-yaml/yaml/parse.go

187 lines
3.2 KiB
Go
Raw Normal View History

// Copyright (c) 2019, Drone IO Inc.
// Copyright (c) 2021, Robert Kaussow <mail@thegeeklab.de>
2019-02-10 20:00:16 +01:00
2019-01-23 00:44:17 +01:00
package yaml
import (
"bufio"
"bytes"
2019-05-30 17:14:47 +02:00
"errors"
2019-01-23 00:44:17 +01:00
"io"
"os"
"strings"
"gopkg.in/yaml.v2"
2019-01-23 00:44:17 +01:00
)
var ErrMissingKind = errors.New("yaml: missing kind attribute")
2019-05-30 17:14:47 +02:00
2019-01-23 00:44:17 +01:00
// Parse parses the configuration from io.Reader r.
func Parse(r io.Reader) (*Manifest, error) {
resources, err := ParseRaw(r)
if err != nil {
return nil, err
}
2019-01-23 00:44:17 +01:00
manifest := new(Manifest)
2019-01-23 00:44:17 +01:00
for _, raw := range resources {
if raw == nil {
continue
}
2019-01-23 00:44:17 +01:00
resource, err := parseRaw(raw)
if err != nil {
return nil, err
}
2019-05-30 17:14:47 +02:00
if resource.GetKind() == "" {
return nil, ErrMissingKind
2019-05-30 17:14:47 +02:00
}
2019-01-23 00:44:17 +01:00
manifest.Resources = append(
manifest.Resources,
resource,
)
}
2019-01-23 00:44:17 +01:00
return manifest, nil
}
// ParseBytes parses the configuration from bytes b.
func ParseBytes(b []byte) (*Manifest, error) {
return Parse(
bytes.NewBuffer(b),
)
}
// ParseString parses the configuration from string s.
func ParseString(s string) (*Manifest, error) {
return ParseBytes(
[]byte(s),
)
}
// ParseFile parses the configuration from path p.
func ParseFile(p string) (*Manifest, error) {
f, err := os.Open(p)
if err != nil {
return nil, err
}
defer f.Close()
2019-01-23 00:44:17 +01:00
return Parse(f)
}
func parseRaw(r *RawResource) (Resource, error) { //nolint:ireturn
2019-01-23 00:44:17 +01:00
var obj Resource
2019-01-23 00:44:17 +01:00
switch r.Kind {
case "cron":
obj = new(Cron)
case "secret":
obj = new(Secret)
case "signature":
obj = new(Signature)
case "registry":
obj = new(Registry)
default:
obj = new(Pipeline)
}
2019-01-23 00:44:17 +01:00
err := yaml.Unmarshal(r.Data, obj)
2019-01-23 00:44:17 +01:00
return obj, err
}
// ParseRaw parses the multi-document yaml from the
// io.Reader and returns a slice of raw resources.
func ParseRaw(r io.Reader) ([]*RawResource, error) {
const newline = '\n'
var (
resources []*RawResource
resource *RawResource
)
2019-01-23 00:44:17 +01:00
scanner := bufio.NewScanner(r)
for scanner.Scan() {
line := scanner.Text()
if isSeparator(line) {
resource = nil
}
2019-01-23 00:44:17 +01:00
if resource == nil {
resource = &RawResource{}
resources = append(resources, resource)
}
2019-01-23 00:44:17 +01:00
if isSeparator(line) {
continue
}
2019-01-23 00:44:17 +01:00
if isTerminator(line) {
break
}
if errors.Is(scanner.Err(), io.EOF) {
2019-01-23 00:44:17 +01:00
break
}
2019-01-23 00:44:17 +01:00
resource.Data = append(
resource.Data,
line...,
)
2019-01-23 00:44:17 +01:00
resource.Data = append(
resource.Data,
newline,
)
}
2019-01-23 00:44:17 +01:00
for _, resource := range resources {
err := yaml.Unmarshal(resource.Data, resource)
if err != nil {
return nil, err
}
}
2019-01-23 00:44:17 +01:00
return resources, nil
}
// ParseRawString parses the multi-document yaml from s
// and returns a slice of raw resources.
func ParseRawString(s string) ([]*RawResource, error) {
return ParseRaw(
strings.NewReader(s),
)
}
// ParseRawBytes parses the multi-document yaml from b
// and returns a slice of raw resources.
func ParseRawBytes(b []byte) ([]*RawResource, error) {
return ParseRaw(
bytes.NewReader(b),
)
}
// ParseRawFile parses the multi-document yaml from path p
// and returns a slice of raw resources.
func ParseRawFile(p string) ([]*RawResource, error) {
f, err := os.Open(p)
if err != nil {
return nil, err
}
defer f.Close()
2019-01-23 00:44:17 +01:00
return ParseRaw(f)
}
func isSeparator(s string) bool {
return strings.HasPrefix(s, "---")
}
func isTerminator(s string) bool {
return strings.HasPrefix(s, "...")
}