github.com/connyay/libcompose@v0.4.0/config/schema_helpers.go (about) 1 package config 2 3 import ( 4 "encoding/json" 5 "strings" 6 7 "github.com/docker/go-connections/nat" 8 "github.com/xeipuuv/gojsonschema" 9 ) 10 11 var ( 12 schemaLoaderV1 gojsonschema.JSONLoader 13 constraintSchemaLoaderV1 gojsonschema.JSONLoader 14 schemaLoaderV2 gojsonschema.JSONLoader 15 constraintSchemaLoaderV2 gojsonschema.JSONLoader 16 schemaV1 map[string]interface{} 17 schemaV2 map[string]interface{} 18 ) 19 20 type ( 21 environmentFormatChecker struct{} 22 portsFormatChecker struct{} 23 ) 24 25 func (checker environmentFormatChecker) IsFormat(input string) bool { 26 // If the value is a boolean, a warning should be given 27 // However, we can't determine type since gojsonschema converts the value to a string 28 // Adding a function with an interface{} parameter to gojsonschema is probably the best way to handle this 29 return true 30 } 31 32 func (checker portsFormatChecker) IsFormat(input string) bool { 33 _, _, err := nat.ParsePortSpecs([]string{input}) 34 return err == nil 35 } 36 37 func setupSchemaLoaders(schemaData string, schema *map[string]interface{}, schemaLoader, constraintSchemaLoader *gojsonschema.JSONLoader) error { 38 if *schema != nil { 39 return nil 40 } 41 42 var schemaRaw interface{} 43 err := json.Unmarshal([]byte(schemaData), &schemaRaw) 44 if err != nil { 45 return err 46 } 47 48 *schema = schemaRaw.(map[string]interface{}) 49 50 gojsonschema.FormatCheckers.Add("environment", environmentFormatChecker{}) 51 gojsonschema.FormatCheckers.Add("ports", portsFormatChecker{}) 52 gojsonschema.FormatCheckers.Add("expose", portsFormatChecker{}) 53 *schemaLoader = gojsonschema.NewGoLoader(schemaRaw) 54 55 definitions := (*schema)["definitions"].(map[string]interface{}) 56 constraints := definitions["constraints"].(map[string]interface{}) 57 service := constraints["service"].(map[string]interface{}) 58 *constraintSchemaLoader = gojsonschema.NewGoLoader(service) 59 60 return nil 61 } 62 63 // gojsonschema doesn't provide a list of valid types for a property 64 // This parses the schema manually to find all valid types 65 func parseValidTypesFromSchema(schema map[string]interface{}, context string) []string { 66 contextSplit := strings.Split(context, ".") 67 key := contextSplit[len(contextSplit)-1] 68 69 definitions := schema["definitions"].(map[string]interface{}) 70 service := definitions["service"].(map[string]interface{}) 71 properties := service["properties"].(map[string]interface{}) 72 property := properties[key].(map[string]interface{}) 73 74 var validTypes []string 75 76 if val, ok := property["oneOf"]; ok { 77 validConditions := val.([]interface{}) 78 79 for _, validCondition := range validConditions { 80 condition := validCondition.(map[string]interface{}) 81 validTypes = append(validTypes, condition["type"].(string)) 82 } 83 } else if val, ok := property["$ref"]; ok { 84 reference := val.(string) 85 if reference == "#/definitions/string_or_list" { 86 return []string{"string", "array"} 87 } else if reference == "#/definitions/list_of_strings" { 88 return []string{"array"} 89 } else if reference == "#/definitions/list_or_dict" { 90 return []string{"array", "object"} 91 } 92 } 93 94 return validTypes 95 }