github.com/blend/go-sdk@v1.20240719.1/cmd/ask/main.go (about)

     1  /*
     2  
     3  Copyright (c) 2024 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package main
     9  
    10  import (
    11  	"bytes"
    12  	"flag"
    13  	"fmt"
    14  	"os"
    15  	"strings"
    16  
    17  	"gopkg.in/yaml.v3"
    18  
    19  	"github.com/blend/go-sdk/sh"
    20  )
    21  
    22  type configVar struct {
    23  	Field   string
    24  	Default string
    25  	Value   string
    26  }
    27  
    28  func (cv *configVar) Set(value string) error {
    29  	cv.Value = value
    30  	return nil
    31  }
    32  
    33  type configVarSet []configVar
    34  
    35  func (cvs configVarSet) String() string {
    36  	return "Fields to prompt for in the form fieldname=default"
    37  }
    38  
    39  func (cvs configVarSet) Union(other configVarSet) configVarSet {
    40  	return append(cvs, other...)
    41  }
    42  
    43  func (cvs *configVarSet) Set(flagValue string) error {
    44  	parts := strings.SplitN(flagValue, "=", 2)
    45  	if len(parts) > 1 {
    46  		*cvs = append(*cvs, configVar{
    47  			Field:   parts[0],
    48  			Default: parts[1],
    49  		})
    50  	} else if len(parts) > 0 {
    51  		*cvs = append(*cvs, configVar{
    52  			Field: parts[0],
    53  		})
    54  	} else {
    55  		return fmt.Errorf("invalid config var: %s", flagValue)
    56  	}
    57  	return nil
    58  }
    59  
    60  func (cvs configVarSet) MarshalYAML() (interface{}, error) {
    61  	output := make(map[string]interface{})
    62  	for _, cv := range cvs {
    63  		if cv.Value != "" {
    64  			output[cv.Field] = cv.Value
    65  		} else {
    66  			output[cv.Field] = cv.Default
    67  		}
    68  	}
    69  	return output, nil
    70  }
    71  
    72  func main() {
    73  	fields := configVarSet{}
    74  	secureFields := configVarSet{}
    75  	output := flag.String("o", "", "The output file")
    76  	flag.Var(&fields, "field", "Fields to prompt for, can be multiple")
    77  	flag.Var(&secureFields, "secure", "Secure Fields to prompt for, can be multiple, will hide input")
    78  	flag.Parse()
    79  
    80  	if len(fields) == 0 && len(secureFields) == 0 {
    81  		fmt.Fprintf(os.Stderr, "please provide at least (1) field or a secure field\n")
    82  		flag.Usage()
    83  	}
    84  
    85  	for index := range fields {
    86  		prompt(&fields[index])
    87  	}
    88  
    89  	for index := range secureFields {
    90  		secure(&secureFields[index])
    91  	}
    92  
    93  	all := fields.Union(secureFields)
    94  	buffer := new(bytes.Buffer)
    95  	if err := yaml.NewEncoder(buffer).Encode(all); err != nil {
    96  		fmt.Fprintf(os.Stderr, "%v", err)
    97  		os.Exit(1)
    98  	}
    99  
   100  	if *output != "" {
   101  		if err := os.WriteFile(*output, buffer.Bytes(), 0644); err != nil {
   102  			fmt.Fprintf(os.Stderr, "%v", err)
   103  			os.Exit(1)
   104  		}
   105  	} else {
   106  		fmt.Fprint(os.Stderr, buffer.String())
   107  	}
   108  }
   109  
   110  func prompt(cv *configVar) {
   111  	if len(cv.Default) > 0 {
   112  		cv.Value = sh.Promptf("%s[%s]: ", cv.Field, cv.Default)
   113  	} else {
   114  		cv.Value = sh.Promptf("%s: ", cv.Field)
   115  	}
   116  }
   117  
   118  func secure(cv *configVar) {
   119  	var prompt string
   120  	if len(cv.Default) > 0 {
   121  		prompt = fmt.Sprintf("%s[%s]: ", cv.Field, cv.Default)
   122  	} else {
   123  		prompt = fmt.Sprintf("%s: ", cv.Field)
   124  	}
   125  	output := sh.MustPassword(prompt)
   126  	cv.Value = output
   127  }