github.com/emate/packer@v0.8.1-0.20150625195101-fe0fde195dc6/command/meta.go (about)

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