mirror of https://github.com/docker/cli.git
Add expanded mount syntax to Compose schema and types.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
3b8ecc089b
commit
d2d48f3f69
File diff suppressed because one or more lines are too long
|
@ -235,7 +235,37 @@
|
||||||
},
|
},
|
||||||
"user": {"type": "string"},
|
"user": {"type": "string"},
|
||||||
"userns_mode": {"type": "string"},
|
"userns_mode": {"type": "string"},
|
||||||
"volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
"volumes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"oneOf": [
|
||||||
|
{"type": "string"},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"required": ["type"],
|
||||||
|
"properties": {
|
||||||
|
"type": {"type": "string"},
|
||||||
|
"source": {"type": "string"},
|
||||||
|
"target": {"type": "string"},
|
||||||
|
"read_only": {"type": "boolean"},
|
||||||
|
"bind": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"propagation": {"type": "string"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"volume": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"nocopy": {"type": "boolean"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"working_dir": {"type": "string"}
|
"working_dir": {"type": "string"}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
|
|
@ -78,18 +78,22 @@ func Validate(config map[string]interface{}, version string) error {
|
||||||
|
|
||||||
func toError(result *gojsonschema.Result) error {
|
func toError(result *gojsonschema.Result) error {
|
||||||
err := getMostSpecificError(result.Errors())
|
err := getMostSpecificError(result.Errors())
|
||||||
description := getDescription(err)
|
return err
|
||||||
return fmt.Errorf("%s %s", err.Field(), description)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDescription(err gojsonschema.ResultError) string {
|
func getDescription(err validationError) string {
|
||||||
if err.Type() == "invalid_type" {
|
switch err.parent.Type() {
|
||||||
if expectedType, ok := err.Details()["expected"].(string); ok {
|
case "invalid_type":
|
||||||
|
if expectedType, ok := err.parent.Details()["expected"].(string); ok {
|
||||||
return fmt.Sprintf("must be a %s", humanReadableType(expectedType))
|
return fmt.Sprintf("must be a %s", humanReadableType(expectedType))
|
||||||
}
|
}
|
||||||
|
case "number_one_of", "number_any_of":
|
||||||
|
if err.child == nil {
|
||||||
|
return err.parent.Description()
|
||||||
}
|
}
|
||||||
|
return err.child.Description()
|
||||||
return err.Description()
|
}
|
||||||
|
return err.parent.Description()
|
||||||
}
|
}
|
||||||
|
|
||||||
func humanReadableType(definition string) string {
|
func humanReadableType(definition string) string {
|
||||||
|
@ -113,23 +117,45 @@ func humanReadableType(definition string) string {
|
||||||
return definition
|
return definition
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMostSpecificError(errors []gojsonschema.ResultError) gojsonschema.ResultError {
|
type validationError struct {
|
||||||
var mostSpecificError gojsonschema.ResultError
|
parent gojsonschema.ResultError
|
||||||
|
child gojsonschema.ResultError
|
||||||
|
}
|
||||||
|
|
||||||
for _, err := range errors {
|
func (err validationError) Error() string {
|
||||||
if mostSpecificError == nil {
|
description := getDescription(err)
|
||||||
mostSpecificError = err
|
return fmt.Sprintf("%s %s", err.parent.Field(), description)
|
||||||
} else if specificity(err) > specificity(mostSpecificError) {
|
}
|
||||||
mostSpecificError = err
|
|
||||||
} else if specificity(err) == specificity(mostSpecificError) {
|
func getMostSpecificError(errors []gojsonschema.ResultError) validationError {
|
||||||
|
mostSpecificError := 0
|
||||||
|
for i, err := range errors {
|
||||||
|
if specificity(err) > specificity(errors[mostSpecificError]) {
|
||||||
|
mostSpecificError = i
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if specificity(err) == specificity(errors[mostSpecificError]) {
|
||||||
// Invalid type errors win in a tie-breaker for most specific field name
|
// Invalid type errors win in a tie-breaker for most specific field name
|
||||||
if err.Type() == "invalid_type" && mostSpecificError.Type() != "invalid_type" {
|
if err.Type() == "invalid_type" && errors[mostSpecificError].Type() != "invalid_type" {
|
||||||
mostSpecificError = err
|
mostSpecificError = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mostSpecificError
|
if mostSpecificError+1 == len(errors) {
|
||||||
|
return validationError{parent: errors[mostSpecificError]}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch errors[mostSpecificError].Type() {
|
||||||
|
case "number_one_of", "number_any_of":
|
||||||
|
return validationError{
|
||||||
|
parent: errors[mostSpecificError],
|
||||||
|
child: errors[mostSpecificError+1],
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return validationError{parent: errors[mostSpecificError]}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func specificity(err gojsonschema.ResultError) int {
|
func specificity(err gojsonschema.ResultError) int {
|
||||||
|
|
|
@ -119,7 +119,7 @@ type ServiceConfig struct {
|
||||||
Tty bool `mapstructure:"tty"`
|
Tty bool `mapstructure:"tty"`
|
||||||
Ulimits map[string]*UlimitsConfig
|
Ulimits map[string]*UlimitsConfig
|
||||||
User string
|
User string
|
||||||
Volumes []string
|
Volumes []ServiceVolumeConfig
|
||||||
WorkingDir string `mapstructure:"working_dir"`
|
WorkingDir string `mapstructure:"working_dir"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,6 +223,26 @@ type ServicePortConfig struct {
|
||||||
Protocol string
|
Protocol string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServiceVolumeConfig are references to a volume used by a service
|
||||||
|
type ServiceVolumeConfig struct {
|
||||||
|
Type string
|
||||||
|
Source string
|
||||||
|
Target string
|
||||||
|
ReadOnly string `mapstructure:"read_only"`
|
||||||
|
Bind *ServiceVolumeBind
|
||||||
|
Volume *ServiceVolumeVolume
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceVolumeBind are options for a service volume of type bind
|
||||||
|
type ServiceVolumeBind struct {
|
||||||
|
Propogation string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceVolumeVolume are options for a service volume of type volume
|
||||||
|
type ServiceVolumeVolume struct {
|
||||||
|
NoCopy bool `mapstructure:"nocopy"`
|
||||||
|
}
|
||||||
|
|
||||||
// ServiceSecretConfig is the secret configuration for a service
|
// ServiceSecretConfig is the secret configuration for a service
|
||||||
type ServiceSecretConfig struct {
|
type ServiceSecretConfig struct {
|
||||||
Source string
|
Source string
|
||||||
|
|
Loading…
Reference in New Issue