func (p *Pty) resize(f *os.File) { var rows, cols int if terminal.IsTerminal(int(p.Stdout.Fd())) { rows, cols, _ = p.Size() } else { rows = 24 cols = 80 } ptyx.Setsize(f, rows, cols) }
func (p *Pty) Record(command string, stdoutCopy io.Writer) error { // start command in pty cmd := exec.Command("sh", "-c", command) cmd.Env = append(os.Environ(), "ASCIINEMA_REC=1") master, err := pty.Start(cmd) if err != nil { return err } defer master.Close() // install WINCH signal handler signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGWINCH) defer signal.Stop(signals) go func() { for _ = range signals { p.resize(master) } }() defer close(signals) // put stdin in raw mode (if it's a tty) fd := p.Stdin.Fd() if terminal.IsTerminal(int(fd)) { oldState, err := raw.MakeRaw(fd) if err != nil { return err } defer raw.TcSetAttr(fd, oldState) } // do initial resize p.resize(master) // start stdin -> master copying stop := util.Copy(master, p.Stdin) // copy pty master -> p.stdout & stdoutCopy stdout := io.MultiWriter(p.Stdout, stdoutCopy) stdoutWaitChan := make(chan struct{}) go func() { io.Copy(stdout, master) stdoutWaitChan <- struct{}{} }() // wait for the process to exit and reap it cmd.Wait() // wait for master -> stdout copying to finish // // sometimes after process exits reading from master blocks forever (race condition?) // we're using timeout here to overcome this problem select { case <-stdoutWaitChan: case <-time.After(200 * time.Millisecond): } // stop stdin -> master copying stop() return nil }