github.com/dacamp/packer@v0.10.2/provisioner/shell-local/communicator.go (about) 1 package shell 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "os/exec" 8 "syscall" 9 10 "github.com/mitchellh/packer/packer" 11 "github.com/mitchellh/packer/template/interpolate" 12 ) 13 14 type Communicator struct { 15 ExecuteCommand []string 16 Ctx interpolate.Context 17 } 18 19 func (c *Communicator) Start(cmd *packer.RemoteCmd) error { 20 // Render the template so that we know how to execute the command 21 c.Ctx.Data = &ExecuteCommandTemplate{ 22 Command: cmd.Command, 23 } 24 for i, field := range c.ExecuteCommand { 25 command, err := interpolate.Render(field, &c.Ctx) 26 if err != nil { 27 return fmt.Errorf("Error processing command: %s", err) 28 } 29 30 c.ExecuteCommand[i] = command 31 } 32 33 // Build the local command to execute 34 localCmd := exec.Command(c.ExecuteCommand[0], c.ExecuteCommand[1:]...) 35 localCmd.Stdin = cmd.Stdin 36 localCmd.Stdout = cmd.Stdout 37 localCmd.Stderr = cmd.Stderr 38 39 // Start it. If it doesn't work, then error right away. 40 if err := localCmd.Start(); err != nil { 41 return err 42 } 43 44 // We've started successfully. Start a goroutine to wait for 45 // it to complete and track exit status. 46 go func() { 47 var exitStatus int 48 err := localCmd.Wait() 49 if err != nil { 50 if exitErr, ok := err.(*exec.ExitError); ok { 51 exitStatus = 1 52 53 // There is no process-independent way to get the REAL 54 // exit status so we just try to go deeper. 55 if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { 56 exitStatus = status.ExitStatus() 57 } 58 } 59 } 60 61 cmd.SetExited(exitStatus) 62 }() 63 64 return nil 65 } 66 67 func (c *Communicator) Upload(string, io.Reader, *os.FileInfo) error { 68 return fmt.Errorf("upload not supported") 69 } 70 71 func (c *Communicator) UploadDir(string, string, []string) error { 72 return fmt.Errorf("uploadDir not supported") 73 } 74 75 func (c *Communicator) Download(string, io.Writer) error { 76 return fmt.Errorf("download not supported") 77 } 78 79 func (c *Communicator) DownloadDir(string, string, []string) error { 80 return fmt.Errorf("downloadDir not supported") 81 } 82 83 type ExecuteCommandTemplate struct { 84 Command string 85 }