...

Source file src/cuelang.org/go/pkg/tool/cli/cli.go

Documentation: cuelang.org/go/pkg/tool/cli

     1  // Copyright 2019 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cli
    16  
    17  import (
    18  	"bufio"
    19  	"fmt"
    20  	"io"
    21  	"strings"
    22  
    23  	"cuelang.org/go/cue"
    24  	"cuelang.org/go/internal/task"
    25  )
    26  
    27  func init() {
    28  	task.Register("tool/cli.Print", newPrintCmd)
    29  	task.Register("tool/cli.Ask", newAskCmd)
    30  
    31  	// For backwards compatibility.
    32  	task.Register("print", newPrintCmd)
    33  }
    34  
    35  type printCmd struct{}
    36  
    37  func newPrintCmd(v cue.Value) (task.Runner, error) {
    38  	return &printCmd{}, nil
    39  }
    40  
    41  func (c *printCmd) Run(ctx *task.Context) (res interface{}, err error) {
    42  	str := ctx.String("text")
    43  	if ctx.Err != nil {
    44  		return nil, ctx.Err
    45  	}
    46  	fmt.Fprintln(ctx.Stdout, str)
    47  	return nil, nil
    48  }
    49  
    50  type askCmd struct{}
    51  
    52  func newAskCmd(v cue.Value) (task.Runner, error) {
    53  	return &askCmd{}, nil
    54  }
    55  
    56  type oneByteReader struct {
    57  	r io.Reader
    58  }
    59  
    60  func (r *oneByteReader) Read(p []byte) (int, error) {
    61  	if len(p) == 0 {
    62  		return 0, nil
    63  	}
    64  	return r.r.Read(p[:1])
    65  }
    66  
    67  func (c *askCmd) Run(ctx *task.Context) (res interface{}, err error) {
    68  	str := ctx.String("prompt")
    69  	if ctx.Err != nil {
    70  		return nil, ctx.Err
    71  	}
    72  	if str != "" {
    73  		fmt.Fprint(ctx.Stdout, str+" ")
    74  	}
    75  
    76  	// Roger is convinced that bufio.Scanner will only issue as many reads
    77  	// as it needs, so that limiting it to one-byte reads should be enough
    78  	// to not read any bytes after a newline.
    79  	// This behavior is true today but technically not documented,
    80  	// so Roger will send a CL to properly document it.
    81  	//
    82  	// TODO(mvdan): come back to remove this notice once Roger's CL is
    83  	// approved, or to rewrite the code if it is rejected.
    84  	scanner := bufio.NewScanner(&oneByteReader{ctx.Stdin})
    85  	var response string
    86  	if scanner.Scan() {
    87  		response = scanner.Text()
    88  	}
    89  	if err := scanner.Err(); err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	update := map[string]interface{}{"response": response}
    94  
    95  	switch v := ctx.Lookup("response"); v.IncompleteKind() {
    96  	case cue.BoolKind:
    97  		switch strings.ToLower(response) {
    98  		case "yes":
    99  			update["response"] = true
   100  		default:
   101  			update["response"] = false
   102  		}
   103  	case cue.StringKind:
   104  		// already set above
   105  	}
   106  	return update, nil
   107  }
   108  

View as plain text