func runRun(cmd *Command, args []string) { if len(args) == 0 { cmd.PrintUsage() os.Exit(2) } appname := mustApp() cols, err := term.Cols() if err != nil { printFatal(err.Error()) } lines, err := term.Lines() if err != nil { printFatal(err.Error()) } attached := !detachedRun opts := heroku.DynoCreateOpts{Attach: &attached} if attached { env := map[string]string{ "COLUMNS": strconv.Itoa(cols), "LINES": strconv.Itoa(lines), "TERM": os.Getenv("TERM"), } opts.Env = &env } if dynoSize != "" { if !strings.HasSuffix(dynoSize, "X") { cmd.PrintUsage() os.Exit(2) } opts.Size = &dynoSize } command := strings.Join(args, " ") dyno, err := client.DynoCreate(appname, command, &opts) must(err) if detachedRun { log.Printf("Ran `%s` on %s as %s, detached.", dyno.Command, appname, dyno.Name) return } log.Printf("Running `%s` on %s as %s:", dyno.Command, appname, dyno.Name) u, err := url.Parse(*dyno.AttachURL) if err != nil { printFatal(err.Error()) } cn, err := tls.Dial("tcp", u.Host, nil) if err != nil { printFatal(err.Error()) } defer cn.Close() br := bufio.NewReader(cn) _, err = io.WriteString(cn, u.Path[1:]+"\r\n") if err != nil { printFatal(err.Error()) } for { _, pre, err := br.ReadLine() if err != nil { printFatal(err.Error()) } if !pre { break } } if term.IsTerminal(os.Stdin) && term.IsTerminal(os.Stdout) { err = term.MakeRaw(os.Stdin) if err != nil { printFatal(err.Error()) } defer term.Restore(os.Stdin) sig := make(chan os.Signal) signal.Notify(sig, os.Signal(syscall.SIGQUIT), os.Interrupt) go func() { defer term.Restore(os.Stdin) for sg := range sig { switch sg { case os.Interrupt: cn.Write([]byte{3}) case os.Signal(syscall.SIGQUIT): cn.Write([]byte{28}) default: panic("not reached") } } }() } errc := make(chan error) cp := func(a io.Writer, b io.Reader) { _, err := io.Copy(a, b) errc <- err } go cp(os.Stdout, br) go cp(cn, os.Stdin) if err = <-errc; err != nil { printFatal(err.Error()) } }
func runRun(cmd *Command, args []string, client *controller.Client) error { if len(args) == 0 { cmd.printUsage(true) } if runRelease == "" { release, err := client.GetAppRelease(mustApp()) if err == controller.ErrNotFound { return errors.New("No app release, specify a release with -release") } if err != nil { return err } runRelease = release.ID } req := &ct.NewJob{ Cmd: args, TTY: term.IsTerminal(os.Stdin) && term.IsTerminal(os.Stdout) && !runDetached, ReleaseID: runRelease, } if req.TTY { cols, err := term.Cols() if err != nil { return err } lines, err := term.Lines() if err != nil { return err } req.Columns = cols req.Lines = lines req.Env = map[string]string{ "COLUMNS": strconv.Itoa(cols), "LINES": strconv.Itoa(lines), "TERM": os.Getenv("TERM"), } } if runDetached { job, err := client.RunJobDetached(mustApp(), req) if err != nil { return err } log.Println(job.ID) return nil } rwc, err := client.RunJobAttached(mustApp(), req) if err != nil { return err } defer rwc.Close() if req.TTY { if err := term.MakeRaw(os.Stdin); err != nil { return err } defer term.Restore(os.Stdin) } go func() { io.Copy(rwc, os.Stdin) rwc.CloseWrite() }() if req.TTY { _, err = io.Copy(os.Stdout, rwc) } else { err = demultiplex.Copy(os.Stdout, os.Stderr, rwc) } // TODO: get exit code and use it return err }
func runRun(cmd *Command, args []string) { cols, err := term.Cols() if err != nil { log.Fatal(err) } lines, err := term.Lines() if err != nil { log.Fatal(err) } data := make(map[string]interface{}) data["command"] = strings.Join(args, " ") if !detachedRun { data["attach"] = true data["env"] = map[string]interface{}{ "COLUMNS": strconv.Itoa(cols), "LINES": strconv.Itoa(lines), "TERM": os.Getenv("TERM"), } } resp := struct { Url *string `json:"attach_url,omitempty"` }{} must(Post(&resp, "/apps/"+mustApp()+"/dynos", data)) if detachedRun { return } u, err := url.Parse(*resp.Url) if err != nil { log.Fatal(err) } cn, err := tls.Dial("tcp", u.Host, nil) if err != nil { log.Fatal(err) } defer cn.Close() br := bufio.NewReader(cn) _, err = io.WriteString(cn, u.Path[1:]+"\r\n") if err != nil { log.Fatal(err) } for { _, pre, err := br.ReadLine() if err != nil { log.Fatal(err) } if !pre { break } } if term.IsTerminal(os.Stdin) && term.IsTerminal(os.Stdout) { err = term.MakeRaw(os.Stdin) if err != nil { log.Fatal(err) } defer term.Restore(os.Stdin) sig := make(chan os.Signal) signal.Notify(sig, os.Signal(syscall.SIGQUIT), os.Interrupt) go func() { defer term.Restore(os.Stdin) for sg := range sig { switch sg { case os.Interrupt: cn.Write([]byte{3}) case os.Signal(syscall.SIGQUIT): cn.Write([]byte{28}) default: panic("not reached") } } }() } errc := make(chan error) cp := func(a io.Writer, b io.Reader) { _, err := io.Copy(a, b) errc <- err } go cp(os.Stdout, br) go cp(cn, os.Stdin) if err = <-errc; err != nil { log.Fatal(err) } }
func runRun(cmd *Command, args []string) { req := &newJob{ Cmd: args, TTY: term.IsTerminal(os.Stdin) && term.IsTerminal(os.Stdout) && !detachedRun, Attach: !detachedRun, } if req.TTY { cols, err := term.Cols() if err != nil { log.Fatal(err) } lines, err := term.Lines() if err != nil { log.Fatal(err) } req.Columns = cols req.Lines = lines req.Env = map[string]string{ "COLUMNS": strconv.Itoa(cols), "LINES": strconv.Itoa(lines), "TERM": os.Getenv("TERM"), } } path := "/apps/" + mustApp() + "/jobs" if detachedRun { must(Post(nil, path, req)) return } data, err := json.Marshal(req) if err != nil { log.Fatal(err) } httpReq, err := http.NewRequest("POST", path, bytes.NewBuffer(data)) if err != nil { log.Fatal(err) } c, err := net.Dial("tcp", apiURL[7:]) if err != nil { log.Fatal(err) } defer c.Close() clientconn := httputil.NewClientConn(c, nil) res, err := clientconn.Do(httpReq) if err != nil { log.Fatal(err) } if res.StatusCode != 200 { log.Fatalf("Expected 200, got %d", res.StatusCode) } conn, bufr := clientconn.Hijack() if req.TTY { if err := term.MakeRaw(os.Stdin); err != nil { log.Fatal(err) } defer term.Restore(os.Stdin) } errc := make(chan error) go func() { buf := make([]byte, bufr.Buffered()) bufr.Read(buf) os.Stdout.Write(buf) _, err := io.Copy(os.Stdout, conn) errc <- err }() if _, err := io.Copy(conn, os.Stdin); err != nil { log.Fatal(err) } if err := <-errc; err != nil { log.Fatal(err) } }