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  }