github.com/dacamp/packer@v0.10.2/provisioner/shell-local/provisioner.go (about)

     1  package shell
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"runtime"
     7  
     8  	"github.com/mitchellh/packer/common"
     9  	"github.com/mitchellh/packer/helper/config"
    10  	"github.com/mitchellh/packer/packer"
    11  	"github.com/mitchellh/packer/template/interpolate"
    12  )
    13  
    14  type Config struct {
    15  	common.PackerConfig `mapstructure:",squash"`
    16  
    17  	// Command is the command to execute
    18  	Command string
    19  
    20  	// ExecuteCommand is the command used to execute the command.
    21  	ExecuteCommand []string `mapstructure:"execute_command"`
    22  
    23  	ctx interpolate.Context
    24  }
    25  
    26  type Provisioner struct {
    27  	config Config
    28  }
    29  
    30  func (p *Provisioner) Prepare(raws ...interface{}) error {
    31  	err := config.Decode(&p.config, &config.DecodeOpts{
    32  		Interpolate:        true,
    33  		InterpolateContext: &p.config.ctx,
    34  		InterpolateFilter: &interpolate.RenderFilter{
    35  			Exclude: []string{
    36  				"execute_command",
    37  			},
    38  		},
    39  	}, raws...)
    40  	if err != nil {
    41  		return err
    42  	}
    43  
    44  	if len(p.config.ExecuteCommand) == 0 {
    45  		if runtime.GOOS == "windows" {
    46  			p.config.ExecuteCommand = []string{
    47  				"cmd",
    48  				"/C",
    49  				"{{.Command}}",
    50  			}
    51  		} else {
    52  			p.config.ExecuteCommand = []string{
    53  				"/bin/sh",
    54  				"-c",
    55  				"{{.Command}}",
    56  			}
    57  		}
    58  	}
    59  
    60  	var errs *packer.MultiError
    61  	if p.config.Command == "" {
    62  		errs = packer.MultiErrorAppend(errs,
    63  			errors.New("command must be specified"))
    64  	}
    65  
    66  	if len(p.config.ExecuteCommand) == 0 {
    67  		errs = packer.MultiErrorAppend(errs,
    68  			errors.New("execute_command must not be empty"))
    69  	}
    70  
    71  	if errs != nil && len(errs.Errors) > 0 {
    72  		return errs
    73  	}
    74  
    75  	return nil
    76  }
    77  
    78  func (p *Provisioner) Provision(ui packer.Ui, _ packer.Communicator) error {
    79  	// Make another communicator for local
    80  	comm := &Communicator{
    81  		Ctx:            p.config.ctx,
    82  		ExecuteCommand: p.config.ExecuteCommand,
    83  	}
    84  
    85  	// Build the remote command
    86  	cmd := &packer.RemoteCmd{Command: p.config.Command}
    87  
    88  	ui.Say(fmt.Sprintf(
    89  		"Executing local command: %s",
    90  		p.config.Command))
    91  	if err := cmd.StartWithUi(comm, ui); err != nil {
    92  		return fmt.Errorf(
    93  			"Error executing command: %s\n\n"+
    94  				"Please see output above for more information.",
    95  			p.config.Command)
    96  	}
    97  	if cmd.ExitStatus != 0 {
    98  		return fmt.Errorf(
    99  			"Erroneous exit code %d while executing command: %s\n\n"+
   100  				"Please see output above for more information.",
   101  			cmd.ExitStatus,
   102  			p.config.Command)
   103  	}
   104  
   105  	return nil
   106  }
   107  
   108  func (p *Provisioner) Cancel() {
   109  	// Just do nothing. When the process ends, so will our provisioner
   110  }