mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-09 21:17:09 +08:00
update github.com/compose-spec/compose-go to v1.0.5
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
64
vendor/github.com/compose-spec/compose-go/loader/interpolate.go
generated
vendored
64
vendor/github.com/compose-spec/compose-go/loader/interpolate.go
generated
vendored
@ -21,14 +21,21 @@ import (
|
||||
"strings"
|
||||
|
||||
interp "github.com/compose-spec/compose-go/interpolation"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var interpolateTypeCastMapping = map[interp.Path]interp.Cast{
|
||||
servicePath("configs", interp.PathMatchList, "mode"): toInt,
|
||||
servicePath("secrets", interp.PathMatchList, "mode"): toInt,
|
||||
servicePath("healthcheck", "retries"): toInt,
|
||||
servicePath("healthcheck", "disable"): toBoolean,
|
||||
servicePath("cpu_count"): toInt64,
|
||||
servicePath("cpu_percent"): toFloat,
|
||||
servicePath("cpu_period"): toInt64,
|
||||
servicePath("cpu_quota"): toInt64,
|
||||
servicePath("cpu_rt_period"): toInt64,
|
||||
servicePath("cpu_rt_runtime"): toInt64,
|
||||
servicePath("cpus"): toFloat32,
|
||||
servicePath("cpu_shares"): toInt64,
|
||||
servicePath("init"): toBoolean,
|
||||
servicePath("deploy", "replicas"): toInt,
|
||||
servicePath("deploy", "update_config", "parallelism"): toInt,
|
||||
servicePath("deploy", "update_config", "max_failure_ratio"): toFloat,
|
||||
@ -36,20 +43,35 @@ var interpolateTypeCastMapping = map[interp.Path]interp.Cast{
|
||||
servicePath("deploy", "rollback_config", "max_failure_ratio"): toFloat,
|
||||
servicePath("deploy", "restart_policy", "max_attempts"): toInt,
|
||||
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,
|
||||
servicePath("ports", interp.PathMatchList, "target"): toInt,
|
||||
servicePath("ports", interp.PathMatchList, "published"): toInt,
|
||||
servicePath("privileged"): toBoolean,
|
||||
servicePath("read_only"): toBoolean,
|
||||
servicePath("scale"): toInt,
|
||||
servicePath("secrets", interp.PathMatchList, "mode"): toInt,
|
||||
servicePath("shm_size"): toUnitBytes,
|
||||
servicePath("stdin_open"): toBoolean,
|
||||
servicePath("stop_grace_period"): toDuration,
|
||||
servicePath("tty"): toBoolean,
|
||||
servicePath("ulimits", interp.PathMatchAll): toInt,
|
||||
servicePath("ulimits", interp.PathMatchAll, "hard"): toInt,
|
||||
servicePath("ulimits", interp.PathMatchAll, "soft"): toInt,
|
||||
servicePath("privileged"): toBoolean,
|
||||
servicePath("read_only"): toBoolean,
|
||||
servicePath("stdin_open"): toBoolean,
|
||||
servicePath("tty"): toBoolean,
|
||||
servicePath("volumes", interp.PathMatchList, "read_only"): toBoolean,
|
||||
servicePath("volumes", interp.PathMatchList, "volume", "nocopy"): toBoolean,
|
||||
servicePath("volumes", interp.PathMatchList, "tmpfs", "size"): toUnitBytes,
|
||||
iPath("networks", interp.PathMatchAll, "external"): toBoolean,
|
||||
iPath("networks", interp.PathMatchAll, "internal"): toBoolean,
|
||||
iPath("networks", interp.PathMatchAll, "attachable"): toBoolean,
|
||||
iPath("networks", interp.PathMatchAll, "enable_ipv6"): toBoolean,
|
||||
iPath("volumes", interp.PathMatchAll, "external"): toBoolean,
|
||||
iPath("secrets", interp.PathMatchAll, "external"): toBoolean,
|
||||
iPath("configs", interp.PathMatchAll, "external"): toBoolean,
|
||||
@ -67,10 +89,38 @@ func toInt(value string) (interface{}, error) {
|
||||
return strconv.Atoi(value)
|
||||
}
|
||||
|
||||
func toInt64(value string) (interface{}, error) {
|
||||
return strconv.ParseInt(value, 10, 64)
|
||||
}
|
||||
|
||||
func toUnitBytes(value string) (interface{}, error) {
|
||||
i, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.UnitBytes(i), nil
|
||||
}
|
||||
|
||||
func toDuration(value string) (interface{}, error) {
|
||||
i, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return types.Duration(i), nil
|
||||
}
|
||||
|
||||
func toFloat(value string) (interface{}, error) {
|
||||
return strconv.ParseFloat(value, 64)
|
||||
}
|
||||
|
||||
func toFloat32(value string) (interface{}, error) {
|
||||
f, err := strconv.ParseFloat(value, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return float32(f), nil
|
||||
}
|
||||
|
||||
// should match http://yaml.org/type/bool.html
|
||||
func toBoolean(value string) (interface{}, error) {
|
||||
switch strings.ToLower(value) {
|
||||
|
163
vendor/github.com/compose-spec/compose-go/loader/loader.go
generated
vendored
163
vendor/github.com/compose-spec/compose-go/loader/loader.go
generated
vendored
@ -31,14 +31,13 @@ import (
|
||||
"github.com/compose-spec/compose-go/schema"
|
||||
"github.com/compose-spec/compose-go/template"
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/joho/godotenv"
|
||||
shellwords "github.com/mattn/go-shellwords"
|
||||
"github.com/compose-spec/godotenv"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/mattn/go-shellwords"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Options supported by Load
|
||||
@ -49,6 +48,8 @@ type Options struct {
|
||||
SkipInterpolation bool
|
||||
// Skip normalization
|
||||
SkipNormalization bool
|
||||
// Resolve paths
|
||||
ResolvePaths bool
|
||||
// Skip consistency check
|
||||
SkipConsistencyCheck bool
|
||||
// Skip extends
|
||||
@ -103,6 +104,11 @@ func WithDiscardEnvFiles(opts *Options) {
|
||||
opts.discardEnvFiles = true
|
||||
}
|
||||
|
||||
// WithSkipValidation sets the Options to skip validation when loading sections
|
||||
func WithSkipValidation(opts *Options) {
|
||||
opts.SkipValidation = true
|
||||
}
|
||||
|
||||
// ParseYAML reads the bytes from a file, parses the bytes into a mapping
|
||||
// structure, and returns it.
|
||||
func ParseYAML(source []byte) (map[string]interface{}, error) {
|
||||
@ -199,7 +205,7 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
|
||||
}
|
||||
|
||||
if !opts.SkipNormalization {
|
||||
err = normalize(project)
|
||||
err = normalize(project, opts.ResolvePaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -216,34 +222,14 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
|
||||
}
|
||||
|
||||
func parseConfig(b []byte, opts *Options) (map[string]interface{}, error) {
|
||||
yaml, err := ParseYAML(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !opts.SkipInterpolation {
|
||||
withoutComments, err := removeYamlComments(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
substituted, err := opts.Interpolate.Substitute(string(withoutComments), template.Mapping(opts.Interpolate.LookupValue))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = []byte(substituted)
|
||||
return interp.Interpolate(yaml, *opts.Interpolate)
|
||||
}
|
||||
|
||||
return ParseYAML(b)
|
||||
}
|
||||
|
||||
// removeYamlComments drop all comments from the yaml file, so we don't try to apply string substitutions on irrelevant places
|
||||
func removeYamlComments(b []byte) ([]byte, error) {
|
||||
var cfg interface{}
|
||||
err := yaml.Unmarshal(b, &cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err = yaml.Marshal(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
return yaml, err
|
||||
}
|
||||
|
||||
func groupXFieldsIntoExtensions(dict map[string]interface{}) map[string]interface{} {
|
||||
@ -274,7 +260,7 @@ func loadSections(filename string, config map[string]interface{}, configDetails
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg.Networks, err = LoadNetworks(getSection(config, "networks"), configDetails.Version)
|
||||
cfg.Networks, err = LoadNetworks(getSection(config, "networks"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -282,11 +268,11 @@ func loadSections(filename string, config map[string]interface{}, configDetails
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.Secrets, err = LoadSecrets(getSection(config, "secrets"), configDetails)
|
||||
cfg.Secrets, err = LoadSecrets(getSection(config, "secrets"), configDetails, opts.ResolvePaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.Configs, err = LoadConfigObjs(getSection(config, "configs"), configDetails)
|
||||
cfg.Configs, err = LoadConfigObjs(getSection(config, "configs"), configDetails, opts.ResolvePaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -439,6 +425,14 @@ func formatInvalidKeyError(keyPrefix string, key interface{}) error {
|
||||
func LoadServices(filename string, servicesDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, opts *Options) ([]types.ServiceConfig, error) {
|
||||
var services []types.ServiceConfig
|
||||
|
||||
x, ok := servicesDict["extensions"]
|
||||
if ok {
|
||||
// as a top-level attribute, "services" doesn't support extensions, and a service can be named `x-foo`
|
||||
for k, v := range x.(map[string]interface{}) {
|
||||
servicesDict[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
for name := range servicesDict {
|
||||
serviceConfig, err := loadServiceWithExtends(filename, name, servicesDict, workingDir, lookupEnv, opts, &cycleTracker{})
|
||||
if err != nil {
|
||||
@ -456,7 +450,12 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serviceConfig, err := LoadService(name, servicesDict[name].(map[string]interface{}), workingDir, lookupEnv)
|
||||
target, ok := servicesDict[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot extend service %q in %s: service not found", name, filename)
|
||||
}
|
||||
|
||||
serviceConfig, err := LoadService(name, target.(map[string]interface{}), workingDir, lookupEnv, opts.ResolvePaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -478,15 +477,7 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !opts.SkipInterpolation {
|
||||
substitute, err := opts.Interpolate.Substitute(string(bytes), template.Mapping(opts.Interpolate.LookupValue))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bytes = []byte(substitute)
|
||||
}
|
||||
|
||||
baseFile, err := ParseYAML(bytes)
|
||||
baseFile, err := parseConfig(bytes, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -516,10 +507,10 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
|
||||
}
|
||||
}
|
||||
|
||||
if err := mergo.Merge(baseService, serviceConfig, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(serviceSpecials)); err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot merge service %s", name)
|
||||
serviceConfig, err = _merge(baseService, serviceConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serviceConfig = baseService
|
||||
}
|
||||
|
||||
return serviceConfig, nil
|
||||
@ -527,8 +518,10 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
|
||||
|
||||
// LoadService produces a single ServiceConfig from a compose file Dict
|
||||
// the serviceDict is not validated if directly used. Use Load() to enable validation
|
||||
func LoadService(name string, serviceDict map[string]interface{}, workingDir string, lookupEnv template.Mapping) (*types.ServiceConfig, error) {
|
||||
serviceConfig := &types.ServiceConfig{}
|
||||
func LoadService(name string, serviceDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, resolvePaths bool) (*types.ServiceConfig, error) {
|
||||
serviceConfig := &types.ServiceConfig{
|
||||
Scale: 1,
|
||||
}
|
||||
if err := Transform(serviceDict, serviceConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -538,8 +531,18 @@ func LoadService(name string, serviceDict map[string]interface{}, workingDir str
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := resolveVolumePaths(serviceConfig.Volumes, workingDir, lookupEnv); err != nil {
|
||||
return nil, err
|
||||
for i, volume := range serviceConfig.Volumes {
|
||||
if volume.Type != "bind" {
|
||||
continue
|
||||
}
|
||||
|
||||
if volume.Source == "" {
|
||||
return nil, errors.New(`invalid mount config for type "bind": field Source must not be empty`)
|
||||
}
|
||||
|
||||
if resolvePaths {
|
||||
serviceConfig.Volumes[i] = resolveVolumePath(volume, workingDir, lookupEnv)
|
||||
}
|
||||
}
|
||||
|
||||
return serviceConfig, nil
|
||||
@ -574,30 +577,19 @@ func resolveEnvironment(serviceConfig *types.ServiceConfig, workingDir string, l
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveVolumePaths(volumes []types.ServiceVolumeConfig, workingDir string, lookupEnv template.Mapping) error {
|
||||
for i, volume := range volumes {
|
||||
if volume.Type != "bind" {
|
||||
continue
|
||||
}
|
||||
|
||||
if volume.Source == "" {
|
||||
return errors.New(`invalid mount config for type "bind": field Source must not be empty`)
|
||||
}
|
||||
|
||||
filePath := expandUser(volume.Source, lookupEnv)
|
||||
// Check if source is an absolute path (either Unix or Windows), to
|
||||
// handle a Windows client with a Unix daemon or vice-versa.
|
||||
//
|
||||
// Note that this is not required for Docker for Windows when specifying
|
||||
// a local Windows path, because Docker for Windows translates the Windows
|
||||
// path into a valid path within the VM.
|
||||
if !path.IsAbs(filePath) && !isAbs(filePath) {
|
||||
filePath = absPath(workingDir, filePath)
|
||||
}
|
||||
volume.Source = filePath
|
||||
volumes[i] = volume
|
||||
func resolveVolumePath(volume types.ServiceVolumeConfig, workingDir string, lookupEnv template.Mapping) types.ServiceVolumeConfig {
|
||||
filePath := expandUser(volume.Source, lookupEnv)
|
||||
// Check if source is an absolute path (either Unix or Windows), to
|
||||
// handle a Windows client with a Unix daemon or vice-versa.
|
||||
//
|
||||
// Note that this is not required for Docker for Windows when specifying
|
||||
// a local Windows path, because Docker for Windows translates the Windows
|
||||
// path into a valid path within the VM.
|
||||
if !path.IsAbs(filePath) && !isAbs(filePath) {
|
||||
filePath = absPath(workingDir, filePath)
|
||||
}
|
||||
return nil
|
||||
volume.Source = filePath
|
||||
return volume
|
||||
}
|
||||
|
||||
// TODO: make this more robust
|
||||
@ -633,7 +625,7 @@ func transformUlimits(data interface{}) (interface{}, error) {
|
||||
|
||||
// LoadNetworks produces a NetworkConfig map from a compose file Dict
|
||||
// the source Dict is not validated if directly used. Use Load() to enable validation
|
||||
func LoadNetworks(source map[string]interface{}, version string) (map[string]types.NetworkConfig, error) {
|
||||
func LoadNetworks(source map[string]interface{}) (map[string]types.NetworkConfig, error) {
|
||||
networks := make(map[string]types.NetworkConfig)
|
||||
err := Transform(source, &networks)
|
||||
if err != nil {
|
||||
@ -701,13 +693,13 @@ func LoadVolumes(source map[string]interface{}) (map[string]types.VolumeConfig,
|
||||
|
||||
// LoadSecrets produces a SecretConfig map from a compose file Dict
|
||||
// the source Dict is not validated if directly used. Use Load() to enable validation
|
||||
func LoadSecrets(source map[string]interface{}, details types.ConfigDetails) (map[string]types.SecretConfig, error) {
|
||||
func LoadSecrets(source map[string]interface{}, details types.ConfigDetails, resolvePaths bool) (map[string]types.SecretConfig, error) {
|
||||
secrets := make(map[string]types.SecretConfig)
|
||||
if err := Transform(source, &secrets); err != nil {
|
||||
return secrets, err
|
||||
}
|
||||
for name, secret := range secrets {
|
||||
obj, err := loadFileObjectConfig(name, "secret", types.FileObjectConfig(secret), details)
|
||||
obj, err := loadFileObjectConfig(name, "secret", types.FileObjectConfig(secret), details, resolvePaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -719,13 +711,13 @@ func LoadSecrets(source map[string]interface{}, details types.ConfigDetails) (ma
|
||||
|
||||
// LoadConfigObjs produces a ConfigObjConfig map from a compose file Dict
|
||||
// the source Dict is not validated if directly used. Use Load() to enable validation
|
||||
func LoadConfigObjs(source map[string]interface{}, details types.ConfigDetails) (map[string]types.ConfigObjConfig, error) {
|
||||
func LoadConfigObjs(source map[string]interface{}, details types.ConfigDetails, resolvePaths bool) (map[string]types.ConfigObjConfig, error) {
|
||||
configs := make(map[string]types.ConfigObjConfig)
|
||||
if err := Transform(source, &configs); err != nil {
|
||||
return configs, err
|
||||
}
|
||||
for name, config := range configs {
|
||||
obj, err := loadFileObjectConfig(name, "config", types.FileObjectConfig(config), details)
|
||||
obj, err := loadFileObjectConfig(name, "config", types.FileObjectConfig(config), details, resolvePaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -735,7 +727,7 @@ func LoadConfigObjs(source map[string]interface{}, details types.ConfigDetails)
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig, details types.ConfigDetails) (types.FileObjectConfig, error) {
|
||||
func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig, details types.ConfigDetails, resolvePaths bool) (types.FileObjectConfig, error) {
|
||||
// if "external: true"
|
||||
switch {
|
||||
case obj.External.External:
|
||||
@ -758,7 +750,9 @@ func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfi
|
||||
return obj, errors.Errorf("%[1]s %[2]s: %[1]s.driver and %[1]s.file conflict; only use %[1]s.driver", objType, name)
|
||||
}
|
||||
default:
|
||||
obj.File = absPath(details.WorkingDir, obj.File)
|
||||
if resolvePaths {
|
||||
obj.File = absPath(details.WorkingDir, obj.File)
|
||||
}
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
@ -1018,10 +1012,13 @@ 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)
|
||||
}
|
||||
panic(errors.Errorf("invalid type for size %T", value))
|
||||
}
|
||||
|
||||
var transformStringToDuration TransformerFunc = func(value interface{}) (interface{}, error) {
|
||||
|
74
vendor/github.com/compose-spec/compose-go/loader/merge.go
generated
vendored
74
vendor/github.com/compose-spec/compose-go/loader/merge.go
generated
vendored
@ -33,6 +33,7 @@ var serviceSpecials = &specials{
|
||||
m: map[reflect.Type]func(dst, src reflect.Value) error{
|
||||
reflect.TypeOf(&types.LoggingConfig{}): safelyMerge(mergeLoggingConfig),
|
||||
reflect.TypeOf(&types.UlimitsConfig{}): safelyMerge(mergeUlimitsConfig),
|
||||
reflect.TypeOf([]types.ServiceVolumeConfig{}): mergeSlice(toServiceVolumeConfigsMap, toServiceVolumeConfigsSlice),
|
||||
reflect.TypeOf([]types.ServicePortConfig{}): mergeSlice(toServicePortConfigsMap, toServicePortConfigsSlice),
|
||||
reflect.TypeOf([]types.ServiceSecretConfig{}): mergeSlice(toServiceSecretConfigsMap, toServiceSecretConfigsSlice),
|
||||
reflect.TypeOf([]types.ServiceConfigObjConfig{}): mergeSlice(toServiceConfigObjConfigsMap, toSServiceConfigObjConfigsSlice),
|
||||
@ -86,13 +87,11 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
|
||||
for name, overrideService := range overrideServices {
|
||||
overrideService := overrideService
|
||||
if baseService, ok := baseServices[name]; ok {
|
||||
if err := mergo.Merge(&baseService, &overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(serviceSpecials)); err != nil {
|
||||
return base, errors.Wrapf(err, "cannot merge service %s", name)
|
||||
merged, err := _merge(&baseService, &overrideService)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot merge service %s", name)
|
||||
}
|
||||
if len(overrideService.Command) > 0 {
|
||||
baseService.Command = overrideService.Command
|
||||
}
|
||||
baseServices[name] = baseService
|
||||
baseServices[name] = *merged
|
||||
continue
|
||||
}
|
||||
baseServices[name] = overrideService
|
||||
@ -105,6 +104,19 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func _merge(baseService *types.ServiceConfig, overrideService *types.ServiceConfig) (*types.ServiceConfig, error) {
|
||||
if err := mergo.Merge(baseService, overrideService, mergo.WithAppendSlice, mergo.WithOverride, mergo.WithTransformers(serviceSpecials)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if overrideService.Command != nil {
|
||||
baseService.Command = overrideService.Command
|
||||
}
|
||||
if overrideService.Entrypoint != nil {
|
||||
baseService.Entrypoint = overrideService.Entrypoint
|
||||
}
|
||||
return baseService, nil
|
||||
}
|
||||
|
||||
func toServiceSecretConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
|
||||
secrets, ok := s.([]types.ServiceSecretConfig)
|
||||
if !ok {
|
||||
@ -135,8 +147,33 @@ func toServicePortConfigsMap(s interface{}) (map[interface{}]interface{}, error)
|
||||
return nil, errors.Errorf("not a servicePortConfig slice: %v", s)
|
||||
}
|
||||
m := map[interface{}]interface{}{}
|
||||
type port struct {
|
||||
target uint32
|
||||
published uint32
|
||||
ip string
|
||||
protocol string
|
||||
}
|
||||
|
||||
for _, p := range ports {
|
||||
m[p.Published] = p
|
||||
mergeKey := port{
|
||||
target: p.Target,
|
||||
published: p.Published,
|
||||
ip: p.HostIP,
|
||||
protocol: p.Protocol,
|
||||
}
|
||||
m[mergeKey] = p
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func toServiceVolumeConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
|
||||
volumes, ok := s.([]types.ServiceVolumeConfig)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("not a ServiceVolumeConfig slice: %v", s)
|
||||
}
|
||||
m := map[interface{}]interface{}{}
|
||||
for _, v := range volumes {
|
||||
m[v.Target] = v
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@ -166,7 +203,28 @@ func toServicePortConfigsSlice(dst reflect.Value, m map[interface{}]interface{})
|
||||
for _, v := range m {
|
||||
s = append(s, v.(types.ServicePortConfig))
|
||||
}
|
||||
sort.Slice(s, func(i, j int) bool { return s[i].Published < s[j].Published })
|
||||
sort.Slice(s, func(i, j int) bool {
|
||||
if s[i].Target != s[j].Target {
|
||||
return s[i].Target < s[j].Target
|
||||
}
|
||||
if s[i].Published != s[j].Published {
|
||||
return s[i].Published < s[j].Published
|
||||
}
|
||||
if s[i].HostIP != s[j].HostIP {
|
||||
return s[i].HostIP < s[j].HostIP
|
||||
}
|
||||
return s[i].Protocol < s[j].Protocol
|
||||
})
|
||||
dst.Set(reflect.ValueOf(s))
|
||||
return nil
|
||||
}
|
||||
|
||||
func toServiceVolumeConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
|
||||
s := []types.ServiceVolumeConfig{}
|
||||
for _, v := range m {
|
||||
s = append(s, v.(types.ServiceVolumeConfig))
|
||||
}
|
||||
sort.Slice(s, func(i, j int) bool { return s[i].Target < s[j].Target })
|
||||
dst.Set(reflect.ValueOf(s))
|
||||
return nil
|
||||
}
|
||||
|
43
vendor/github.com/compose-spec/compose-go/loader/normalize.go
generated
vendored
43
vendor/github.com/compose-spec/compose-go/loader/normalize.go
generated
vendored
@ -28,7 +28,7 @@ import (
|
||||
)
|
||||
|
||||
// normalize compose project by moving deprecated attributes to their canonical position and injecting implicit defaults
|
||||
func normalize(project *types.Project) error {
|
||||
func normalize(project *types.Project, resolvePaths bool) error {
|
||||
absWorkingDir, err := filepath.Abs(project.WorkingDir)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -41,6 +41,10 @@ func normalize(project *types.Project) error {
|
||||
}
|
||||
project.ComposeFiles = absComposeFiles
|
||||
|
||||
if project.Networks == nil {
|
||||
project.Networks = make(map[string]types.NetworkConfig)
|
||||
}
|
||||
|
||||
// If not declared explicitly, Compose model involves an implicit "default" network
|
||||
if _, ok := project.Networks["default"]; !ok {
|
||||
project.Networks["default"] = types.NetworkConfig{}
|
||||
@ -72,8 +76,9 @@ func normalize(project *types.Project) error {
|
||||
}
|
||||
localContext := absPath(project.WorkingDir, s.Build.Context)
|
||||
if _, err := os.Stat(localContext); err == nil {
|
||||
s.Build.Context = localContext
|
||||
s.Build.Dockerfile = absPath(localContext, s.Build.Dockerfile)
|
||||
if resolvePaths {
|
||||
s.Build.Context = localContext
|
||||
}
|
||||
} else {
|
||||
// might be a remote http/git context. Unfortunately supported "remote" syntax is highly ambiguous
|
||||
// in moby/moby and not defined by compose-spec, so let's assume runtime will check
|
||||
@ -82,17 +87,22 @@ func normalize(project *types.Project) error {
|
||||
}
|
||||
s.Environment = s.Environment.Resolve(fn)
|
||||
|
||||
err := relocateLogDriver(s)
|
||||
err := relocateLogDriver(&s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = relocateLogOpt(s)
|
||||
err = relocateLogOpt(&s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = relocateDockerfile(s)
|
||||
err = relocateDockerfile(&s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = relocateScale(&s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -105,6 +115,21 @@ func normalize(project *types.Project) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func relocateScale(s *types.ServiceConfig) error {
|
||||
scale := uint64(s.Scale)
|
||||
if scale != 1 {
|
||||
logrus.Warn("`scale` is deprecated. Use the `deploy.replicas` element")
|
||||
if s.Deploy == nil {
|
||||
s.Deploy = &types.DeployConfig{}
|
||||
}
|
||||
if s.Deploy.Replicas != nil && *s.Deploy.Replicas != scale {
|
||||
return errors.Wrap(errdefs.ErrInvalid, "can't use both 'scale' (deprecated) and 'deploy.replicas'")
|
||||
}
|
||||
s.Deploy.Replicas = &scale
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func absComposeFiles(composeFiles []string) ([]string, error) {
|
||||
absComposeFiles := make([]string, len(composeFiles))
|
||||
for i, composeFile := range composeFiles {
|
||||
@ -191,7 +216,7 @@ func relocateExternalName(project *types.Project) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func relocateLogOpt(s types.ServiceConfig) error {
|
||||
func relocateLogOpt(s *types.ServiceConfig) error {
|
||||
if len(s.LogOpt) != 0 {
|
||||
logrus.Warn("`log_opts` is deprecated. Use the `logging` element")
|
||||
if s.Logging == nil {
|
||||
@ -208,7 +233,7 @@ func relocateLogOpt(s types.ServiceConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func relocateLogDriver(s types.ServiceConfig) error {
|
||||
func relocateLogDriver(s *types.ServiceConfig) error {
|
||||
if s.LogDriver != "" {
|
||||
logrus.Warn("`log_driver` is deprecated. Use the `logging` element")
|
||||
if s.Logging == nil {
|
||||
@ -223,7 +248,7 @@ func relocateLogDriver(s types.ServiceConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func relocateDockerfile(s types.ServiceConfig) error {
|
||||
func relocateDockerfile(s *types.ServiceConfig) error {
|
||||
if s.Dockerfile != "" {
|
||||
logrus.Warn("`dockerfile` is deprecated. Use the `build` element")
|
||||
if s.Build == nil {
|
||||
|
11
vendor/github.com/compose-spec/compose-go/loader/validate.go
generated
vendored
11
vendor/github.com/compose-spec/compose-go/loader/validate.go
generated
vendored
@ -38,20 +38,13 @@ func checkConsistency(project *types.Project) error {
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(s.NetworkMode, types.NetworkModeServicePrefix) {
|
||||
serviceName := s.NetworkMode[len(types.NetworkModeServicePrefix):]
|
||||
if strings.HasPrefix(s.NetworkMode, types.ServicePrefix) {
|
||||
serviceName := s.NetworkMode[len(types.ServicePrefix):]
|
||||
if _, err := project.GetServices(serviceName); err != nil {
|
||||
return fmt.Errorf("service %q not found for network_mode 'service:%s'", serviceName, serviceName)
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(s.NetworkMode, types.NetworkModeContainerPrefix) {
|
||||
containerName := s.NetworkMode[len(types.NetworkModeContainerPrefix):]
|
||||
if _, err := project.GetByContainerName(containerName); err != nil {
|
||||
return fmt.Errorf("service with container_name %q not found for network_mode 'container:%s'", containerName, containerName)
|
||||
}
|
||||
}
|
||||
|
||||
for _, volume := range s.Volumes {
|
||||
switch volume.Type {
|
||||
case types.VolumeTypeVolume:
|
||||
|
25
vendor/github.com/compose-spec/compose-go/schema/compose-spec.json
generated
vendored
25
vendor/github.com/compose-spec/compose-go/schema/compose-spec.json
generated
vendored
@ -331,7 +331,7 @@
|
||||
"privileged": {"type": "boolean"},
|
||||
"profiles": {"$ref": "#/definitions/list_of_strings"},
|
||||
"pull_policy": {"type": "string", "enum": [
|
||||
"always", "never", "if_not_present", "build"
|
||||
"always", "never", "if_not_present", "build", "missing"
|
||||
]},
|
||||
"read_only": {"type": "boolean"},
|
||||
"restart": {"type": "string"},
|
||||
@ -367,6 +367,7 @@
|
||||
"stdin_open": {"type": "boolean"},
|
||||
"stop_grace_period": {"type": "string", "format": "duration"},
|
||||
"stop_signal": {"type": "string"},
|
||||
"storage_opt": {"type": "object"},
|
||||
"tmpfs": {"$ref": "#/definitions/string_or_list"},
|
||||
"tty": {"type": "boolean"},
|
||||
"ulimits": {
|
||||
@ -426,8 +427,10 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
"oneOf": [
|
||||
{"type": "integer", "minimum": 0},
|
||||
{"type": "string"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@ -599,12 +602,12 @@
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"capabilities": {"$ref": "#/definitions/list_of_strings"},
|
||||
"count": {"type": ["string", "integer"]},
|
||||
"device_ids": {"$ref": "#/definitions/list_of_strings"},
|
||||
"driver":{"type": "string"},
|
||||
"options":{"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"capabilities": {"$ref": "#/definitions/list_of_strings"},
|
||||
"count": {"type": ["string", "integer"]},
|
||||
"device_ids": {"$ref": "#/definitions/list_of_strings"},
|
||||
"driver":{"type": "string"},
|
||||
"options":{"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
@ -769,7 +772,7 @@
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
".+": {
|
||||
"type": ["string", "number", "null"]
|
||||
"type": ["string", "number", "boolean", "null"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@ -810,4 +813,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
33
vendor/github.com/compose-spec/compose-go/template/template.go
generated
vendored
33
vendor/github.com/compose-spec/compose-go/template/template.go
generated
vendored
@ -25,11 +25,12 @@ import (
|
||||
)
|
||||
|
||||
var delimiter = "\\$"
|
||||
var substitution = "[_a-z][_a-z0-9]*(?::?[-?][^}]*)?"
|
||||
var substitutionNamed = "[_a-z][_a-z0-9]*"
|
||||
var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-?][^}]*)?"
|
||||
|
||||
var patternString = fmt.Sprintf(
|
||||
"%s(?i:(?P<escaped>%s)|(?P<named>%s)|{(?P<braced>%s)}|(?P<invalid>))",
|
||||
delimiter, delimiter, substitution, substitution,
|
||||
delimiter, delimiter, substitutionNamed, substitutionBraced,
|
||||
)
|
||||
|
||||
var defaultPattern = regexp.MustCompile(patternString)
|
||||
@ -74,9 +75,11 @@ func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, su
|
||||
return escaped
|
||||
}
|
||||
|
||||
braced := false
|
||||
substitution := groups["named"]
|
||||
if substitution == "" {
|
||||
substitution = groups["braced"]
|
||||
braced = true
|
||||
}
|
||||
|
||||
if substitution == "" {
|
||||
@ -84,19 +87,21 @@ func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, su
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, f := range subsFuncs {
|
||||
var (
|
||||
value string
|
||||
applied bool
|
||||
)
|
||||
value, applied, err = f(substitution, mapping)
|
||||
if err != nil {
|
||||
return ""
|
||||
if braced {
|
||||
for _, f := range subsFuncs {
|
||||
var (
|
||||
value string
|
||||
applied bool
|
||||
)
|
||||
value, applied, err = f(substitution, mapping)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if !applied {
|
||||
continue
|
||||
}
|
||||
return value
|
||||
}
|
||||
if !applied {
|
||||
continue
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
value, ok := mapping(substitution)
|
||||
|
23
vendor/github.com/compose-spec/compose-go/types/project.go
generated
vendored
23
vendor/github.com/compose-spec/compose-go/types/project.go
generated
vendored
@ -94,24 +94,6 @@ func (p Project) ConfigNames() []string {
|
||||
return names
|
||||
}
|
||||
|
||||
func (p Project) GetByContainerName(names ...string) (Services, error) {
|
||||
if len(names) == 0 {
|
||||
return p.Services, nil
|
||||
}
|
||||
services := Services{}
|
||||
outLoop:
|
||||
for _, name := range names {
|
||||
for _, s := range p.Services {
|
||||
if name == s.ContainerName {
|
||||
services = append(services, s)
|
||||
continue outLoop
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("service with container_name %q could not be found", name)
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
// GetServices retrieve services by names, or return all services if no name specified
|
||||
func (p Project) GetServices(names ...string) (Services, error) {
|
||||
if len(names) == 0 {
|
||||
@ -228,6 +210,11 @@ func (s Services) GetProfiles() []string {
|
||||
|
||||
// ApplyProfiles disables service which don't match selected profiles
|
||||
func (p *Project) ApplyProfiles(profiles []string) {
|
||||
for _, p := range profiles {
|
||||
if p == "*" {
|
||||
return
|
||||
}
|
||||
}
|
||||
var enabled, disabled Services
|
||||
for _, service := range p.Services {
|
||||
if service.HasProfile(profiles) {
|
||||
|
38
vendor/github.com/compose-spec/compose-go/types/types.go
generated
vendored
38
vendor/github.com/compose-spec/compose-go/types/types.go
generated
vendored
@ -89,7 +89,7 @@ type ServiceConfig struct {
|
||||
Profiles []string `mapstructure:"profiles" yaml:"profiles,omitempty" json:"profiles,omitempty"`
|
||||
|
||||
Build *BuildConfig `yaml:",omitempty" json:"build,omitempty"`
|
||||
BlkioConfig *BlkioConfig `yaml:",omitempty" json:"blkio_config,omitempty"`
|
||||
BlkioConfig *BlkioConfig `mapstructure:"blkio_config" yaml:",omitempty" json:"blkio_config,omitempty"`
|
||||
CapAdd []string `mapstructure:"cap_add" yaml:"cap_add,omitempty" json:"cap_add,omitempty"`
|
||||
CapDrop []string `mapstructure:"cap_drop" yaml:"cap_drop,omitempty" json:"cap_drop,omitempty"`
|
||||
CgroupParent string `mapstructure:"cgroup_parent" yaml:"cgroup_parent,omitempty" json:"cgroup_parent,omitempty"`
|
||||
@ -152,7 +152,7 @@ type ServiceConfig struct {
|
||||
ReadOnly bool `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"`
|
||||
Restart string `yaml:",omitempty" json:"restart,omitempty"`
|
||||
Runtime string `yaml:",omitempty" json:"runtime,omitempty"`
|
||||
Scale int `yaml:",omitempty" json:"scale,omitempty"`
|
||||
Scale int `yaml:"-" json:"-"`
|
||||
Secrets []ServiceSecretConfig `yaml:",omitempty" json:"secrets,omitempty"`
|
||||
SecurityOpt []string `mapstructure:"security_opt" yaml:"security_opt,omitempty" json:"security_opt,omitempty"`
|
||||
ShmSize UnitBytes `mapstructure:"shm_size" yaml:"shm_size,omitempty" json:"shm_size,omitempty"`
|
||||
@ -226,10 +226,17 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
// ServicePrefix is the prefix for references pointing to a service
|
||||
ServicePrefix = "service:"
|
||||
// ContainerPrefix is the prefix for references pointing to a container
|
||||
ContainerPrefix = "container:"
|
||||
|
||||
// NetworkModeServicePrefix is the prefix for network_mode pointing to a service
|
||||
NetworkModeServicePrefix = "service:"
|
||||
// Deprecated prefer ServicePrefix
|
||||
NetworkModeServicePrefix = ServicePrefix
|
||||
// NetworkModeContainerPrefix is the prefix for network_mode pointing to a container
|
||||
NetworkModeContainerPrefix = "container:"
|
||||
// Deprecated prefer ContainerPrefix
|
||||
NetworkModeContainerPrefix = ContainerPrefix
|
||||
)
|
||||
|
||||
// GetDependencies retrieve all services this service depends on
|
||||
@ -246,9 +253,21 @@ func (s ServiceConfig) GetDependencies() []string {
|
||||
dependencies.append(link)
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(s.NetworkMode, NetworkModeServicePrefix) {
|
||||
dependencies.append(s.NetworkMode[len(NetworkModeServicePrefix):])
|
||||
if strings.HasPrefix(s.NetworkMode, ServicePrefix) {
|
||||
dependencies.append(s.NetworkMode[len(ServicePrefix):])
|
||||
}
|
||||
if strings.HasPrefix(s.Ipc, ServicePrefix) {
|
||||
dependencies.append(s.Ipc[len(ServicePrefix):])
|
||||
}
|
||||
if strings.HasPrefix(s.Pid, ServicePrefix) {
|
||||
dependencies.append(s.Pid[len(ServicePrefix):])
|
||||
}
|
||||
for _, vol := range s.VolumesFrom {
|
||||
if !strings.HasPrefix(s.Pid, ContainerPrefix) {
|
||||
dependencies.append(vol)
|
||||
}
|
||||
}
|
||||
|
||||
return dependencies.toSlice()
|
||||
}
|
||||
|
||||
@ -352,7 +371,7 @@ func (e MappingWithEquals) OverrideBy(other MappingWithEquals) MappingWithEquals
|
||||
// Resolve update a MappingWithEquals for keys without value (`key`, but not `key=`)
|
||||
func (e MappingWithEquals) Resolve(lookupFn func(string) (string, bool)) MappingWithEquals {
|
||||
for k, v := range e {
|
||||
if v == nil || *v == "" {
|
||||
if v == nil {
|
||||
if value, ok := lookupFn(k); ok {
|
||||
e[k] = &value
|
||||
}
|
||||
@ -558,7 +577,7 @@ type ServiceNetworkConfig struct {
|
||||
// ServicePortConfig is the port configuration for a service
|
||||
type ServicePortConfig struct {
|
||||
Mode string `yaml:",omitempty" json:"mode,omitempty"`
|
||||
HostIP string `yaml:"host_ip,omitempty" json:"host_ip,omitempty"`
|
||||
HostIP string `mapstructure:"host_ip" yaml:"host_ip,omitempty" json:"host_ip,omitempty"`
|
||||
Target uint32 `yaml:",omitempty" json:"target,omitempty"`
|
||||
Published uint32 `yaml:",omitempty" json:"published,omitempty"`
|
||||
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
|
||||
@ -671,7 +690,7 @@ type ServiceVolumeVolume struct {
|
||||
|
||||
// ServiceVolumeTmpfs are options for a service volume of type tmpfs
|
||||
type ServiceVolumeTmpfs struct {
|
||||
Size int64 `yaml:",omitempty" json:"size,omitempty"`
|
||||
Size UnitBytes `yaml:",omitempty" json:"size,omitempty"`
|
||||
|
||||
Extensions map[string]interface{} `yaml:",inline" json:"-"`
|
||||
}
|
||||
@ -729,6 +748,7 @@ type NetworkConfig struct {
|
||||
Internal bool `yaml:",omitempty" json:"internal,omitempty"`
|
||||
Attachable bool `yaml:",omitempty" json:"attachable,omitempty"`
|
||||
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
|
||||
EnableIPv6 bool `mapstructure:"enable_ipv6" yaml:"enable_ipv6,omitempty" json:"enable_ipv6,omitempty"`
|
||||
Extensions map[string]interface{} `yaml:",inline" json:"-"`
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user