github.com/hashicorp/packer@v1.14.3/helper/wrappedreadline/wrappedreadline.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 // STOLEN SHAMELESSLY FROM THE TERRAFORM REPO BECAUSE VENDORING OUT 5 // WRAPPEDREADLINE AND WRAPPEDSTREAMS FELT LIKE TOO MUCH WORK. 6 // 7 // "a little copying is better than a lot of dependency" 8 // 9 // wrappedreadline is a package that has helpers for interacting with 10 // readline from a panicwrap executable. 11 // 12 // panicwrap overrides the standard file descriptors so that the child process 13 // no longer looks like a TTY. The helpers here access the extra file descriptors 14 // passed by panicwrap to fix that. 15 // 16 // panicwrap should be checked for with panicwrap.Wrapped before using this 17 // library, since this library won't adapt if the binary is not wrapped. 18 package wrappedreadline 19 20 import ( 21 "runtime" 22 23 "github.com/chzyer/readline" 24 25 "github.com/hashicorp/packer/helper/wrappedstreams" 26 ) 27 28 // Override overrides the values in readline.Config that need to be 29 // set with wrapped values. 30 func Override(cfg *readline.Config) *readline.Config { 31 cfg.Stdin = wrappedstreams.Stdin() 32 cfg.Stdout = wrappedstreams.Stdout() 33 cfg.Stderr = wrappedstreams.Stderr() 34 35 cfg.FuncGetWidth = TerminalWidth 36 cfg.FuncIsTerminal = IsTerminal 37 38 rm := RawMode{StdinFd: int(wrappedstreams.Stdin().Fd())} 39 cfg.FuncMakeRaw = rm.Enter 40 cfg.FuncExitRaw = rm.Exit 41 42 return cfg 43 } 44 45 // IsTerminal determines if this process is attached to a TTY. 46 func IsTerminal() bool { 47 // Windows is always a terminal 48 if runtime.GOOS == "windows" { 49 return true 50 } 51 52 // Same implementation as readline but with our custom fds 53 return readline.IsTerminal(int(wrappedstreams.Stdin().Fd())) && 54 (readline.IsTerminal(int(wrappedstreams.Stdout().Fd())) || 55 readline.IsTerminal(int(wrappedstreams.Stderr().Fd()))) 56 } 57 58 // TerminalWidth gets the terminal width in characters. 59 func TerminalWidth() int { 60 if runtime.GOOS == "windows" { 61 return readline.GetScreenWidth() 62 } 63 64 return getWidth() 65 } 66 67 // RawMode is a helper for entering and exiting raw mode. 68 type RawMode struct { 69 StdinFd int 70 71 state *readline.State 72 } 73 74 func (r *RawMode) Enter() (err error) { 75 r.state, err = readline.MakeRaw(r.StdinFd) 76 return err 77 } 78 79 func (r *RawMode) Exit() error { 80 if r.state == nil { 81 return nil 82 } 83 84 return readline.Restore(r.StdinFd, r.state) 85 }