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