github.phpd.cn/hashicorp/packer@v1.3.2/command/meta.go (about)

     1  package command
     2  
     3  import (
     4  	"bufio"
     5  	"flag"
     6  	"fmt"
     7  	"io"
     8  
     9  	"github.com/hashicorp/packer/helper/flag-kv"
    10  	"github.com/hashicorp/packer/helper/flag-slice"
    11  	"github.com/hashicorp/packer/packer"
    12  	"github.com/hashicorp/packer/template"
    13  )
    14  
    15  // FlagSetFlags is an enum to define what flags are present in the
    16  // default FlagSet returned by Meta.FlagSet
    17  type FlagSetFlags uint
    18  
    19  const (
    20  	FlagSetNone        FlagSetFlags = 0
    21  	FlagSetBuildFilter FlagSetFlags = 1 << iota
    22  	FlagSetVars
    23  )
    24  
    25  // Meta contains the meta-options and functionality that nearly every
    26  // Packer command inherits.
    27  type Meta struct {
    28  	CoreConfig *packer.CoreConfig
    29  	Cache      packer.Cache
    30  	Ui         packer.Ui
    31  	Version    string
    32  
    33  	// These are set by command-line flags
    34  	flagBuildExcept []string
    35  	flagBuildOnly   []string
    36  	flagVars        map[string]string
    37  }
    38  
    39  // Core returns the core for the given template given the configured
    40  // CoreConfig and user variables on this Meta.
    41  func (m *Meta) Core(tpl *template.Template) (*packer.Core, error) {
    42  	// Copy the config so we don't modify it
    43  	config := *m.CoreConfig
    44  	config.Template = tpl
    45  	config.Variables = m.flagVars
    46  
    47  	// Init the core
    48  	core, err := packer.NewCore(&config)
    49  	if err != nil {
    50  		return nil, fmt.Errorf("Error initializing core: %s", err)
    51  	}
    52  
    53  	return core, nil
    54  }
    55  
    56  // BuildNames returns the list of builds that are in the given core
    57  // that we care about taking into account the only and except flags.
    58  func (m *Meta) BuildNames(c *packer.Core) []string {
    59  	// TODO: test
    60  
    61  	// Filter the "only"
    62  	if len(m.flagBuildOnly) > 0 {
    63  		// Build a set of all the available names
    64  		nameSet := make(map[string]struct{})
    65  		for _, n := range c.BuildNames() {
    66  			nameSet[n] = struct{}{}
    67  		}
    68  
    69  		// Build our result set which we pre-allocate some sane number
    70  		result := make([]string, 0, len(m.flagBuildOnly))
    71  		for _, n := range m.flagBuildOnly {
    72  			if _, ok := nameSet[n]; ok {
    73  				result = append(result, n)
    74  			}
    75  		}
    76  
    77  		return result
    78  	}
    79  
    80  	// Filter the "except"
    81  	if len(m.flagBuildExcept) > 0 {
    82  		// Build a set of the things we don't want
    83  		nameSet := make(map[string]struct{})
    84  		for _, n := range m.flagBuildExcept {
    85  			nameSet[n] = struct{}{}
    86  		}
    87  
    88  		// Build our result set which is the names of all builds except
    89  		// those in the given set.
    90  		names := c.BuildNames()
    91  		result := make([]string, 0, len(names))
    92  		for _, n := range names {
    93  			if _, ok := nameSet[n]; !ok {
    94  				result = append(result, n)
    95  			}
    96  		}
    97  		return result
    98  	}
    99  
   100  	// We care about everything
   101  	return c.BuildNames()
   102  }
   103  
   104  // FlagSet returns a FlagSet with the common flags that every
   105  // command implements. The exact behavior of FlagSet can be configured
   106  // using the flags as the second parameter, for example to disable
   107  // build settings on the commands that don't handle builds.
   108  func (m *Meta) FlagSet(n string, fs FlagSetFlags) *flag.FlagSet {
   109  	f := flag.NewFlagSet(n, flag.ContinueOnError)
   110  
   111  	// FlagSetBuildFilter tells us to enable the settings for selecting
   112  	// builds we care about.
   113  	if fs&FlagSetBuildFilter != 0 {
   114  		f.Var((*sliceflag.StringFlag)(&m.flagBuildExcept), "except", "")
   115  		f.Var((*sliceflag.StringFlag)(&m.flagBuildOnly), "only", "")
   116  	}
   117  
   118  	// FlagSetVars tells us what variables to use
   119  	if fs&FlagSetVars != 0 {
   120  		f.Var((*kvflag.Flag)(&m.flagVars), "var", "")
   121  		f.Var((*kvflag.FlagJSON)(&m.flagVars), "var-file", "")
   122  	}
   123  
   124  	// Create an io.Writer that writes to our Ui properly for errors.
   125  	// This is kind of a hack, but it does the job. Basically: create
   126  	// a pipe, use a scanner to break it into lines, and output each line
   127  	// to the UI. Do this forever.
   128  	errR, errW := io.Pipe()
   129  	errScanner := bufio.NewScanner(errR)
   130  	go func() {
   131  		for errScanner.Scan() {
   132  			m.Ui.Error(errScanner.Text())
   133  		}
   134  	}()
   135  	f.SetOutput(errW)
   136  
   137  	return f
   138  }
   139  
   140  // ValidateFlags should be called after parsing flags to validate the
   141  // given flags
   142  func (m *Meta) ValidateFlags() error {
   143  	// TODO
   144  	return nil
   145  }