crazy-max_diun/pkg/dockerfile/client.go

78 lines
1.8 KiB
Go

package dockerfile
import (
"bytes"
"os"
"github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/moby/buildkit/frontend/dockerfile/parser"
"github.com/moby/buildkit/frontend/dockerfile/shell"
"github.com/pkg/errors"
)
// Client represents an active dockerfile object
type Client struct {
ast *parser.Node
stages []instructions.Stage
metaArgs []instructions.KeyValuePairOptional
shlex *shell.Lex
}
// Options holds dockerfile client object options
type Options struct {
Filename string
}
// New initializes a new dockerfile client
func New(opts Options) (*Client, error) {
b, err := os.ReadFile(opts.Filename)
if err != nil {
return nil, errors.Wrapf(err, "cannot read Dockerfile %s", opts.Filename)
}
parsed, err := parser.Parse(bytes.NewReader(b))
if err != nil {
return nil, errors.Wrapf(err, "cannot parse Dockerfile %s", opts.Filename)
}
stages, metaArgs, err := instructions.Parse(parsed.AST)
if err != nil {
return nil, errors.Wrapf(err, "cannot parse stages for Dockerfile %s", opts.Filename)
}
var kvpoArgs []instructions.KeyValuePairOptional
shlex := shell.NewLex(parsed.EscapeToken)
for _, cmd := range metaArgs {
for _, metaArg := range cmd.Args {
if metaArg.Value != nil {
*metaArg.Value, _ = shlex.ProcessWordWithMap(*metaArg.Value, metaArgsToMap(kvpoArgs))
}
kvpoArgs = append(kvpoArgs, metaArg)
}
}
return &Client{
ast: parsed.AST,
stages: stages,
metaArgs: kvpoArgs,
shlex: shlex,
}, nil
}
func (c *Client) isStageName(name string) bool {
for _, stage := range c.stages {
if stage.Name == name {
return true
}
}
return false
}
func metaArgsToMap(metaArgs []instructions.KeyValuePairOptional) map[string]string {
m := map[string]string{}
for _, arg := range metaArgs {
m[arg.Key] = arg.ValueString()
}
return m
}