vendor: update compose-go to v1.20.0

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2023-10-21 08:29:01 +02:00
parent be4fd7110d
commit 05a0fdf744
20 changed files with 605 additions and 303 deletions

View File

@ -20,6 +20,7 @@ import (
"context"
"fmt"
"path/filepath"
"reflect"
"github.com/compose-spec/compose-go/dotenv"
interp "github.com/compose-spec/compose-go/interpolation"
@ -109,37 +110,55 @@ func loadInclude(ctx context.Context, filename string, configDetails types.Confi
func importResources(model *types.Config, imported *types.Project, path []string) error {
services := mapByName(model.Services)
for _, service := range imported.Services {
if _, ok := services[service.Name]; ok {
if present, ok := services[service.Name]; ok {
if reflect.DeepEqual(present, service) {
continue
}
return fmt.Errorf("imported compose file %s defines conflicting service %s", path, service.Name)
}
model.Services = append(model.Services, service)
}
for _, service := range imported.DisabledServices {
if _, ok := services[service.Name]; ok {
if disabled, ok := services[service.Name]; ok {
if reflect.DeepEqual(disabled, service) {
continue
}
return fmt.Errorf("imported compose file %s defines conflicting service %s", path, service.Name)
}
model.Services = append(model.Services, service)
}
for n, network := range imported.Networks {
if _, ok := model.Networks[n]; ok {
if present, ok := model.Networks[n]; ok {
if reflect.DeepEqual(present, network) {
continue
}
return fmt.Errorf("imported compose file %s defines conflicting network %s", path, n)
}
model.Networks[n] = network
}
for n, volume := range imported.Volumes {
if _, ok := model.Volumes[n]; ok {
if present, ok := model.Volumes[n]; ok {
if reflect.DeepEqual(present, volume) {
continue
}
return fmt.Errorf("imported compose file %s defines conflicting volume %s", path, n)
}
model.Volumes[n] = volume
}
for n, secret := range imported.Secrets {
if _, ok := model.Secrets[n]; ok {
if present, ok := model.Secrets[n]; ok {
if reflect.DeepEqual(present, secret) {
continue
}
return fmt.Errorf("imported compose file %s defines conflicting secret %s", path, n)
}
model.Secrets[n] = secret
}
for n, config := range imported.Configs {
if _, ok := model.Configs[n]; ok {
if present, ok := model.Configs[n]; ok {
if reflect.DeepEqual(present, config) {
continue
}
return fmt.Errorf("imported compose file %s defines conflicting config %s", path, n)
}
model.Configs[n] = config

View File

@ -46,10 +46,6 @@ var interpolateTypeCastMapping = map[tree.Path]interp.Cast{
servicePath("deploy", "placement", "max_replicas_per_node"): toInt,
servicePath("healthcheck", "retries"): toInt,
servicePath("healthcheck", "disable"): toBoolean,
servicePath("mem_limit"): toUnitBytes,
servicePath("mem_reservation"): toUnitBytes,
servicePath("memswap_limit"): toUnitBytes,
servicePath("mem_swappiness"): toUnitBytes,
servicePath("oom_kill_disable"): toBoolean,
servicePath("oom_score_adj"): toInt64,
servicePath("pids_limit"): toInt64,
@ -58,16 +54,13 @@ var interpolateTypeCastMapping = map[tree.Path]interp.Cast{
servicePath("read_only"): toBoolean,
servicePath("scale"): toInt,
servicePath("secrets", tree.PathMatchList, "mode"): toInt,
servicePath("shm_size"): toUnitBytes,
servicePath("stdin_open"): toBoolean,
servicePath("stop_grace_period"): toDuration,
servicePath("tty"): toBoolean,
servicePath("ulimits", tree.PathMatchAll): toInt,
servicePath("ulimits", tree.PathMatchAll, "hard"): toInt,
servicePath("ulimits", tree.PathMatchAll, "soft"): toInt,
servicePath("volumes", tree.PathMatchList, "read_only"): toBoolean,
servicePath("volumes", tree.PathMatchList, "volume", "nocopy"): toBoolean,
servicePath("volumes", tree.PathMatchList, "tmpfs", "size"): toUnitBytes,
iPath("networks", tree.PathMatchAll, "external"): toBoolean,
iPath("networks", tree.PathMatchAll, "internal"): toBoolean,
iPath("networks", tree.PathMatchAll, "attachable"): toBoolean,
@ -93,14 +86,6 @@ func toInt64(value string) (interface{}, error) {
return strconv.ParseInt(value, 10, 64)
}
func toUnitBytes(value string) (interface{}, error) {
return transformSize(value)
}
func toDuration(value string) (interface{}, error) {
return transformStringToDuration(value)
}
func toFloat(value string) (interface{}, error) {
return strconv.ParseFloat(value, 64)
}

View File

@ -28,15 +28,12 @@ import (
"regexp"
"strconv"
"strings"
"time"
"github.com/compose-spec/compose-go/consts"
interp "github.com/compose-spec/compose-go/interpolation"
"github.com/compose-spec/compose-go/schema"
"github.com/compose-spec/compose-go/template"
"github.com/compose-spec/compose-go/types"
"github.com/docker/go-units"
"github.com/mattn/go-shellwords"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -241,6 +238,15 @@ func LoadWithContext(ctx context.Context, configDetails types.ConfigDetails, opt
return nil, err
}
opts.projectName = projectName
// TODO(milas): this should probably ALWAYS set (overriding any existing)
if _, ok := configDetails.Environment[consts.ComposeProjectName]; !ok && projectName != "" {
if configDetails.Environment == nil {
configDetails.Environment = map[string]string{}
}
configDetails.Environment[consts.ComposeProjectName] = projectName
}
return load(ctx, configDetails, opts, nil)
}
@ -464,10 +470,6 @@ func projectName(details types.ConfigDetails, opts *Options) (string, error) {
return "", InvalidProjectNameErr(projectName)
}
// TODO(milas): this should probably ALWAYS set (overriding any existing)
if _, ok := details.Environment[consts.ComposeProjectName]; !ok && projectName != "" {
details.Environment[consts.ComposeProjectName] = projectName
}
return projectName, nil
}
@ -586,7 +588,7 @@ func Transform(source interface{}, target interface{}, additionalTransformers ..
config := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.ComposeDecodeHookFunc(
createTransformHook(additionalTransformers...),
mapstructure.StringToTimeDurationHookFunc()),
decoderHook),
Result: target,
TagName: "yaml",
Metadata: &data,
@ -610,28 +612,20 @@ type Transformer struct {
func createTransformHook(additionalTransformers ...Transformer) mapstructure.DecodeHookFuncType {
transforms := map[reflect.Type]func(interface{}) (interface{}, error){
reflect.TypeOf(types.External{}): transformExternal,
reflect.TypeOf(types.HealthCheckTest{}): transformHealthCheckTest,
reflect.TypeOf(types.ShellCommand{}): transformShellCommand,
reflect.TypeOf(types.StringList{}): transformStringList,
reflect.TypeOf(map[string]string{}): transformMapStringString,
reflect.TypeOf(types.Options{}): transformOptions,
reflect.TypeOf(types.UlimitsConfig{}): transformUlimits,
reflect.TypeOf(types.UnitBytes(0)): transformSize,
reflect.TypeOf([]types.ServicePortConfig{}): transformServicePort,
reflect.TypeOf(types.ServiceSecretConfig{}): transformFileReferenceConfig,
reflect.TypeOf(types.ServiceConfigObjConfig{}): transformFileReferenceConfig,
reflect.TypeOf(types.StringOrNumberList{}): transformStringOrNumberList,
reflect.TypeOf(map[string]*types.ServiceNetworkConfig{}): transformServiceNetworkMap,
reflect.TypeOf(types.Mapping{}): transformMappingOrListFunc("=", false),
reflect.TypeOf(types.MappingWithEquals{}): transformMappingOrListFunc("=", true),
reflect.TypeOf(types.Labels{}): transformMappingOrListFunc("=", false),
reflect.TypeOf(types.MappingWithColon{}): transformMappingOrListFunc(":", false),
reflect.TypeOf(types.HostsList{}): transformMappingOrListFunc(":", false),
reflect.TypeOf(types.ServiceVolumeConfig{}): transformServiceVolumeConfig,
reflect.TypeOf(types.BuildConfig{}): transformBuildConfig,
reflect.TypeOf(types.Duration(0)): transformStringToDuration,
reflect.TypeOf(types.DependsOnConfig{}): transformDependsOnConfig,
reflect.TypeOf(types.ExtendsConfig{}): transformExtendsConfig,
reflect.TypeOf(types.DeviceRequest{}): transformServiceDeviceRequest,
reflect.TypeOf(types.SSHConfig{}): transformSSHConfig,
reflect.TypeOf(types.IncludeConfig{}): transformIncludeConfig,
}
@ -1031,7 +1025,7 @@ func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfi
return obj, nil
}
var transformMapStringString TransformerFunc = func(data interface{}) (interface{}, error) {
var transformOptions TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case map[string]interface{}:
return toMapStringString(value, false), nil
@ -1094,35 +1088,6 @@ var transformServicePort TransformerFunc = func(data interface{}) (interface{},
}
}
var transformServiceDeviceRequest TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case map[string]interface{}:
count, ok := value["count"]
if ok {
switch val := count.(type) {
case int:
return value, nil
case string:
if strings.ToLower(val) == "all" {
value["count"] = -1
return value, nil
}
i, err := strconv.ParseInt(val, 10, 64)
if err == nil {
value["count"] = i
return value, nil
}
return data, errors.Errorf("invalid string value for 'count' (the only value allowed is 'all' or a number)")
default:
return data, errors.Errorf("invalid type %T for device count", val)
}
}
return data, nil
default:
return data, errors.Errorf("invalid type %T for resource reservation", value)
}
}
var transformFileReferenceConfig TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case string:
@ -1258,26 +1223,6 @@ func ParseShortSSHSyntax(value string) ([]types.SSHKey, error) {
return result, nil
}
var transformStringOrNumberList TransformerFunc = func(value interface{}) (interface{}, error) {
list := value.([]interface{})
result := make([]string, len(list))
for i, item := range list {
result[i] = fmt.Sprint(item)
}
return result, nil
}
var transformStringList TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case string:
return []string{value}, nil
case []interface{}:
return value, nil
default:
return data, errors.Errorf("invalid type %T for string list", value)
}
}
func transformMappingOrListFunc(sep string, allowNil bool) TransformerFunc {
return func(data interface{}) (interface{}, error) {
return transformMappingOrList(data, sep, allowNil)
@ -1312,52 +1257,6 @@ func transformValueToMapEntry(value string, separator string, allowNil bool) (st
}
}
var transformShellCommand TransformerFunc = func(value interface{}) (interface{}, error) {
if str, ok := value.(string); ok {
return shellwords.Parse(str)
}
return value, nil
}
var transformHealthCheckTest TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case string:
return append([]string{"CMD-SHELL"}, value), nil
case []interface{}:
return value, nil
default:
return value, errors.Errorf("invalid type %T for healthcheck.test", value)
}
}
var transformSize TransformerFunc = func(value interface{}) (interface{}, error) {
switch value := value.(type) {
case int:
return int64(value), nil
case int64, types.UnitBytes:
return value, nil
case string:
return units.RAMInBytes(value)
default:
return value, errors.Errorf("invalid type for size %T", value)
}
}
var transformStringToDuration TransformerFunc = func(value interface{}) (interface{}, error) {
switch value := value.(type) {
case string:
d, err := time.ParseDuration(value)
if err != nil {
return value, err
}
return types.Duration(d), nil
case types.Duration:
return value, nil
default:
return value, errors.Errorf("invalid type %T for duration", value)
}
}
func toMapStringString(value map[string]interface{}, allowNil bool) map[string]interface{} {
output := make(map[string]interface{})
for key, value := range value {

View File

@ -0,0 +1,53 @@
/*
Copyright 2020 The Compose Specification Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package loader
import "reflect"
// comparable to yaml.Unmarshaler, decoder allow a type to define it's own custom logic to convert value
// see https://github.com/mitchellh/mapstructure/pull/294
type decoder interface {
DecodeMapstructure(interface{}) error
}
// see https://github.com/mitchellh/mapstructure/issues/115#issuecomment-735287466
// adapted to support types derived from built-in types, as DecodeMapstructure would not be able to mutate internal
// value, so need to invoke DecodeMapstructure defined by pointer to type
func decoderHook(from reflect.Value, to reflect.Value) (interface{}, error) {
// If the destination implements the decoder interface
u, ok := to.Interface().(decoder)
if !ok {
// for non-struct types we need to invoke func (*type) DecodeMapstructure()
if to.CanAddr() {
pto := to.Addr()
u, ok = pto.Interface().(decoder)
}
if !ok {
return from.Interface(), nil
}
}
// If it is nil and a pointer, create and assign the target value first
if to.Type().Kind() == reflect.Ptr && to.IsNil() {
to.Set(reflect.New(to.Type().Elem()))
u = to.Interface().(decoder)
}
// Call the custom DecodeMapstructure method
if err := u.DecodeMapstructure(from.Interface()); err != nil {
return to.Interface(), err
}
return to.Interface(), nil
}

View File

@ -320,8 +320,8 @@ func mergeLoggingConfig(dst, src reflect.Value) error {
if getLoggingDriver(dst.Elem()) == "" {
dst.Elem().FieldByName("Driver").SetString(getLoggingDriver(src.Elem()))
}
dstOptions := dst.Elem().FieldByName("Options").Interface().(map[string]string)
srcOptions := src.Elem().FieldByName("Options").Interface().(map[string]string)
dstOptions := dst.Elem().FieldByName("Options").Interface().(types.Options)
srcOptions := src.Elem().FieldByName("Options").Interface().(types.Options)
return mergo.Merge(&dstOptions, srcOptions, mergo.WithOverride)
}
// Different driver, override with src