summaryrefslogtreecommitdiff
path: root/vendor/github.com/mitchellh/packer/command/meta.go
blob: 187c364a328e680fbbaf31ed1df6b1297e62f5c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package command

import (
	"bufio"
	"flag"
	"fmt"
	"io"

	"github.com/hashicorp/packer/helper/flag-kv"
	"github.com/hashicorp/packer/helper/flag-slice"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template"
)

// FlagSetFlags is an enum to define what flags are present in the
// default FlagSet returned by Meta.FlagSet
type FlagSetFlags uint

const (
	FlagSetNone        FlagSetFlags = 0
	FlagSetBuildFilter FlagSetFlags = 1 << iota
	FlagSetVars
)

// Meta contains the meta-options and functionality that nearly every
// Packer command inherits.
type Meta struct {
	CoreConfig *packer.CoreConfig
	Cache      packer.Cache
	Ui         packer.Ui
	Version    string

	// These are set by command-line flags
	flagBuildExcept []string
	flagBuildOnly   []string
	flagVars        map[string]string
}

// Core returns the core for the given template given the configured
// CoreConfig and user variables on this Meta.
func (m *Meta) Core(tpl *template.Template) (*packer.Core, error) {
	// Copy the config so we don't modify it
	config := *m.CoreConfig
	config.Template = tpl
	config.Variables = m.flagVars

	// Init the core
	core, err := packer.NewCore(&config)
	if err != nil {
		return nil, fmt.Errorf("Error initializing core: %s", err)
	}

	return core, nil
}

// BuildNames returns the list of builds that are in the given core
// that we care about taking into account the only and except flags.
func (m *Meta) BuildNames(c *packer.Core) []string {
	// TODO: test

	// Filter the "only"
	if len(m.flagBuildOnly) > 0 {
		// Build a set of all the available names
		nameSet := make(map[string]struct{})
		for _, n := range c.BuildNames() {
			nameSet[n] = struct{}{}
		}

		// Build our result set which we pre-allocate some sane number
		result := make([]string, 0, len(m.flagBuildOnly))
		for _, n := range m.flagBuildOnly {
			if _, ok := nameSet[n]; ok {
				result = append(result, n)
			}
		}

		return result
	}

	// Filter the "except"
	if len(m.flagBuildExcept) > 0 {
		// Build a set of the things we don't want
		nameSet := make(map[string]struct{})
		for _, n := range m.flagBuildExcept {
			nameSet[n] = struct{}{}
		}

		// Build our result set which is the names of all builds except
		// those in the given set.
		names := c.BuildNames()
		result := make([]string, 0, len(names))
		for _, n := range names {
			if _, ok := nameSet[n]; !ok {
				result = append(result, n)
			}
		}
		return result
	}

	// We care about everything
	return c.BuildNames()
}

// FlagSet returns a FlagSet with the common flags that every
// command implements. The exact behavior of FlagSet can be configured
// using the flags as the second parameter, for example to disable
// build settings on the commands that don't handle builds.
func (m *Meta) FlagSet(n string, fs FlagSetFlags) *flag.FlagSet {
	f := flag.NewFlagSet(n, flag.ContinueOnError)

	// FlagSetBuildFilter tells us to enable the settings for selecting
	// builds we care about.
	if fs&FlagSetBuildFilter != 0 {
		f.Var((*sliceflag.StringFlag)(&m.flagBuildExcept), "except", "")
		f.Var((*sliceflag.StringFlag)(&m.flagBuildOnly), "only", "")
	}

	// FlagSetVars tells us what variables to use
	if fs&FlagSetVars != 0 {
		f.Var((*kvflag.Flag)(&m.flagVars), "var", "")
		f.Var((*kvflag.FlagJSON)(&m.flagVars), "var-file", "")
	}
	if len(m.flagVars) == 0 {
		m.flagVars = make(map[string]string)
	}

	// Create an io.Writer that writes to our Ui properly for errors.
	// This is kind of a hack, but it does the job. Basically: create
	// a pipe, use a scanner to break it into lines, and output each line
	// to the UI. Do this forever.
	errR, errW := io.Pipe()
	errScanner := bufio.NewScanner(errR)
	go func() {
		for errScanner.Scan() {
			m.Ui.Error(errScanner.Text())
		}
	}()
	f.SetOutput(errW)

	return f
}

// ValidateFlags should be called after parsing flags to validate the
// given flags
func (m *Meta) ValidateFlags() error {
	// TODO
	return nil
}