get.porter.sh/porter@v1.3.0/pkg/generator/generator.go (about)

     1  package generator
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  
     8  	"get.porter.sh/porter/pkg/secrets"
     9  	"github.com/cnabio/cnab-go/secrets/host"
    10  	survey "gopkg.in/AlecAivazis/survey.v1"
    11  )
    12  
    13  // GenerateOptions are the options to generate a parameter or credential set
    14  type GenerateOptions struct {
    15  	// Name of the parameter or credential set.
    16  	Name      string
    17  	Namespace string
    18  	Labels    map[string]string
    19  
    20  	// Should we survey?
    21  	Silent bool
    22  }
    23  
    24  // SurveyType indicates whether the survey is for a parameter or credential
    25  type SurveyType string
    26  
    27  const (
    28  	surveyCredentials SurveyType = "credential"
    29  	surveyParameters  SurveyType = "parameter"
    30  
    31  	questionSecret      = "secret"
    32  	questionValue       = "specific value"
    33  	questionEnvVar      = "environment variable"
    34  	questionPath        = "file path"
    35  	questionCommand     = "shell command"
    36  	questionSkip        = "skip"
    37  	surveryFormatString = "%s %s %q\n%s"
    38  	surveyPrefix        = "How would you like to set"
    39  )
    40  
    41  type surveyOptions struct {
    42  	required    bool
    43  	description string
    44  }
    45  
    46  type surveyOption func(*surveyOptions)
    47  
    48  func withDescription(description string) surveyOption {
    49  	return func(s *surveyOptions) {
    50  		s.description = formatDescriptionForSurvey(description)
    51  	}
    52  }
    53  
    54  func withRequired(required bool) surveyOption {
    55  	return func(s *surveyOptions) {
    56  		s.required = required
    57  	}
    58  }
    59  
    60  type generator func(name string, surveyType SurveyType, opts ...surveyOption) (secrets.SourceMap, error)
    61  
    62  func genEmptySet(name string, surveyType SurveyType, opts ...surveyOption) (secrets.SourceMap, error) {
    63  	return secrets.SourceMap{
    64  		Name:   name,
    65  		Source: secrets.Source{Hint: "TODO"},
    66  	}, nil
    67  }
    68  
    69  func formatDescriptionForSurvey(description string) string {
    70  	if description != "" {
    71  		description = description + "\n"
    72  	}
    73  	return description
    74  }
    75  
    76  func buildSurveySelect(name string, surveyType SurveyType, opts ...surveyOption) *survey.Select {
    77  	surveyOptions := &surveyOptions{}
    78  	for _, opt := range opts {
    79  		opt(surveyOptions)
    80  	}
    81  
    82  	selectOptions := []string{questionSecret, questionValue, questionEnvVar, questionPath, questionCommand}
    83  	if !surveyOptions.required {
    84  		selectOptions = append(selectOptions, questionSkip)
    85  	}
    86  
    87  	// extra space-suffix to align question and answer. Unfortunately misaligns help text
    88  	return &survey.Select{
    89  		Message: fmt.Sprintf(surveryFormatString, surveyPrefix, surveyType, name, surveyOptions.description),
    90  		Options: selectOptions,
    91  		Default: "environment variable",
    92  	}
    93  
    94  }
    95  
    96  func genSurvey(name string, surveyType SurveyType, opts ...surveyOption) (secrets.SourceMap, error) {
    97  	if surveyType != surveyCredentials && surveyType != surveyParameters {
    98  		return secrets.SourceMap{}, fmt.Errorf("unsupported survey type: %s", surveyType)
    99  	}
   100  
   101  	// extra space-suffix to align question and answer. Unfortunately misaligns help text
   102  	sourceTypePrompt := buildSurveySelect(name, surveyType, opts...)
   103  
   104  	// extra space-suffix to align question and answer. Unfortunately misaligns help text
   105  	sourceValuePromptTemplate := "Enter the %s that will be used to set %s %q\n "
   106  
   107  	c := secrets.SourceMap{Name: name}
   108  
   109  	source := ""
   110  	if err := survey.AskOne(sourceTypePrompt, &source, nil); err != nil {
   111  		return c, err
   112  	}
   113  
   114  	promptMsg := ""
   115  	switch source {
   116  	case questionSecret:
   117  		promptMsg = fmt.Sprintf(sourceValuePromptTemplate, "secret", surveyType, name)
   118  	case questionValue:
   119  		promptMsg = fmt.Sprintf(sourceValuePromptTemplate, "value", surveyType, name)
   120  	case questionEnvVar:
   121  		promptMsg = fmt.Sprintf(sourceValuePromptTemplate, "environment variable", surveyType, name)
   122  	case questionPath:
   123  		promptMsg = fmt.Sprintf(sourceValuePromptTemplate, "path", surveyType, name)
   124  	case questionCommand:
   125  		promptMsg = fmt.Sprintf(sourceValuePromptTemplate, "command", surveyType, name)
   126  	case questionSkip:
   127  		promptMsg = fmt.Sprintf(sourceValuePromptTemplate, "skip", surveyType, name)
   128  	}
   129  
   130  	if source == questionSkip {
   131  		return secrets.SourceMap{}, nil
   132  	}
   133  
   134  	sourceValuePrompt := &survey.Input{
   135  		Message: promptMsg,
   136  	}
   137  
   138  	value := ""
   139  	if err := survey.AskOne(sourceValuePrompt, &value, nil); err != nil {
   140  		return c, err
   141  	}
   142  	value, err := checkUserHomeDir(value)
   143  	if err != nil {
   144  		return c, err
   145  	}
   146  	switch source {
   147  	case questionSecret:
   148  		c.Source.Strategy = secrets.SourceSecret
   149  		c.Source.Hint = value
   150  	case questionValue:
   151  		c.Source.Strategy = host.SourceValue
   152  		c.Source.Hint = value
   153  	case questionEnvVar:
   154  		c.Source.Strategy = host.SourceEnv
   155  		c.Source.Hint = value
   156  	case questionPath:
   157  		c.Source.Strategy = host.SourcePath
   158  		c.Source.Hint = value
   159  	case questionCommand:
   160  		c.Source.Strategy = host.SourceCommand
   161  		c.Source.Hint = value
   162  	}
   163  	return c, nil
   164  }
   165  
   166  func checkUserHomeDir(value string) (string, error) {
   167  	home, err := os.UserHomeDir()
   168  	if err != nil {
   169  		return "", err
   170  	}
   171  	if strings.HasPrefix(value, "~/") {
   172  		return strings.Replace(value, "~/", home+"/", 1), nil
   173  	}
   174  	return value, nil
   175  }