This repository has been archived on 2020-11-18. You can view files and clone it, but cannot push or open issues or pull requests.
get/parser.go
jolheiser 98795c6735
Initial Commit
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2020-10-30 00:42:30 -05:00

119 lines
2.3 KiB
Go

package get
import (
"bufio"
"bytes"
"errors"
"fmt"
"github.com/go-git/go-git/v5"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
// Parse parses an AST
func Parse(contents []byte) (*AST, error) {
directives := make([]Directive, 0)
comments := make([]string, 0)
errs := make([]error, 0)
scanner := bufio.NewScanner(bytes.NewBuffer(contents))
for scanner.Scan() {
text := os.ExpandEnv(scanner.Text())
// Comments
if strings.HasPrefix(text, "#") {
comments = append(comments, strings.TrimLeft(text, "# "))
continue
}
// Directive
line := strings.Fields(strings.TrimSpace(text))
if len(line) <= 1 {
continue
}
typ, err := ParseType(line[0])
if err != nil {
errs = append(errs, err)
continue
}
args := line[1:]
switch typ {
case CMD:
if len(args) < 1 {
err = errors.New("CMD requires 1 or more arguments")
}
case COPY:
if len(args) != 2 {
err = fmt.Errorf("COPY requires 2 arguments but got %d", len(args))
}
case ECHO:
err = nil // Just explicitly set it
case FETCH:
if len(args) != 2 {
err = fmt.Errorf("FETCH requires 2 arguments but got %d", len(args))
}
case GET:
if len(args) != 1 {
err = fmt.Errorf("GET requires 1 argument but got %d", len(args))
}
}
if err != nil {
errs = append(errs, err)
continue
}
directives = append(directives, Directive{
Type: typ,
Args: args,
Comments: comments,
ParseError: err,
})
comments = make([]string, 0)
}
var err error
if len(errs) > 0 {
err = ErrInvalid{Errors: errs}
}
return &AST{
Directives: directives,
}, err
}
// ParseFile will parse an AST from a file
func ParseFile(filename string) (*AST, error) {
contents, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return Parse(contents)
}
// ParseRepo will clone a repository and search for a Getfile to parse an AST
// It is the caller's responsibility to clean up the clone from <base>
func ParseRepo(base, url string) (*AST, error) {
_, err := git.PlainClone(base, false, &git.CloneOptions{
URL: url,
})
if err != nil {
return nil, err
}
return ParseFile(filepath.Join(base, "Getfile"))
}
type ErrInvalid struct {
Errors []error
}
func (e ErrInvalid) Error() string {
errs := make([]string, len(e.Errors))
for idx, err := range e.Errors {
errs[idx] = err.Error()
}
return strings.Join(errs, "\n")
}