Beispiel #1
0
// NewRockerfile reads parses Rockerfile from an io.Reader
func NewRockerfile(name string, in io.Reader, vars template.Vars, funs template.Funs) (r *Rockerfile, err error) {
	r = &Rockerfile{
		Name: name,
		Vars: vars,
		Funs: funs,
	}

	var (
		source  []byte
		content *bytes.Buffer
	)

	if source, err = ioutil.ReadAll(in); err != nil {
		return nil, fmt.Errorf("Failed to read Rockerfile %s, error: %s", name, err)
	}

	r.Source = string(source)

	if content, err = template.Process(name, bytes.NewReader(source), vars, funs); err != nil {
		return nil, err
	}

	r.Content = content.String()

	// TODO: update parser from Docker

	if r.rootNode, err = parser.Parse(content); err != nil {
		return nil, err
	}

	return r, nil
}
Beispiel #2
0
// Parse parses a Rockerfile from an io.Reader and returns AST data structure
func Parse(rockerfileContent io.Reader) (*parser.Node, error) {
	node, err := parser.Parse(rockerfileContent)
	if err != nil {
		return nil, err
	}

	return node, nil
}
Beispiel #3
0
// cmdInclude implements INCLUDE command
// TODO: document behavior of cmdInclude
func (builder *Builder) cmdInclude(args []string, attributes map[string]bool, flags map[string]string, original string) (err error) {
	if len(args) == 0 {
		return fmt.Errorf("Command is missing value: %s", original)
	}

	module := args[0]
	contextDir := filepath.Dir(builder.Rockerfile)
	resultPath := filepath.Clean(path.Join(contextDir, module))

	// TODO: protect against going out of working directory?

	stat, err := os.Stat(resultPath)
	if err != nil {
		return err
	}
	if !stat.Mode().IsRegular() {
		return fmt.Errorf("Expected included resource to be a regular file: %s (%s)", module, original)
	}

	fd, err := os.Open(resultPath)
	if err != nil {
		return err
	}
	defer fd.Close()

	includedNode, err := parser.Parse(fd)
	if err != nil {
		return err
	}

	for _, node := range includedNode.Children {
		if node.Value == "include" {
			return fmt.Errorf("Nesting includes is not allowed: \"%s\" in %s", original, resultPath)
		}
	}

	// inject included commands info root node at current execution position
	after := append(includedNode.Children, builder.rootNode.Children[builder.i+1:]...)
	builder.rootNode.Children = append(builder.rootNode.Children[:builder.i], after...)
	builder.i--

	return nil
}
Beispiel #4
0
func parseOnbuildCommands(onBuildTriggers []string) ([]ConfigCommand, error) {
	commands := []ConfigCommand{}

	for _, step := range onBuildTriggers {

		ast, err := parser.Parse(strings.NewReader(step))
		if err != nil {
			return commands, err
		}

		for _, n := range ast.Children {
			switch strings.ToUpper(n.Value) {
			case "ONBUILD":
				return commands, fmt.Errorf("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed")
			case "MAINTAINER", "FROM":
				return commands, fmt.Errorf("%s isn't allowed as an ONBUILD trigger", n.Value)
			}

			commands = append(commands, parseCommand(n, true))
		}
	}

	return commands, nil
}
Beispiel #5
0
// Build runs the build of given Rockerfile and returns image id
func (builder *Builder) Build() (imageID string, err error) {
	// Do initial cleanup, you know, just to be sure
	// Previous builds could be ended up abnormally
	if err := builder.cleanup(); err != nil {
		return "", err
	}

	// Initialize auth configuration
	if builder.Auth == nil {
		builder.Auth = &docker.AuthConfiguration{}
	}

	// Initialize in/out file descriptors
	if builder.InStream != nil {
		fd, isTerminal := term.GetFdInfo(builder.InStream)
		builder.fdIn = fd
		builder.isTerminalIn = isTerminal
	}
	if builder.OutStream != nil {
		fd, isTerminal := term.GetFdInfo(builder.OutStream)
		builder.fdOut = fd
		builder.isTerminalOut = isTerminal
	}

	// Wrap this into function to have deferred functions run before
	// we do final checks
	run := func() (err error) {
		fd, err := os.Open(builder.Rockerfile)
		if err != nil {
			return fmt.Errorf("Failed to open file %s, error: %s", builder.Rockerfile, err)
		}
		defer fd.Close()

		data, err := template.Process(builder.Rockerfile, fd, builder.Vars.ToMapOfInterface(), map[string]interface{}{})
		if err != nil {
			return err
		}
		builder.RockerfileContent = data.String()

		if builder.Print {
			fmt.Print(builder.RockerfileContent)
			os.Exit(0)
		}

		if builder.ContextDir == "" {
			builder.ContextDir = filepath.Dir(builder.Rockerfile)
		}

		if _, err := os.Stat(builder.ContextDir); err != nil {
			return err
		}

		if err := builder.checkDockerignore(); err != nil {
			return err
		}

		rootNode, err := parser.Parse(strings.NewReader(builder.RockerfileContent))
		if err != nil {
			return err
		}

		builder.rootNode = rootNode
		builder.dockerfile = &parser.Node{}

		defer func() {
			if err2 := builder.cleanup(); err2 != nil && err == nil {
				err = err2
			}
		}()

		for builder.i = 0; builder.i < len(builder.rootNode.Children); builder.i++ {
			oldImageID := builder.imageID

			if err := builder.dispatch(builder.i, builder.rootNode.Children[builder.i]); err != nil {
				return err
			}

			if builder.imageID != oldImageID && builder.imageID != "" {
				fmt.Fprintf(builder.OutStream, "[Rocker]  ---> %.12s\n", builder.imageID)
			}
		}

		if err := builder.runDockerfile(); err != nil {
			return err
		}

		return nil
	}

	if err := run(); err != nil {
		return "", err
	}

	if builder.imageID == "" {
		return "", fmt.Errorf("No image was generated. Is your Rockerfile empty?")
	}

	fmt.Fprintf(builder.OutStream, "[Rocker] Successfully built %.12s\n", builder.imageID)

	return builder.imageID, nil
}