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 }