forked from redhat-developer/odo
/
validators.go
128 lines (105 loc) · 3.63 KB
/
validators.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package validation
import (
"fmt"
"github.com/openshift/odo/pkg/util"
"gopkg.in/AlecAivazis/survey.v1"
"strconv"
"strings"
)
// NameValidator provides a Validator view of the ValidateName function.
func NameValidator(name interface{}) error {
if s, ok := name.(string); ok {
return ValidateName(s)
}
return fmt.Errorf("can only validate strings, got %v", name)
}
// Validator is a function that validates that the provided interface conforms to expectations or return an error
type Validator func(interface{}) error
// NilValidator always validates
func NilValidator(interface{}) error { return nil }
// IntegerValidator validates that the provided object can be properly converted to an int value
func IntegerValidator(ans interface{}) error {
if _, ok := ans.(int); ok {
return nil
}
if s, ok := ans.(string); ok {
_, err := strconv.Atoi(s)
if err != nil {
return fmt.Errorf("invalid integer value '%s': %s", s, err)
}
return nil
}
return fmt.Errorf("don't know how to convert %v into an integer", ans)
}
// PathValidator validates whether the given path exists on the file system
func PathValidator(path interface{}) error {
if s, ok := path.(string); ok {
exists := util.CheckPathExists(s)
if exists {
return nil
}
return fmt.Errorf("path '%s' does not exist on the file system", s)
}
return fmt.Errorf("can only validate strings, got %v", path)
}
// PortsValidator validates whether all the parts of the input are valid port declarations
// examples of valid input are:
// 8080
// 8080, 9090/udp
// 8080/tcp, 9090/udp
func PortsValidator(portsStr interface{}) error {
if s, ok := portsStr.(string); ok {
_, err := util.GetContainerPortsFromStrings(util.GetSplitValuesFromStr(s))
if err != nil {
return err
}
return nil
}
return fmt.Errorf("can only validate strings, got %v", portsStr)
}
// KeyEqValFormatValidator ensures that all the parts of the input follow the key=value format
// examples of valid input are:
// NAME=JANE
// PORT=8080,PATH=/health
func KeyEqValFormatValidator(portsStr interface{}) error {
if s, ok := portsStr.(string); ok {
parts := util.GetSplitValuesFromStr(s)
for _, part := range parts {
kvParts := strings.Split(part, "=")
if len(kvParts) != 2 {
return fmt.Errorf("Part '%s' does not have the correct format", part)
}
if len(strings.TrimSpace(kvParts[0])) != len(kvParts[0]) ||
len(strings.TrimSpace(kvParts[1])) != len(kvParts[1]) {
return fmt.Errorf("Spaces are not allowed in '%s'", part)
}
}
return nil
}
return fmt.Errorf("can only validate strings, got %v", portsStr)
}
// GetValidatorFor retrieves a validator for the specified validatable, first validating its required state, then its value
// based on type then any additional validators in the order specified by Validatable.AdditionalValidators
func GetValidatorFor(prop Validatable) Validator {
v, _ := internalGetValidatorFor(prop)
return v
}
// internalGetValidatorFor exposed for testing purposes
func internalGetValidatorFor(prop Validatable) (validator Validator, chain []survey.Validator) {
// make sure we don't run into issues when composing validators
validatorChain := make([]survey.Validator, 0, 5)
if prop.Required {
validatorChain = append(validatorChain, survey.Required)
}
switch prop.Type {
case "integer":
validatorChain = append(validatorChain, survey.Validator(IntegerValidator))
}
for i := range prop.AdditionalValidators {
validatorChain = append(validatorChain, survey.Validator(prop.AdditionalValidators[i]))
}
if len(validatorChain) > 0 {
return Validator(survey.ComposeValidators(validatorChain...)), validatorChain
}
return NilValidator, validatorChain
}