func readPassword(prompt string) (password string, err error) { if acceptPasswordFromStdin && !term.IsTerminal(os.Stdin) { _, err = fmt.Scanln(&password) return } // NOTE: speakeasy may not support multi-byte chars on Windows return speakeasy.Ask("Enter password: ") }
func runLog(cmd *Command, args []string) { if len(args) != 0 { cmd.printUsage() os.Exit(2) } opts := heroku.LogSessionCreateOpts{} if dyno != "" { opts.Dyno = &dyno } if source != "" { opts.Source = &source } if lines != -1 { opts.Lines = &lines } else { tailopt := true lineopt := 10 opts.Tail = &tailopt opts.Lines = &lineopt } session, err := client.LogSessionCreate(mustApp(), &opts) if err != nil { log.Fatal(err) } resp, err := http.Get(session.LogplexURL) if err != nil { log.Fatal(err) } if resp.StatusCode/100 != 2 { if resp.StatusCode/100 == 4 { log.Fatal("Unauthorized") } else { log.Fatal("Unexpected error: " + resp.Status) } } writer := LineWriter(WriterAdapter{os.Stdout}) if term.IsTerminal(os.Stdout) { writer = newColorizer(writer) } scanner := bufio.NewScanner(resp.Body) scanner.Split(bufio.ScanLines) for scanner.Scan() { if _, err = writer.Writeln(scanner.Text()); err != nil { log.Fatal(err) } } resp.Body.Close() }
func mustConfirm(warning, desired string) { if term.IsTerminal(os.Stdin) { printWarning(warning) fmt.Printf("> ") } var confirm string if _, err := fmt.Scanln(&confirm); err != nil { printFatal(err.Error()) } if confirm != desired { printFatal("Confirmation did not match %q.", desired) } }
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) { 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, 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 main() { log.SetFlags(0) // make sure command is specified, disallow global args args := os.Args[1:] if len(args) < 1 || strings.IndexRune(args[0], '-') == 0 { usage() } // Run the update command as early as possible to avoid the possibility of // installations being stranded without updates due to errors in other code if args[0] == cmdUpdate.Name() { cmdUpdate.Run(cmdUpdate, args) return } else if updater != nil { defer updater.backgroundRun() // doesn't run if os.Exit is called } if !term.IsTerminal(os.Stdout) { ansi.DisableColors(true) } initClients() for _, cmd := range commands { if cmd.Name() == args[0] && cmd.Run != nil { cmd.Flag.Usage = func() { cmd.printUsage() } if cmd.NeedsApp { cmd.Flag.StringVar(&flagApp, "a", "", "app name") } if err := cmd.Flag.Parse(args[1:]); err != nil { os.Exit(2) } if flagApp != "" { if gitRemoteApp, err := appFromGitRemote(flagApp); err == nil { flagApp = gitRemoteApp } } if cmd.NeedsApp { if a, _ := app(); a == "" { log.Println("no app specified") cmd.printUsage() os.Exit(2) } } cmd.Run(cmd, cmd.Flag.Args()) return } } path := findPlugin(args[0]) if path == "" { fmt.Fprintf(os.Stderr, "Unknown command: %s\n", args[0]) if g := suggest(args[0]); len(g) > 0 { fmt.Fprintf(os.Stderr, "Possible alternatives: %v\n", strings.Join(g, " ")) } fmt.Fprintf(os.Stderr, "Run 'hk help' for usage.\n") os.Exit(2) } err := execPlugin(path, args) printError("exec error: %s", 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) } }