// printStatus pretty prints a status message func printStatus(L *lua.LState) int { w, _, err := terminal.GetSize(int(os.Stdout.Fd())) if err != nil { emit("Unable to get terminal size: %v", err) return 0 } reset := "\033[0m" red := "\033[31m" green := "\033[32m" blue := "\033[34m" status := fmt.Sprintf("[%vudef%v]", blue, reset) ok := fmt.Sprintf("[ %vok%v ]", green, reset) fail := fmt.Sprintf("[%vfail%v]", red, reset) switch L.Get(2).Type() { case lua.LTBool: status = fail if L.ToBool(2) { status = ok } case lua.LTNumber: status = fail if L.ToInt(2) == 0 { status = ok } } message := L.ToString(1) fmt.Printf("%v%v%v\n", message, strings.Repeat(" ", w-len(message)-len(status)+len(reset)+len(red)-1), status) return 0 }
func (cmd CmdCheck) newReadProgress(todo restic.Stat) *restic.Progress { if !cmd.global.ShowProgress() { return nil } readProgress := restic.NewProgress(time.Second) readProgress.OnUpdate = func(s restic.Stat, d time.Duration, ticker bool) { status := fmt.Sprintf("[%s] %s %d / %d items", formatDuration(d), formatPercent(s.Blobs, todo.Blobs), s.Blobs, todo.Blobs) w, _, err := terminal.GetSize(int(os.Stdout.Fd())) if err == nil { if len(status) > w { max := w - len(status) - 4 status = status[:max] + "... " } } fmt.Printf("\x1b[2K%s\r", status) } readProgress.OnDone = func(s restic.Stat, d time.Duration, ticker bool) { fmt.Printf("\nduration: %s\n", formatDuration(d)) } return readProgress }
func runAttached(c *cli.Context, app, ps, args, release string) (int, error) { fd := os.Stdin.Fd() var w, h int if terminal.IsTerminal(int(fd)) { stdinState, err := terminal.GetState(int(fd)) if err != nil { return -1, err } defer terminal.Restore(int(fd), stdinState) w, h, err = terminal.GetSize(int(fd)) if err != nil { return -1, err } } code, err := rackClient(c).RunProcessAttached(app, ps, args, release, h, w, os.Stdin, os.Stdout) if err != nil { return -1, err } return code, nil }
func (p *pullProgress) SetProgress(cur, max int, msg string) { cols, _, err := terminal.GetSize(0) if err != nil { format := fmt.Sprintf("%%%dd", len(fmt.Sprintf("%d", max))) fmt.Printf(format+"/%d %s\n", cur, max, msg) } else { if p.first { p.first = false } else if p.verbose { fmt.Printf("\x1b[2A\x1b[K%s\n", p.lastmsg) } else { fmt.Print("\x1b[2A") } percent := fmt.Sprintf("%d%%", 100*cur/max) ratio := fmt.Sprintf("%d/%d", cur, max) progresssize := cols - len(percent) - 2 psz1 := progresssize * cur / max psz2 := progresssize - psz1 progress := strings.Repeat("#", psz1) + strings.Repeat("-", psz2) msglen := cols - len(ratio) - 2 if len(msg) > msglen { msg = msg[:msglen] } p.lastmsg = fmt.Sprintf("%s %s", ratio, msg) fmt.Printf("\x1b[K%s %s\n\x1b[K%s\n", percent, progress, p.lastmsg) } }
// newProgressMax returns a progress that counts blobs. func newProgressMax(show bool, max uint64, description string) *restic.Progress { if !show { return nil } p := restic.NewProgress() p.OnUpdate = func(s restic.Stat, d time.Duration, ticker bool) { status := fmt.Sprintf("[%s] %s %d / %d %s", formatDuration(d), formatPercent(s.Blobs, max), s.Blobs, max, description) w, _, err := terminal.GetSize(int(os.Stdout.Fd())) if err == nil { if len(status) > w { max := w - len(status) - 4 status = status[:max] + "... " } } PrintProgress("%s", status) } p.OnDone = func(s restic.Stat, d time.Duration, ticker bool) { fmt.Printf("\n") } return p }
func (t *Table) String() string { if t.Headers == nil && len(t.rows) < 1 { return "" } var ttyWidth int terminalFd := int(os.Stdout.Fd()) if os.Getenv("TSURU_FORCE_WRAP") != "" { terminalFd = int(os.Stdin.Fd()) } if terminal.IsTerminal(terminalFd) { ttyWidth, _, _ = terminal.GetSize(terminalFd) } sizes := t.resizeLastColumn(ttyWidth) result := t.separator() if t.Headers != nil { for column, header := range t.Headers { result += "| " + header result += strings.Repeat(" ", sizes[column]+1-len(header)) } result += "|\n" result += t.separator() } result = t.addRows(t.rows, sizes, result) if !t.LineSeparator { result += t.separator() } return result }
func newReadProgress(gopts GlobalOptions, todo restic.Stat) *restic.Progress { if gopts.Quiet { return nil } readProgress := restic.NewProgress() readProgress.OnUpdate = func(s restic.Stat, d time.Duration, ticker bool) { status := fmt.Sprintf("[%s] %s %d / %d items", formatDuration(d), formatPercent(s.Blobs, todo.Blobs), s.Blobs, todo.Blobs) w, _, err := terminal.GetSize(int(os.Stdout.Fd())) if err == nil { if len(status) > w { max := w - len(status) - 4 status = status[:max] + "... " } } PrintProgress("%s", status) } readProgress.OnDone = func(s restic.Stat, d time.Duration, ticker bool) { fmt.Printf("\nduration: %s\n", formatDuration(d)) } return readProgress }
func sendTermSize(control *websocket.Conn) error { width, height, err := terminal.GetSize(int(syscall.Stdout)) if err != nil { return err } shared.Debugf("Window size is now: %dx%d", width, height) w, err := control.NextWriter(websocket.TextMessage) if err != nil { return err } msg := shared.ContainerExecControl{} msg.Command = "window-resize" msg.Args = make(map[string]string) msg.Args["width"] = strconv.Itoa(width) msg.Args["height"] = strconv.Itoa(height) buf, err := json.Marshal(msg) if err != nil { return err } _, err = w.Write(buf) w.Close() return err }
func updateTerminalSize(term *terminal.Terminal) { width, height, err := terminal.GetSize(0) if err != nil { return } term.SetSize(width, height) }
func GetSize() (int, int, error) { w, h, err := terminal.GetSize(int(os.Stdout.Fd())) if err != nil { return -1, -1, err } return w, h, nil }
func (client NativeClient) OutputWithPty(command string) (string, error) { session, err := client.session(command) if err != nil { return "", nil } fd := int(os.Stdin.Fd()) termWidth, termHeight, err := terminal.GetSize(fd) if err != nil { return "", err } modes := ssh.TerminalModes{ ssh.ECHO: 0, ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_OSPEED: 14400, } // request tty -- fixes error with hosts that use // "Defaults requiretty" in /etc/sudoers - I'm looking at you RedHat if err := session.RequestPty("xterm", termHeight, termWidth, modes); err != nil { return "", err } output, err := session.CombinedOutput(command) defer session.Close() return string(output), err }
func connect(ip string, creds server.Credentials) error { config := &ssh.ClientConfig{ User: creds.Username, Auth: []ssh.AuthMethod{ ssh.Password(creds.Password), }, } conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:22", ip), config) if err != nil { return err } defer conn.Close() // Create a session session, err := conn.NewSession() defer session.Close() if err != nil { return err } fd := int(os.Stdin.Fd()) oldState, err := terminal.MakeRaw(fd) if err != nil { return err } termWidth, termHeight, err := terminal.GetSize(fd) defer terminal.Restore(fd, oldState) if err != nil { return err } session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin modes := ssh.TerminalModes{ ssh.ECHO: 1, // disable echoing ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } // Request pseudo terminal if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil { return err } // Start remote shell if err := session.Shell(); err != nil { return err } if err := session.Wait(); err != nil { if reflect.TypeOf(err) == reflect.TypeOf(&ssh.ExitError{}) { return nil } else { return err } } return nil }
func client(user, passwd, ip string) { config := &ssh.ClientConfig{ User: user, Auth: []ssh.AuthMethod{ ssh.Password(passwd), }, } client, err := ssh.Dial("tcp", ip, config) if err != nil { fmt.Println("建立连接: ", err) return } defer client.Close() session, err := client.NewSession() if err != nil { fmt.Println("创建Session出错: ", err) return } defer session.Close() fd := int(os.Stdin.Fd()) oldState, err := terminal.MakeRaw(fd) if err != nil { fmt.Println("创建文件描述符: ", err) return } session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin termWidth, termHeight, err := terminal.GetSize(fd) if err != nil { fmt.Println("获取窗口宽高: ", err) return } defer terminal.Restore(fd, oldState) modes := ssh.TerminalModes{ ssh.ECHO: 1, ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_OSPEED: 14400, } if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil { fmt.Println("创建终端出错: ", err) return } err = session.Shell() if err != nil { fmt.Println("执行Shell出错: ", err) return } err = session.Wait() if err != nil { fmt.Println("执行Wait出错: ", err) return } }
func newArchiveProgress(gopts GlobalOptions, todo restic.Stat) *restic.Progress { if gopts.Quiet { return nil } archiveProgress := restic.NewProgress() var bps, eta uint64 itemsTodo := todo.Files + todo.Dirs archiveProgress.OnUpdate = func(s restic.Stat, d time.Duration, ticker bool) { if IsProcessBackground() { return } sec := uint64(d / time.Second) if todo.Bytes > 0 && sec > 0 && ticker { bps = s.Bytes / sec if s.Bytes >= todo.Bytes { eta = 0 } else if bps > 0 { eta = (todo.Bytes - s.Bytes) / bps } } itemsDone := s.Files + s.Dirs status1 := fmt.Sprintf("[%s] %s %s/s %s / %s %d / %d items %d errors ", formatDuration(d), formatPercent(s.Bytes, todo.Bytes), formatBytes(bps), formatBytes(s.Bytes), formatBytes(todo.Bytes), itemsDone, itemsTodo, s.Errors) status2 := fmt.Sprintf("ETA %s ", formatSeconds(eta)) w, _, err := terminal.GetSize(int(os.Stdout.Fd())) if err == nil { maxlen := w - len(status2) - 1 if maxlen < 4 { status1 = "" } else if len(status1) > maxlen { status1 = status1[:maxlen-4] status1 += "... " } } PrintProgress("%s%s", status1, status2) } archiveProgress.OnDone = func(s restic.Stat, d time.Duration, ticker bool) { fmt.Printf("\nduration: %s, %s\n", formatDuration(d), formatRate(todo.Bytes, d)) } return archiveProgress }
func (r *LightRenderer) updateTerminalSize() { width, height, err := terminal.GetSize(r.fd()) if err == nil { r.width = width r.height = r.maxHeightFunc(height) } else { r.width = getEnv("COLUMNS", defaultWidth) r.height = r.maxHeightFunc(getEnv("LINES", defaultHeight)) } }
// ClearLine creates a platform dependent string to clear the current // line, so it can be overwritten. ANSI sequences are not supported on // current windows cmd shell. func ClearLine() string { if runtime.GOOS == "windows" { w, _, err := terminal.GetSize(int(os.Stdout.Fd())) if err == nil { return strings.Repeat(" ", w-1) + "\r" } return "" } return "\x1b[2K" }
func displayJSONMessagesStream(in io.Reader, out io.Writer) (string, error) { var ( dec = json.NewDecoder(in) ids = map[string]int{} diff = 0 fd = getFd(out) isTerminal = terminal.IsTerminal(fd) message = "" ) //oldState, err := terminal.MakeRaw(fd) //if err == nil { // defer terminal.Restore(fd, oldState) //} terminalWidth, terminalHeight, _ = terminal.GetSize(fd) for { var jm JSONMessage if err := dec.Decode(&jm); err != nil { if err == io.EOF { break } return "", err } if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") { line, ok := ids[jm.ID] if !ok { line = len(ids) ids[jm.ID] = line if isTerminal { fmt.Fprintf(out, "\n") } diff = 0 } else { diff = len(ids) - line } if jm.ID != "" && isTerminal { // <ESC>[{diff}A = move cursor up diff rows fmt.Fprintf(out, "%c[%dA", 27, diff) } } var err error message, err = jm.Display(out, isTerminal) if jm.ID != "" && isTerminal { // <ESC>[{diff}B = move cursor down diff rows fmt.Fprintf(out, "%c[%dB", 27, diff) } if err != nil { return "", err } } return message, nil }
func (c *Common) height() int { if c.Height > 0 { return c.Height } if c.Height < 0 { // use screen height - y if _, h, err := terminal.GetSize(int(os.Stdin.Fd())); err == nil { return h + c.Height } } return DEFAULT_HEIGHT }
func NewTextBuffer() *TextBuffer { w, h, err := terminal.GetSize(int(os.Stdout.Fd())) if err != nil { panic(err) } stdErr.Printf("Dimensions: (%d, %d)", w, h) return &TextBuffer{ cursor: &Cursor{}, width: w, height: h, } }
func (c *Common) width() int { if c.Width > 0 { return c.Width } if c.Width < 0 { // use screen width - x if w, _, err := terminal.GetSize(int(os.Stdin.Fd())); err == nil { return w + c.Width } } return DEFAULT_WIDTH }
func PrintStory(story stories.Story) { cols, _, err := terminal.GetSize(0) if err != nil { cols = 128 } cols -= 3 fmt.Print("NAME: ") fmt.Print(story.Name) fmt.Println() fmt.Print("STATE: ") fmt.Print(story.State) fmt.Println() fmt.Print("OWNER: ") fmt.Print(story.Owner.Initials) fmt.Println() fmt.Println("DESCRIPTION:") fmt.Println(story.Description) fmt.Println() fmt.Print("TYPE: ") fmt.Print(story.StoryType) fmt.Println() fmt.Print("ESTIMATE: ") fmt.Print(story.Points) fmt.Println() fmt.Println("COMMENTS:") for _, comment := range story.Comments { createdTime, timeErr := time.Parse(time.RFC3339, comment.CreatedAt) if timeErr == nil { fmt.Println(createdTime.Local().String()) } else { fmt.Println(comment.CreatedAt) } //fmt.Printf("\t%v\n", strings.Replace(comment.Text[0:int(math.Min(cols-8, float64(len(comment.Text))))], "\n", "\n\t", -1)) fmt.Printf("> %v\n", strings.Replace(comment.Text, "\n", "\n>> ", -1)) fmt.Println() } fmt.Print("LABELS: ") labelNames := []string{} for _, label := range story.Labels { labelNames = append(labelNames, label.Name) } fmt.Println(strings.Join(labelNames, ",")) fmt.Println() }
func (m *MinTerm) open() error { f, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) if err != nil { return err } m.out = f fd := int(m.out.Fd()) w, h, err := terminal.GetSize(fd) if err != nil { return err } m.width, m.height = w, h return nil }
// GetTTYWidth returns the width of controlling TTY if it can or 80. func GetTTYWidth() int { var tty *os.File var err error if tty, err = os.OpenFile("/dev/tty", os.O_RDWR, 0600); err != nil { tty = os.Stdout } else { defer tty.Close() } if width, _, err := terminal.GetSize(int(tty.Fd())); err != nil { return 80 } else { return width - 1 } }
// printSummary prints a diff of charts after upate func printSummary(diff string) { if len(diff) == 0 { log.Msg("Already up-to-date.") return } s := make(repoSummary) // parse git diff-tree for _, line := range strings.Split(diff, "\n") { kv := strings.Split(line, "\t") st, chart := kv[0], kv[1] s.add(st, chart) } // width of columns colwidth := 29 // get console width maxwidth := 118 if w, _, err := terminal.GetSize(int(os.Stdout.Fd())); err == nil { maxwidth = w } // print results for st, charts := range s { switch st { case "A": log.Msg("Added %d charts", len(charts)) case "D": log.Msg("Sent %d charts to the depths", len(charts)) case "M": log.Msg("Updated %d charts", len(charts)) } line := "" for _, ch := range charts { // if adding this column passes the max // print and reset to zero if len(line)+colwidth > maxwidth { log.Msg(line) line = "" } // append to line with padding line = fmt.Sprintf("%s%-29s", line, ch) } log.Msg(line) } }
func (cmd CmdBackup) newArchiveProgress(todo restic.Stat) *restic.Progress { if !cmd.global.ShowProgress() { return nil } archiveProgress := restic.NewProgress(time.Second) var bps, eta uint64 itemsTodo := todo.Files + todo.Dirs archiveProgress.OnUpdate = func(s restic.Stat, d time.Duration, ticker bool) { sec := uint64(d / time.Second) if todo.Bytes > 0 && sec > 0 && ticker { bps = s.Bytes / sec if s.Bytes >= todo.Bytes { eta = 0 } else if bps > 0 { eta = (todo.Bytes - s.Bytes) / bps } } itemsDone := s.Files + s.Dirs status1 := fmt.Sprintf("[%s] %s %s/s %s / %s %d / %d items %d errors ", formatDuration(d), formatPercent(s.Bytes, todo.Bytes), formatBytes(bps), formatBytes(s.Bytes), formatBytes(todo.Bytes), itemsDone, itemsTodo, s.Errors) status2 := fmt.Sprintf("ETA %s ", formatSeconds(eta)) w, _, err := terminal.GetSize(int(os.Stdout.Fd())) if err == nil { if len(status1)+len(status2) > w { max := w - len(status2) - 4 status1 = status1[:max] + "... " } } fmt.Printf("\x1b[2K%s%s\r", status1, status2) } archiveProgress.OnDone = func(s restic.Stat, d time.Duration, ticker bool) { fmt.Printf("\nduration: %s, %s\n", formatDuration(d), formatRate(todo.Bytes, d)) } return archiveProgress }
// makeSession initializes a gossh.Session connected to the invoking process's stdout/stderr/stdout. // If the invoking session is a terminal, a TTY will be requested for the SSH session. // It returns a gossh.Session, a finalizing function used to clean up after the session terminates, // and any error encountered in setting up the session. func makeSession(client *SSHForwardingClient) (session *gossh.Session, finalize func(), err error) { session, err = client.NewSession() if err != nil { return } if err = client.ForwardAgentAuthentication(session); err != nil { return } session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin modes := gossh.TerminalModes{ gossh.ECHO: 1, // enable echoing gossh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud gossh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } fd := int(os.Stdin.Fd()) if terminal.IsTerminal(fd) { var termWidth, termHeight int var oldState *terminal.State oldState, err = terminal.MakeRaw(fd) if err != nil { return } finalize = func() { session.Close() terminal.Restore(fd, oldState) } termWidth, termHeight, err = terminal.GetSize(fd) if err != nil { return } err = session.RequestPty("xterm-256color", termHeight, termWidth, modes) } else { finalize = func() { session.Close() } } return }
// copypaste from oldmain func list(projectID string, accessToken string, include stories.IncludeOptions, style printing.PrintStyle) { _, h, err := terminal.GetSize(0) usePager := (err == nil) if _, err := exec.LookPath("less"); err != nil { usePager = false } // fetch stories numberOfStories := 0 resp, fetcherror := stories.Fetch(projectID, accessToken, include) if fetcherror == nil { storyList := stories.Process(resp) numberOfStories = len(storyList) statusMap := stories.CountStories(storyList) usePager = usePager && (numberOfStories+3) > (h-1) if usePager { //http://stackoverflow.com/questions/21738674/how-do-i-print-a-buffer-to-stdout-piped-through-a-pager cmd := exec.Command("less") // create a pipe (blocking) r, stdin := io.Pipe() // Set your i/o's cmd.Stdin = r cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr c := make(chan struct{}) go func() { defer close(c) cmd.Run() }() printing.PrintStories(stdin, storyList, style) printing.PrintStatusLine(stdin, style, statusMap) stdin.Close() <-c } else { printing.PrintStories(os.Stdout, storyList, style) printing.PrintStatusLine(os.Stdout, style, statusMap) } } else { fmt.Println(fetcherror) panic("fetch error?") } }
func (m *MinTerm) open() error { f, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) if err != nil { return err } m.termIn = f m.termOut = f m.closeTermOut = false // since it's repeated fd := int(f.Fd()) w, h, err := terminal.GetSize(fd) if err != nil { return err } m.width, m.height = w, h return nil }
func listTask(ctx *cli.Context) error { tasks := pClient.GetTasks() termWidth, _, _ := terminal.GetSize(int(os.Stdout.Fd())) verbose := ctx.Bool("verbose") if tasks.Err != nil { return fmt.Errorf("Error getting tasks:\n%v\n", tasks.Err) } w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) if tasks.Len() == 0 { fmt.Println("No task found. Have you created a task?") return nil } printFields(w, false, 0, "ID", "NAME", "STATE", "HIT", "MISS", "FAIL", "CREATED", "LAST FAILURE", ) for _, task := range tasks.ScheduledTasks { //165 is the width of the error message from ID - LAST FAILURE inclusive. //If the header row wraps, then the error message will automatically wrap too if termWidth < 165 { verbose = true } printFields(w, false, 0, task.ID, fixSize(verbose, task.Name, 41), task.State, trunc(task.HitCount), trunc(task.MissCount), trunc(task.FailedCount), task.CreationTime().Format(unionParseFormat), /*153 is the width of the error message from ID up to LAST FAILURE*/ fixSize(verbose, task.LastFailureMessage, termWidth-153), ) } w.Flush() return nil }
func newArchiveStdinProgress(gopts GlobalOptions) *restic.Progress { if gopts.Quiet { return nil } archiveProgress := restic.NewProgress() var bps uint64 archiveProgress.OnUpdate = func(s restic.Stat, d time.Duration, ticker bool) { if IsProcessBackground() { return } sec := uint64(d / time.Second) if s.Bytes > 0 && sec > 0 && ticker { bps = s.Bytes / sec } status1 := fmt.Sprintf("[%s] %s %s/s", formatDuration(d), formatBytes(s.Bytes), formatBytes(bps)) w, _, err := terminal.GetSize(int(os.Stdout.Fd())) if err == nil { maxlen := w - len(status1) if maxlen < 4 { status1 = "" } else if len(status1) > maxlen { status1 = status1[:maxlen-4] status1 += "... " } } PrintProgress("%s", status1) } archiveProgress.OnDone = func(s restic.Stat, d time.Duration, ticker bool) { fmt.Printf("\nduration: %s, %s\n", formatDuration(d), formatRate(s.Bytes, d)) } return archiveProgress }