Skip to content

Commit 4f9f7b8

Browse files
authored
wrapped errors (knative#3375)
1 parent 3837e3a commit 4f9f7b8

File tree

7 files changed

+561
-385
lines changed

7 files changed

+561
-385
lines changed

cmd/build.go

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -158,58 +158,17 @@ func runBuild(cmd *cobra.Command, _ []string, newClient ClientFactory) (err erro
158158
cfg buildConfig
159159
f fn.Function
160160
)
161-
if cfg, err = newBuildConfig().Prompt(); err != nil { // gather values into a single instruction set
162-
// Layer 2: Catch technical errors and provide CLI-specific user-friendly messages
163-
164-
// Check if it's a "not initialized" error (no function found)
165-
var errNotInit *fn.ErrNotInitialized
166-
if errors.As(err, &errNotInit) {
167-
return wrapNotInitializedError(err, "build")
168-
}
169-
170-
// Check if it's a registry required error (function exists but no registry)
171-
if errors.Is(err, fn.ErrRegistryRequired) {
172-
return wrapRegistryRequiredError(err, "build")
173-
}
174-
return
161+
if cfg, err = newBuildConfig().Prompt(); err != nil {
162+
return wrapPromptError(err, "build")
175163
}
176164
if err = cfg.Validate(cmd); err != nil { // Perform any pre-validation
177-
// Layer 2: Catch technical errors and provide CLI-specific user-friendly messages
178-
if errors.Is(err, fn.ErrConflictingImageAndRegistry) {
179-
return fmt.Errorf(`%w
180-
181-
Cannot use both --image and --registry together. Choose one:
182-
183-
Use --image for complete image name:
184-
func build --image example.com/user/myfunc
185-
186-
Use --registry for automatic naming:
187-
func build --registry example.com/user
188-
189-
Note: FUNC_REGISTRY environment variable doesn't conflict with --image flag
190-
191-
For more options, run 'func build --help'`, err)
192-
}
193-
if errors.Is(err, fn.ErrPlatformNotSupported) {
194-
return fmt.Errorf(`%w
195-
196-
The --platform flag is only supported with the S2I builder.
197-
198-
Try this:
199-
func build --registry <registry> --builder=s2i --platform linux/amd64
200-
201-
Or remove the --platform flag:
202-
func build --registry <registry>
203-
204-
For more options, run 'func build --help'`, err)
205-
}
206-
return
165+
return wrapValidateError(err, "build")
207166
}
208167
if f, err = fn.NewFunction(cfg.Path); err != nil { // Read in the Function
209168
return
210169
}
211170
if !f.Initialized() {
212-
return fn.NewErrNotInitialized(f.Root)
171+
return NewErrNotInitializedFromPath(f.Root, "build")
213172
}
214173
f = cfg.Configure(f) // Returns an f updated with values from the config (flags, envs, etc)
215174

cmd/create.go

Lines changed: 50 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -108,31 +108,6 @@ EXAMPLES
108108
fmt.Fprintf(os.Stderr, "unable to provide template suggestions: %v", err)
109109
}
110110

111-
// Detect hyphen-prefixed arguments mis-parsed as flags
112-
cmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
113-
for _, arg := range os.Args[1:] {
114-
if strings.HasPrefix(arg, "--") {
115-
flagName := strings.TrimPrefix(arg, "--")
116-
if cmd.Flags().Lookup(flagName) != nil {
117-
continue
118-
}
119-
if strings.Contains(err.Error(), "unknown flag") && strings.Contains(err.Error(), arg) {
120-
return wrapFlagParsingError(err, arg)
121-
}
122-
} else if strings.HasPrefix(arg, "-") && len(arg) > 1 {
123-
firstChar := string(arg[1])
124-
shortFlag := cmd.Flags().ShorthandLookup(firstChar)
125-
126-
if shortFlag != nil && len(arg) > 2 && strings.Contains(arg, "-") {
127-
return wrapFlagParsingError(err, arg)
128-
} else if strings.Contains(err.Error(), "unknown shorthand flag") && strings.Contains(err.Error(), arg[1:2]) {
129-
return wrapFlagParsingError(err, arg)
130-
}
131-
}
132-
}
133-
return err
134-
})
135-
136111
return cmd
137112
}
138113

@@ -207,6 +182,16 @@ func newCreateConfig(cmd *cobra.Command, args []string, newClient ClientFactory)
207182
absolutePath string
208183
)
209184

