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  }