func runDeploy(cmd *Command, args []string) { r, w := io.Pipe() if len(args) < 1 { printFatal("You must specify an image to deploy") } image := args[0] message := getMessage() form := &PostDeployForm{Image: image} var endpoint string appName, _ := app() if appName != "" { endpoint = fmt.Sprintf("/apps/%s/deploys", appName) } else { endpoint = "/deploys" } rh := heroku.RequestHeaders{CommitMessage: message} go func() { must(client.PostWithHeaders(w, endpoint, form, rh.Headers())) must(w.Close()) }() outFd, isTerminalOut := term.GetFdInfo(os.Stdout) must(jsonmessage.DisplayJSONMessagesStream(r, os.Stdout, outFd, isTerminalOut)) }
func runRun(cmd *Command, args []string) { if len(args) == 0 { cmd.PrintUsage() os.Exit(2) } appname := mustApp() message := getMessage() w, err := term.GetWinsize(inFd) if err != nil { // If syscall.TIOCGWINSZ is not supported by the device, we're // probably trying to run tests. Set w to some sensible default. if err.Error() == "operation not supported by device" { w = &term.Winsize{ Height: 20, Width: 80, } } else { printFatal(err.Error()) } } attached := !detachedRun opts := heroku.DynoCreateOpts{Attach: &attached, Message: message} if attached { env := map[string]string{ "COLUMNS": strconv.Itoa(int(w.Width)), "LINES": strconv.Itoa(int(w.Height)), "TERM": os.Getenv("TERM"), } opts.Env = &env } if dynoSize != "" { opts.Size = &dynoSize } command := strings.Join(args, " ") if detachedRun { dyno, err := client.DynoCreate(appname, command, &opts) must(err) log.Printf("Ran `%s` on %s as %s, detached.", dyno.Command, appname, dyno.Name) return } params := struct { Command string `json:"command"` Attach *bool `json:"attach,omitempty"` Env *map[string]string `json:"env,omitempty"` Size *string `json:"size,omitempty"` }{ Command: command, Attach: opts.Attach, Env: opts.Env, Size: opts.Size, } rh := heroku.RequestHeaders{CommitMessage: message} req, err := client.NewRequest("POST", "/apps/"+appname+"/dynos", params, rh.Headers()) must(err) u, err := url.Parse(apiURL) must(err) proto, address := dialParams(u) var dial net.Conn if proto == "tls" { dial, err = tlsDial("tcp", address, &tls.Config{}) if err != nil { printFatal(err.Error()) } } else { dial, err = net.Dial(proto, address) if err != nil { printFatal(err.Error()) } } clientconn := httputil.NewClientConn(dial, nil) defer clientconn.Close() res, err := clientconn.Do(req) defer res.Body.Close() if err = heroku.CheckResp(res); err != nil { printFatal(err.Error()) } if err != nil && err != httputil.ErrPersistEOF { printFatal(err.Error()) } rwc, br := clientconn.Hijack() defer rwc.Close() if isTerminalIn && isTerminalOut { state, err := term.SetRawTerminal(inFd) if err != nil { printFatal(err.Error()) } defer term.RestoreTerminal(inFd, state) } errChanOut := make(chan error, 1) errChanIn := make(chan error, 1) exit := make(chan bool) go func() { defer close(exit) defer close(errChanOut) var err error _, err = io.Copy(os.Stdout, br) errChanOut <- err }() go func() { _, err := io.Copy(rwc, os.Stdin) errChanIn <- err rwc.(interface { CloseWrite() error }).CloseWrite() }() <-exit select { case err = <-errChanIn: must(err) case err = <-errChanOut: must(err) } }