Example #1
0
func (i *cliUi) Input(opts *ui.InputOpts) (string, error) {
	// 如何设置了环境变量,我们就不询问提示input
	if value := opts.EnvVarValue(); value != "" {
		return value, nil
	}

	r := i.Reader
	w := i.Writer
	if r == nil {
		r = defaultInputReader
	}
	if w == nil {
		w = defaultInputWriter
	}
	if r == nil {
		r = os.Stdin
	}
	if w == nil {
		w = os.Stdout
	}

	// 确保我们只在第一次询问input.Terraform应该确保这个
	// 但是不会破坏验证
	i.l.Lock()
	defer i.l.Unlock()

	// 如果终止,那么就不询问input
	if i.interrupted {
		return "", errors.New("中断")
	}

	// 监听中断操作,那么就不再询问input
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	defer signal.Stop(sigCh)

	// 格式化询问输出
	var buf bytes.Buffer
	buf.WriteString("[reset]")
	buf.WriteString(fmt.Sprintf("[bold]%s[reset]\n", opts.Query))
	if opts.Description != "" {
		s := bufio.NewScanner(strings.NewReader(opts.Description))
		for s.Scan() {
			buf.WriteString(fmt.Sprintf("   %s\n", s.Text()))
		}
		buf.WriteString("\n")
	}
	if opts.Default != "" {
		buf.WriteString("  [bold]Default:[reset] ")
		buf.WriteString(opts.Default)
		buf.WriteString("\n")
	}
	buf.WriteString("  [bold]输入一个值:[reset] ")

	// 询问用户输入
	if _, err := fmt.Fprint(w, ui.Colorize(buf.String())); err != nil {
		return "", err
	}

	// 监听goroutine输入。这允许我们中断
	result := make(chan string, 1)
	if opts.Hide {
		f, ok := r.(*os.File)
		if !ok {
			return "", fmt.Errorf("必须读取一个文件")
		}

		line, err := password.Read(f)
		if err != nil {
			return "", err
		}
		result <- line
	} else {
		go func() {
			var line string
			if _, err := fmt.Fscanln(r, &line); err != nil {
				log.Printf("[ERR] UIInput扫描错误: %s", err)
			}

			result <- line
		}()
	}

	select {
	case line := <-result:

		fmt.Fprint(w, "\n")

		if line == "" {
			line = opts.Default
		}
		return line, nil

	case <-sigCh:
		// 新起一行
		fmt.Fprintln(w)

		// Mark that we were interrupted so future Ask calls fail.
		i.interrupted = true

		return "", errors.New("中断")
	}
}
Example #2
0
File: ui.go Project: mbrodala/otto
func (i *cliUi) Input(opts *ui.InputOpts) (string, error) {
	// If any of the configured EnvVars are set, we don't ask for input.
	if value := opts.EnvVarValue(); value != "" {
		return value, nil
	}

	r := i.Reader
	w := i.Writer
	if r == nil {
		r = defaultInputReader
	}
	if w == nil {
		w = defaultInputWriter
	}
	if r == nil {
		r = os.Stdin
	}
	if w == nil {
		w = os.Stdout
	}

	// Make sure we only ask for input once at a time. Terraform
	// should enforce this, but it doesn't hurt to verify.
	i.l.Lock()
	defer i.l.Unlock()

	// If we're interrupted, then don't ask for input
	if i.interrupted {
		return "", errors.New("interrupted")
	}

	// Listen for interrupts so we can cancel the input ask
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)
	defer signal.Stop(sigCh)

	// Build the output format for asking
	var buf bytes.Buffer
	buf.WriteString("[reset]")
	buf.WriteString(fmt.Sprintf("[bold]%s[reset]\n", opts.Query))
	if opts.Description != "" {
		s := bufio.NewScanner(strings.NewReader(opts.Description))
		for s.Scan() {
			buf.WriteString(fmt.Sprintf("  %s\n", s.Text()))
		}
		buf.WriteString("\n")
	}
	if opts.Default != "" {
		buf.WriteString("  [bold]Default:[reset] ")
		buf.WriteString(opts.Default)
		buf.WriteString("\n")
	}
	buf.WriteString("  [bold]Enter a value:[reset] ")

	// Ask the user for their input
	if _, err := fmt.Fprint(w, ui.Colorize(buf.String())); err != nil {
		return "", err
	}

	// Listen for the input in a goroutine. This will allow us to
	// interrupt this if we are interrupted (SIGINT)
	result := make(chan string, 1)
	if opts.Hide {
		f, ok := r.(*os.File)
		if !ok {
			return "", fmt.Errorf("reader must be a file")
		}

		line, err := password.Read(f)
		if err != nil {
			return "", err
		}

		result <- line
	} else {
		go func() {
			var line string
			if _, err := fmt.Fscanln(r, &line); err != nil {
				log.Printf("[ERR] UIInput scan err: %s", err)
			}

			result <- line
		}()
	}

	select {
	case line := <-result:
		fmt.Fprint(w, "\n")

		if line == "" {
			line = opts.Default
		}

		return line, nil
	case <-sigCh:
		// Print a newline so that any further output starts properly
		// on a new line.
		fmt.Fprintln(w)

		// Mark that we were interrupted so future Ask calls fail.
		i.interrupted = true

		return "", errors.New("interrupted")
	}
}