185+
// Before Cobra parses flags, lets check for potential that func name was
186+
// given with a hyphen (as flag).
187+
//
188+
// If this were to provide more complexity or unreasonable maintainability
189+
// in the future, we can move to ValidateFunctionName() function which will
190+
// print effectively "Note: func names cant start with '-\..." on errors
191+
if err := detectPrefixHyphen(cmd); err != nil {
192+
return cfg, err
193+
}
194+
210195
pathFlag = viper.GetString("path")
211196

212197
// Default to empty string which deriveNameAndAbsolutePathFromPath
@@ -415,20 +400,11 @@ func newInvalidRuntimeError(client *fn.Client, runtime string) error {
415400
for _, v := range runtimes {
416401
fmt.Fprintf(&b, " %v\n", v)
417402
}
418-
419-
baseErr := ErrInvalidRuntime(errors.New(b.String()))
420-
421-
// Check if runtime value indicates mis-parsed function name
422-
for _, arg := range os.Args[1:] {
423-
if strings.HasPrefix(arg, "-") && len(arg) > 2 && strings.Contains(arg[2:], "-") {
424-
if strings.HasPrefix(arg[2:], runtime) || runtime == strings.TrimPrefix(arg, "-"+string(arg[1])) {
425-
flagChar := string(arg[1])
426-
return wrapFlagParsingErrorWithDetails(baseErr, arg, flagChar, runtime)
427-
}
428-
}
429-
}
430-
431-
return baseErr
403+
// a handy edge case note for something like "func create -ly-func" which
404+
// would parse flag -l with 'y-func' value
405+
fmt.Fprintln(&b, "\nNote: If you meant to specify a function name, "+
406+
"remember that they can't start with a '-'")
407+
return ErrInvalidRuntime(errors.New(b.String()))
432408
}
433409

434410
// newInvalidTemplateError creates an error stating that the given template
@@ -445,20 +421,11 @@ func newInvalidTemplateError(client *fn.Client, runtime, template string) error
445421
for _, v := range templates {
446422
fmt.Fprintf(&b, " %v\n", v)
447423
}
448-
449-
baseErr := ErrInvalidTemplate(errors.New(b.String()))
450-
451-
// Check if template value indicates mis-parsed function name
452-
for _, arg := range os.Args[1:] {
453-
if strings.HasPrefix(arg, "-") && len(arg) > 2 && strings.Contains(arg[2:], "-") {
454-
if strings.HasPrefix(arg[2:], template) || template == strings.TrimPrefix(arg, "-"+string(arg[1])) {
455-
flagChar := string(arg[1])
456-
return wrapFlagParsingErrorWithDetails(baseErr, arg, flagChar, template)
457-
}
458-
}
459-
}
460-
461-
return baseErr
424+
// a handy edge case note for something like "func create -ty-func" which
425+
// would parse flag -t with 'y-func' value
426+
fmt.Fprintln(&b, "\nNote: If you meant to specify a function name, "+
427+
"remember that they can't start with a '-'")
428+
return ErrInvalidTemplate(errors.New(b.String()))
462429
}
463430

464431
// prompt the user with value of config members, allowing for interactively
@@ -648,3 +615,33 @@ func RuntimeTemplateOptions(client *fn.Client) (string, error) {
648615
writer.Flush()
649616
return builder.String(), nil
650617
}
618+
619+
// detectHyphenPrefixedName checks for the possibility of function name being
620+
// given with a leading '-' (which is forbidden) and gives user better error.
621+
func detectPrefixHyphen(cmd *cobra.Command) error {
622+
// using os.Args to skip any possible processing from Cobra
623+
for _, arg := range os.Args[1:] {
624+
if arg == "--" {
625+
continue
626+
}
627+
// skip known long existing flags
628+
if strings.HasPrefix(arg, "--") {
629+
name := strings.SplitN(strings.TrimPrefix(arg, "--"), "=", 2)[0]
630+
if cmd.Flags().Lookup(name) != nil {
631+
continue
632+
}
633+
}
634+
635+
// skip known short existing flags
636+
if len(arg) > 1 && strings.HasPrefix(arg, "-") && arg[1] != '-' {
637+
if cmd.Flags().ShorthandLookup(string(arg[1])) != nil {
638+
continue
639+
}
640+
}
641+
// anything still beginning with '-'
642+
if strings.HasPrefix(arg, "-") {
643+
return fmt.Errorf("'%s' appears to be a function name starting with a hyphen (forbidden). Please start with a lowercase letter", arg)
644+
}
645+
}
646+
return nil
647+
}

0 commit comments

Comments
 (0)