update github.com/compose-spec/compose-go to v1.2.1

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2022-03-29 21:24:16 +02:00
parent cad87f54c5
commit 785dc17f13
No known key found for this signature in database
GPG Key ID: 3248E46B6BB8C7F7
27 changed files with 425 additions and 253 deletions

2
go.mod
View File

@ -8,7 +8,7 @@ require (
github.com/bugsnag/panicwrap v1.2.0 // indirect
github.com/cenkalti/backoff v2.1.1+incompatible // indirect
github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e // indirect
github.com/compose-spec/compose-go v1.0.8
github.com/compose-spec/compose-go v1.2.1
github.com/containerd/console v1.0.3
github.com/containerd/containerd v1.6.1
github.com/docker/cli v20.10.12+incompatible

13
go.sum
View File

@ -280,10 +280,8 @@ github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/compose-spec/compose-go v1.0.8 h1:fgT7mYYu5Sp37i2lUIAAvwJpkAHk6dP5ITHy/LlutUk=
github.com/compose-spec/compose-go v1.0.8/go.mod h1:REnCbBugoIdHB7S1sfkN/aJ7AJpNApGNjNiVjA9L8x4=
github.com/compose-spec/godotenv v1.1.1 h1:lp+WpAInnw06YN9sV/XLUOV/9z4C+6wjJdWlrdVac7o=
github.com/compose-spec/godotenv v1.1.1/go.mod h1:zF/3BOa18Z24tts5qnO/E9YURQanJTBUf7nlcCTNsyc=
github.com/compose-spec/compose-go v1.2.1 h1:8+DAP7Mt/Ohl5y6YbZdilLMvIhMxvuSZcNZyywjQmJE=
github.com/compose-spec/compose-go v1.2.1/go.mod h1:pAy7Mikpeft4pxkFU565/DRHEbDfR84G6AQuiL+Hdg8=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
@ -967,8 +965,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/moby/buildkit v0.8.1/go.mod h1:/kyU1hKy/aYCuP39GZA9MaKioovHku57N6cqlKZIaiQ=
github.com/moby/buildkit v0.10.0 h1:ElHQJJdnj/VR/pfNJwhrjQJj8GXFIwVNGZh/Qbd5tVo=
@ -2043,8 +2041,9 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk=
gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -0,0 +1,23 @@
/*
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 consts
const (
ComposeProjectName = "COMPOSE_PROJECT_NAME"
ComposePathSeparator = "COMPOSE_PATH_SEPARATOR"
ComposeFilePath = "COMPOSE_FILE"
)

View File

@ -20,4 +20,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,4 +1,4 @@
// Package godotenv is a go port of the ruby dotenv library (https://github.com/bkeepers/dotenv)
// Package dotenv is a go port of the ruby dotenv library (https://github.com/bkeepers/dotenv)
//
// Examples/readme can be found on the github page at https://github.com/joho/godotenv
//
@ -11,7 +11,7 @@
// godotenv.Load()
//
// and all the env vars declared in .env will be available through os.Getenv("SOME_ENV_VAR")
package godotenv
package dotenv
import (
"errors"

View File

@ -1,4 +1,4 @@
package godotenv
package dotenv
import (
"bytes"
@ -41,9 +41,9 @@ func parseBytes(src []byte, out map[string]string, lookupFn LookupFn) error {
value, ok := lookupFn(key)
if ok {
out[key] = value
cutset = left
continue
}
cutset = left
continue
}
value, left, err := extractVarValue(left, out, lookupFn)
@ -132,14 +132,14 @@ func extractVarValue(src []byte, envMap map[string]string, lookupFn LookupFn) (v
// unquoted value - read until new line
end := bytes.IndexFunc(src, isNewLine)
var rest []byte
var value string
if end < 0 {
value := strings.TrimRightFunc(string(src), unicode.IsSpace)
rest = nil
return expandVariables(value, envMap, lookupFn), rest, nil
value := strings.Split(string(src), "#")[0] // Remove inline comments on unquoted lines
value = strings.TrimRightFunc(value, unicode.IsSpace)
return expandVariables(value, envMap, lookupFn), nil, nil
}
value = strings.TrimRightFunc(string(src[0:end]), unicode.IsSpace)
value := strings.Split(string(src[0:end]), "#")[0]
value = strings.TrimRightFunc(value, unicode.IsSpace)
rest = src[end:]
return expandVariables(value, envMap, lookupFn), rest, nil
}
@ -228,7 +228,6 @@ func isSpace(r rune) bool {
return false
}
// isNewLine reports whether the rune is a new line character
func isNewLine(r rune) bool {
return r == '\n'

View File

@ -115,7 +115,7 @@ func newPathError(path Path, err error) error {
return nil
case *template.InvalidTemplateError:
return errors.Errorf(
"invalid interpolation format for %s: %#v. You may need to escape any $ with another $.",
"invalid interpolation format for %s: %#v. You may need to escape any $ with another $",
path, err.Template)
default:
return errors.Wrapf(err, "error while interpolating %s", path)

View File

@ -1,3 +1,4 @@
name: Full_Example_project_name
services:
foo:
@ -6,6 +7,8 @@ services:
dockerfile: Dockerfile
args:
foo: bar
ssh:
- default
target: foo
network: foo
cache_from:
@ -85,6 +88,10 @@ services:
- spread: node.labels.az
endpoint_mode: dnsrr
device_cgroup_rules:
- "c 1:3 mr"
- "a 7:* rmw"
devices:
- "/dev/ttyUSB0:/dev/ttyUSB0"

View File

@ -21,7 +21,6 @@ import (
"strings"
interp "github.com/compose-spec/compose-go/interpolation"
"github.com/compose-spec/compose-go/types"
"github.com/pkg/errors"
)
@ -53,7 +52,6 @@ var interpolateTypeCastMapping = map[interp.Path]interp.Cast{
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,
@ -94,19 +92,11 @@ func toInt64(value string) (interface{}, error) {
}
func toUnitBytes(value string) (interface{}, error) {
i, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return nil, err
}
return types.UnitBytes(i), nil
return transformSize(value)
}
func toDuration(value string) (interface{}, error) {
i, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return nil, err
}
return types.Duration(i), nil
return transformStringToDuration(value)
}
func toFloat(value string) (interface{}, error) {

View File

@ -23,15 +23,18 @@ import (
"path"
"path/filepath"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"time"
"github.com/compose-spec/compose-go/consts"
"github.com/compose-spec/compose-go/dotenv"
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/compose-spec/godotenv"
"github.com/docker/go-units"
"github.com/mattn/go-shellwords"
"github.com/mitchellh/mapstructure"
@ -58,8 +61,19 @@ type Options struct {
Interpolate *interp.Options
// Discard 'env_file' entries after resolving to 'environment' section
discardEnvFiles bool
// Set project name
Name string
// Set project projectName
projectName string
// Indicates when the projectName was imperatively set or guessed from path
projectNameImperativelySet bool
}
func (o *Options) SetProjectName(name string, imperativelySet bool) {
o.projectName = normalizeProjectName(name)
o.projectNameImperativelySet = imperativelySet
}
func (o Options) GetProjectName() (string, bool) {
return o.projectName, o.projectNameImperativelySet
}
// serviceRef identifies a reference to a service. It's used to detect cyclic
@ -192,8 +206,17 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
s.EnvFile = newEnvFiles
}
projectName, projectNameImperativelySet := opts.GetProjectName()
model.Name = normalizeProjectName(model.Name)
if !projectNameImperativelySet && model.Name != "" {
projectName = model.Name
}
if projectName != "" {
configDetails.Environment[consts.ComposeProjectName] = projectName
}
project := &types.Project{
Name: opts.Name,
Name: projectName,
WorkingDir: configDetails.WorkingDir,
Services: model.Services,
Networks: model.Networks,
@ -221,6 +244,13 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
return project, nil
}
func normalizeProjectName(s string) string {
r := regexp.MustCompile("[a-z0-9_-]")
s = strings.ToLower(s)
s = strings.Join(r.FindAllString(s, -1), "")
return strings.TrimLeft(s, "_-")
}
func parseConfig(b []byte, opts *Options) (map[string]interface{}, error) {
yml, err := ParseYAML(b)
if err != nil {
@ -254,7 +284,14 @@ func loadSections(filename string, config map[string]interface{}, configDetails
cfg := types.Config{
Filename: filename,
}
name := ""
if n, ok := config["name"]; ok {
name, ok = n.(string)
if !ok {
return nil, errors.New("project name must be a string")
}
}
cfg.Name = name
cfg.Services, err = LoadServices(filename, getSection(config, "services"), configDetails.WorkingDir, configDetails.LookupEnv, opts)
if err != nil {
return nil, err
@ -280,10 +317,6 @@ func loadSections(filename string, config map[string]interface{}, configDetails
if len(extensions) > 0 {
cfg.Extensions = extensions
}
if err != nil {
return nil, err
}
return &cfg, nil
}
@ -357,6 +390,7 @@ func createTransformHook(additionalTransformers ...Transformer) mapstructure.Dec
reflect.TypeOf(types.DependsOnConfig{}): transformDependsOnConfig,
reflect.TypeOf(types.ExtendsConfig{}): transformExtendsConfig,
reflect.TypeOf(types.DeviceRequest{}): transformServiceDeviceRequest,
reflect.TypeOf(types.SSHConfig{}): transformSSHConfig,
}
for _, transformer := range additionalTransformers {
@ -559,7 +593,7 @@ func resolveEnvironment(serviceConfig *types.ServiceConfig, workingDir string, l
return err
}
defer file.Close()
fileVars, err := godotenv.ParseWithLookup(file, godotenv.LookupFn(lookupEnv))
fileVars, err := dotenv.ParseWithLookup(file, dotenv.LookupFn(lookupEnv))
if err != nil {
return err
}
@ -817,6 +851,10 @@ var transformServicePort TransformerFunc = func(data interface{}) (interface{},
ports = append(ports, v)
}
case map[string]interface{}:
published := value["published"]
if v, ok := published.(int); ok {
value["published"] = strconv.Itoa(v)
}
ports = append(ports, groupXFieldsIntoExtensions(value))
default:
return data, errors.Errorf("invalid type %T for port", value)
@ -891,7 +929,7 @@ var transformDependsOnConfig TransformerFunc = func(data interface{}) (interface
for _, serviceIntf := range value {
service, ok := serviceIntf.(string)
if !ok {
return data, errors.Errorf("invalid type %T for service depends_on element. Expected string.", value)
return data, errors.Errorf("invalid type %T for service depends_on elementn, expected string", value)
}
transformed[service] = map[string]interface{}{"condition": types.ServiceConditionStarted}
}
@ -941,6 +979,35 @@ var transformServiceNetworkMap TransformerFunc = func(value interface{}) (interf
return value, nil
}
var transformSSHConfig TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case map[string]interface{}:
var result []types.SSHKey
for key, val := range value {
if val == nil {
val = ""
}
result = append(result, types.SSHKey{ID: key, Path: val.(string)})
}
return result, nil
case []interface{}:
var result []types.SSHKey
for _, v := range value {
key, val := transformValueToMapEntry(v.(string), "=", false)
result = append(result, types.SSHKey{ID: key, Path: val.(string)})
}
return result, nil
case string:
if value == "" {
value = "default"
}
key, val := transformValueToMapEntry(value, "=", false)
result := []types.SSHKey{{ID: key, Path: val.(string)}}
return result, nil
}
return nil, errors.Errorf("expected a sting, map or a list, got %T: %#v", data, data)
}
var transformStringOrNumberList TransformerFunc = func(value interface{}) (interface{}, error) {
list := value.([]interface{})
result := make([]string, len(list))
@ -963,47 +1030,52 @@ var transformStringList TransformerFunc = func(data interface{}) (interface{}, e
func transformMappingOrListFunc(sep string, allowNil bool) TransformerFunc {
return func(data interface{}) (interface{}, error) {
return transformMappingOrList(data, sep, allowNil), nil
return transformMappingOrList(data, sep, allowNil)
}
}
func transformListOrMappingFunc(sep string, allowNil bool) TransformerFunc {
return func(data interface{}) (interface{}, error) {
return transformListOrMapping(data, sep, allowNil), nil
return transformListOrMapping(data, sep, allowNil)
}
}
func transformListOrMapping(listOrMapping interface{}, sep string, allowNil bool) interface{} {
func transformListOrMapping(listOrMapping interface{}, sep string, allowNil bool) (interface{}, error) {
switch value := listOrMapping.(type) {
case map[string]interface{}:
return toStringList(value, sep, allowNil)
return toStringList(value, sep, allowNil), nil
case []interface{}:
return listOrMapping
return listOrMapping, nil
}
panic(errors.Errorf("expected a map or a list, got %T: %#v", listOrMapping, listOrMapping))
return nil, errors.Errorf("expected a map or a list, got %T: %#v", listOrMapping, listOrMapping)
}
func transformMappingOrList(mappingOrList interface{}, sep string, allowNil bool) interface{} {
func transformMappingOrList(mappingOrList interface{}, sep string, allowNil bool) (interface{}, error) {
switch value := mappingOrList.(type) {
case map[string]interface{}:
return toMapStringString(value, allowNil)
return toMapStringString(value, allowNil), nil
case []interface{}:
result := make(map[string]interface{})
for _, value := range value {
parts := strings.SplitN(value.(string), sep, 2)
key := parts[0]
switch {
case len(parts) == 1 && allowNil:
result[key] = nil
case len(parts) == 1 && !allowNil:
result[key] = ""
default:
result[key] = parts[1]
}
key, val := transformValueToMapEntry(value.(string), sep, allowNil)
result[key] = val
}
return result
return result, nil
}
return nil, errors.Errorf("expected a map or a list, got %T: %#v", mappingOrList, mappingOrList)
}
func transformValueToMapEntry(value string, separator string, allowNil bool) (string, interface{}) {
parts := strings.SplitN(value, separator, 2)
key := parts[0]
switch {
case len(parts) == 1 && allowNil:
return key, nil
case len(parts) == 1 && !allowNil:
return key, ""
default:
return key, parts[1]
}
panic(errors.Errorf("expected a map or a list, got %T: %#v", mappingOrList, mappingOrList))
}
var transformShellCommand TransformerFunc = func(value interface{}) (interface{}, error) {
@ -1045,6 +1117,8 @@ var transformStringToDuration TransformerFunc = func(value interface{}) (interfa
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)
}

View File

@ -53,6 +53,7 @@ func merge(configs []*types.Config) (*types.Config, error) {
base := configs[0]
for _, override := range configs[1:] {
var err error
base.Name = mergeNames(base.Name, override.Name)
base.Services, err = mergeServices(base.Services, override.Services)
if err != nil {
return base, errors.Wrapf(err, "cannot merge services from %s", override.Filename)
@ -81,6 +82,13 @@ func merge(configs []*types.Config) (*types.Config, error) {
return base, nil
}
func mergeNames(base, override string) string {
if override != "" {
return override
}
return base
}
func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig, error) {
baseServices := mapByName(base)
overrideServices := mapByName(override)
@ -154,7 +162,7 @@ func toServicePortConfigsMap(s interface{}) (map[interface{}]interface{}, error)
m := map[interface{}]interface{}{}
type port struct {
target uint32
published uint32
published string
ip string
protocol string
}
@ -291,7 +299,7 @@ func mergeLoggingConfig(dst, src reflect.Value) error {
return nil
}
//nolint: unparam
// nolint: unparam
func mergeUlimitsConfig(dst, src reflect.Value) error {
if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {
dst.Elem().Set(src.Elem())
@ -299,7 +307,7 @@ func mergeUlimitsConfig(dst, src reflect.Value) error {
return nil
}
//nolint: unparam
// nolint: unparam
func mergeServiceNetworkConfig(dst, src reflect.Value) error {
if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {
dst.Elem().FieldByName("Aliases").Set(src.Elem().FieldByName("Aliases"))

View File

@ -79,7 +79,7 @@ func normalize(project *types.Project, resolvePaths bool) error {
if resolvePaths {
s.Build.Context = localContext
}
} else {
// } 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
}

View File

@ -92,7 +92,7 @@ func populateFieldFromBuffer(char rune, buffer []rune, volume *types.ServiceVolu
volume.Volume = &types.ServiceVolumeVolume{NoCopy: true}
default:
if isBindOption(option) {
volume.Bind = &types.ServiceVolumeBind{Propagation: option}
setBindOption(volume, option)
}
// ignore unknown options
}
@ -109,13 +109,39 @@ var Propagations = []string{
types.PropagationSlave,
}
type setBindOptionFunc func(bind *types.ServiceVolumeBind, option string)
var bindOptions = map[string]setBindOptionFunc{
types.PropagationRPrivate: setBindPropagation,
types.PropagationPrivate: setBindPropagation,
types.PropagationRShared: setBindPropagation,
types.PropagationShared: setBindPropagation,
types.PropagationRSlave: setBindPropagation,
types.PropagationSlave: setBindPropagation,
types.SELinuxShared: setBindSELinux,
types.SELinuxPrivate: setBindSELinux,
}
func setBindPropagation(bind *types.ServiceVolumeBind, option string) {
bind.Propagation = option
}
func setBindSELinux(bind *types.ServiceVolumeBind, option string) {
bind.SELinux = option
}
func isBindOption(option string) bool {
for _, propagation := range Propagations {
if option == propagation {
return true
}
_, ok := bindOptions[option]
return ok
}
func setBindOption(volume *types.ServiceVolumeConfig, option string) {
if volume.Bind == nil {
volume.Bind = &types.ServiceVolumeBind{}
}
return false
bindOptions[option](volume.Bind, option)
}
func populateType(volume *types.ServiceVolumeConfig) {

View File

@ -8,7 +8,12 @@
"properties": {
"version": {
"type": "string",
"description": "Version of the Compose specification used. Tools not implementing required version MUST reject the configuration file."
"description": "declared for backward compatibility, ignored."
},
"name": {
"type": "string",
"description": "define the Compose project name, until user defines one explicitly."
},
"services": {
@ -86,9 +91,13 @@
"context": {"type": "string"},
"dockerfile": {"type": "string"},
"args": {"$ref": "#/definitions/list_or_dict"},
"ssh": {"$ref": "#/definitions/list_or_dict"},
"labels": {"$ref": "#/definitions/list_or_dict"},
"cache_from": {"type": "array", "items": {"type": "string"}},
"cache_to": {"type": "array", "items": {"type": "string"}},
"no_cache": {"type": "boolean"},
"network": {"type": "string"},
"pull": {"type": "boolean"},
"target": {"type": "string"},
"shm_size": {"type": ["integer", "string"]},
"extra_hosts": {"$ref": "#/definitions/list_or_dict"},
@ -318,7 +327,7 @@
"mode": {"type": "string"},
"host_ip": {"type": "string"},
"target": {"type": "integer"},
"published": {"type": "integer"},
"published": {"type": ["string", "integer"]},
"protocol": {"type": "string"}
},
"additionalProperties": false,
@ -410,7 +419,8 @@
"type": "object",
"properties": {
"propagation": {"type": "string"},
"create_host_path": {"type": "boolean"}
"create_host_path": {"type": "boolean"},
"selinux": {"type": "string", "enum": ["z", "Z"]}
},
"additionalProperties": false,
"patternProperties": {"^x-": {}}
@ -519,7 +529,8 @@
"type": "object",
"properties": {
"cpus": {"type": ["number", "string"]},
"memory": {"type": "string"}
"memory": {"type": "string"},
"pids": {"type": "integer"}
},
"additionalProperties": false,
"patternProperties": {"^x-": {}}

View File

@ -27,11 +27,6 @@ import (
_ "embed"
)
const (
defaultVersion = "1.0"
versionField = "version"
)
type portsFormatChecker struct{}
func (checker portsFormatChecker) IsFormat(input interface{}) bool {

View File

@ -26,6 +26,7 @@ import (
var delimiter = "\\$"
var substitutionNamed = "[_a-z][_a-z0-9]*"
var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-?](.*}|[^}]*))?"
var patternString = fmt.Sprintf(
@ -60,15 +61,17 @@ type SubstituteFunc func(string, Mapping) (string, bool, error)
// It accepts additional substitute function.
func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, subsFuncs ...SubstituteFunc) (string, error) {
if len(subsFuncs) == 0 {
subsFuncs = []SubstituteFunc{
softDefault,
hardDefault,
requiredNonEmpty,
required,
}
subsFuncs = getDefaultSortedSubstitutionFunctions(template)
}
var err error
result := pattern.ReplaceAllStringFunc(template, func(substring string) string {
closingBraceIndex := getFirstBraceClosingIndex(substring)
rest := ""
if closingBraceIndex > -1 {
rest = substring[closingBraceIndex+1:]
substring = substring[0 : closingBraceIndex+1]
}
matches := pattern.FindStringSubmatch(substring)
groups := matchGroups(matches, pattern)
if escaped := groups["escaped"]; escaped != "" {
@ -100,7 +103,11 @@ func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, su
if !applied {
continue
}
return value
interpolatedNested, err := SubstituteWith(rest, mapping, pattern, subsFuncs...)
if err != nil {
return ""
}
return value + interpolatedNested
}
}
@ -114,6 +121,42 @@ func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, su
return result, err
}
func getDefaultSortedSubstitutionFunctions(template string, fns ...SubstituteFunc) []SubstituteFunc {
hyphenIndex := strings.IndexByte(template, '-')
questionIndex := strings.IndexByte(template, '?')
if hyphenIndex < 0 || hyphenIndex > questionIndex {
return []SubstituteFunc{
requiredNonEmpty,
required,
softDefault,
hardDefault,
}
}
return []SubstituteFunc{
softDefault,
hardDefault,
requiredNonEmpty,
required,
}
}
func getFirstBraceClosingIndex(s string) int {
openVariableBraces := 0
for i := 0; i < len(s); i++ {
if s[i] == '}' {
openVariableBraces--
if openVariableBraces == 0 {
return i
}
}
if strings.HasPrefix(s[i:], "${") {
openVariableBraces++
i++
}
}
return -1
}
// Substitute variables in the string with their values
func Substitute(template string, mapping Mapping) (string, error) {
return SubstituteWith(template, mapping, defaultPattern)

View File

@ -49,6 +49,7 @@ type ConfigFile struct {
// Config is a full compose file configuration and model
type Config struct {
Filename string `yaml:"-" json:"-"`
Name string `yaml:",omitempty" json:"name,omitempty"`
Services Services `json:"services"`
Networks Networks `yaml:",omitempty" json:"networks,omitempty"`
Volumes Volumes `yaml:",omitempty" json:"volumes,omitempty"`

View File

@ -29,7 +29,7 @@ import (
// Project is the result of loading a set of compose files
type Project struct {
Name string `yaml:"-" json:"-"`
Name string `yaml:"name,omitempty" json:"name,omitempty"`
WorkingDir string `yaml:"-" json:"-"`
Services Services `json:"services"`
Networks Networks `yaml:",omitempty" json:"networks,omitempty"`

View File

@ -88,88 +88,90 @@ type ServiceConfig struct {
Name string `yaml:"-" json:"-"`
Profiles []string `mapstructure:"profiles" yaml:"profiles,omitempty" json:"profiles,omitempty"`
Build *BuildConfig `yaml:",omitempty" json:"build,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"`
CPUCount int64 `mapstructure:"cpu_count" yaml:"cpu_count,omitempty" json:"cpu_count,omitempty"`
CPUPercent float32 `mapstructure:"cpu_percent" yaml:"cpu_percent,omitempty" json:"cpu_percent,omitempty"`
CPUPeriod int64 `mapstructure:"cpu_period" yaml:"cpu_period,omitempty" json:"cpu_period,omitempty"`
CPUQuota int64 `mapstructure:"cpu_quota" yaml:"cpu_quota,omitempty" json:"cpu_quota,omitempty"`
CPURTPeriod int64 `mapstructure:"cpu_rt_period" yaml:"cpu_rt_period,omitempty" json:"cpu_rt_period,omitempty"`
CPURTRuntime int64 `mapstructure:"cpu_rt_runtime" yaml:"cpu_rt_runtime,omitempty" json:"cpu_rt_runtime,omitempty"`
CPUS float32 `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"`
CPUSet string `mapstructure:"cpuset" yaml:"cpuset,omitempty" json:"cpuset,omitempty"`
CPUShares int64 `mapstructure:"cpu_shares" yaml:"cpu_shares,omitempty" json:"cpu_shares,omitempty"`
Command ShellCommand `yaml:",omitempty" json:"command,omitempty"`
Configs []ServiceConfigObjConfig `yaml:",omitempty" json:"configs,omitempty"`
ContainerName string `mapstructure:"container_name" yaml:"container_name,omitempty" json:"container_name,omitempty"`
CredentialSpec *CredentialSpecConfig `mapstructure:"credential_spec" yaml:"credential_spec,omitempty" json:"credential_spec,omitempty"`
DependsOn DependsOnConfig `mapstructure:"depends_on" yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
Deploy *DeployConfig `yaml:",omitempty" json:"deploy,omitempty"`
Devices []string `yaml:",omitempty" json:"devices,omitempty"`
DNS StringList `yaml:",omitempty" json:"dns,omitempty"`
DNSOpts []string `mapstructure:"dns_opt" yaml:"dns_opt,omitempty" json:"dns_opt,omitempty"`
DNSSearch StringList `mapstructure:"dns_search" yaml:"dns_search,omitempty" json:"dns_search,omitempty"`
Dockerfile string `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"`
DomainName string `mapstructure:"domainname" yaml:"domainname,omitempty" json:"domainname,omitempty"`
Entrypoint ShellCommand `yaml:",omitempty" json:"entrypoint,omitempty"`
Environment MappingWithEquals `yaml:",omitempty" json:"environment,omitempty"`
EnvFile StringList `mapstructure:"env_file" yaml:"env_file,omitempty" json:"env_file,omitempty"`
Expose StringOrNumberList `yaml:",omitempty" json:"expose,omitempty"`
Extends ExtendsConfig `yaml:"extends,omitempty" json:"extends,omitempty"`
ExternalLinks []string `mapstructure:"external_links" yaml:"external_links,omitempty" json:"external_links,omitempty"`
ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
GroupAdd []string `mapstructure:"group_add" yaml:"group_add,omitempty" json:"group_add,omitempty"`
Hostname string `yaml:",omitempty" json:"hostname,omitempty"`
HealthCheck *HealthCheckConfig `yaml:",omitempty" json:"healthcheck,omitempty"`
Image string `yaml:",omitempty" json:"image,omitempty"`
Init *bool `yaml:",omitempty" json:"init,omitempty"`
Ipc string `yaml:",omitempty" json:"ipc,omitempty"`
Isolation string `mapstructure:"isolation" yaml:"isolation,omitempty" json:"isolation,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
Links []string `yaml:",omitempty" json:"links,omitempty"`
Logging *LoggingConfig `yaml:",omitempty" json:"logging,omitempty"`
LogDriver string `mapstructure:"log_driver" yaml:"log_driver,omitempty" json:"log_driver,omitempty"`
LogOpt map[string]string `mapstructure:"log_opt" yaml:"log_opt,omitempty" json:"log_opt,omitempty"`
MemLimit UnitBytes `mapstructure:"mem_limit" yaml:"mem_limit,omitempty" json:"mem_limit,omitempty"`
MemReservation UnitBytes `mapstructure:"mem_reservation" yaml:"mem_reservation,omitempty" json:"mem_reservation,omitempty"`
MemSwapLimit UnitBytes `mapstructure:"memswap_limit" yaml:"memswap_limit,omitempty" json:"memswap_limit,omitempty"`
MemSwappiness UnitBytes `mapstructure:"mem_swappiness" yaml:"mem_swappiness,omitempty" json:"mem_swappiness,omitempty"`
MacAddress string `mapstructure:"mac_address" yaml:"mac_address,omitempty" json:"mac_address,omitempty"`
Net string `yaml:"net,omitempty" json:"net,omitempty"`
NetworkMode string `mapstructure:"network_mode" yaml:"network_mode,omitempty" json:"network_mode,omitempty"`
Networks map[string]*ServiceNetworkConfig `yaml:",omitempty" json:"networks,omitempty"`
OomKillDisable bool `mapstructure:"oom_kill_disable" yaml:"oom_kill_disable,omitempty" json:"oom_kill_disable,omitempty"`
OomScoreAdj int64 `mapstructure:"oom_score_adj" yaml:"oom_score_adj,omitempty" json:"oom_score_adj,omitempty"`
Pid string `yaml:",omitempty" json:"pid,omitempty"`
PidsLimit int64 `mapstructure:"pids_limit" yaml:"pids_limit,omitempty" json:"pids_limit,omitempty"`
Platform string `yaml:",omitempty" json:"platform,omitempty"`
Ports []ServicePortConfig `yaml:",omitempty" json:"ports,omitempty"`
Privileged bool `yaml:",omitempty" json:"privileged,omitempty"`
PullPolicy string `mapstructure:"pull_policy" yaml:"pull_policy,omitempty" json:"pull_policy,omitempty"`
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:"-" 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"`
StdinOpen bool `mapstructure:"stdin_open" yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"`
StopGracePeriod *Duration `mapstructure:"stop_grace_period" yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"`
StopSignal string `mapstructure:"stop_signal" yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
Sysctls Mapping `yaml:",omitempty" json:"sysctls,omitempty"`
Tmpfs StringList `yaml:",omitempty" json:"tmpfs,omitempty"`
Tty bool `mapstructure:"tty" yaml:"tty,omitempty" json:"tty,omitempty"`
Ulimits map[string]*UlimitsConfig `yaml:",omitempty" json:"ulimits,omitempty"`
User string `yaml:",omitempty" json:"user,omitempty"`
UserNSMode string `mapstructure:"userns_mode" yaml:"userns_mode,omitempty" json:"userns_mode,omitempty"`
Uts string `yaml:"uts,omitempty" json:"uts,omitempty"`
VolumeDriver string `mapstructure:"volume_driver" yaml:"volume_driver,omitempty" json:"volume_driver,omitempty"`
Volumes []ServiceVolumeConfig `yaml:",omitempty" json:"volumes,omitempty"`
VolumesFrom []string `mapstructure:"volumes_from" yaml:"volumes_from,omitempty" json:"volumes_from,omitempty"`
WorkingDir string `mapstructure:"working_dir" yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
Build *BuildConfig `yaml:",omitempty" json:"build,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"`
CPUCount int64 `mapstructure:"cpu_count" yaml:"cpu_count,omitempty" json:"cpu_count,omitempty"`
CPUPercent float32 `mapstructure:"cpu_percent" yaml:"cpu_percent,omitempty" json:"cpu_percent,omitempty"`
CPUPeriod int64 `mapstructure:"cpu_period" yaml:"cpu_period,omitempty" json:"cpu_period,omitempty"`
CPUQuota int64 `mapstructure:"cpu_quota" yaml:"cpu_quota,omitempty" json:"cpu_quota,omitempty"`
CPURTPeriod int64 `mapstructure:"cpu_rt_period" yaml:"cpu_rt_period,omitempty" json:"cpu_rt_period,omitempty"`
CPURTRuntime int64 `mapstructure:"cpu_rt_runtime" yaml:"cpu_rt_runtime,omitempty" json:"cpu_rt_runtime,omitempty"`
CPUS float32 `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"`
CPUSet string `mapstructure:"cpuset" yaml:"cpuset,omitempty" json:"cpuset,omitempty"`
CPUShares int64 `mapstructure:"cpu_shares" yaml:"cpu_shares,omitempty" json:"cpu_shares,omitempty"`
Command ShellCommand `yaml:",omitempty" json:"command,omitempty"`
Configs []ServiceConfigObjConfig `yaml:",omitempty" json:"configs,omitempty"`
ContainerName string `mapstructure:"container_name" yaml:"container_name,omitempty" json:"container_name,omitempty"`
CredentialSpec *CredentialSpecConfig `mapstructure:"credential_spec" yaml:"credential_spec,omitempty" json:"credential_spec,omitempty"`
DependsOn DependsOnConfig `mapstructure:"depends_on" yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
Deploy *DeployConfig `yaml:",omitempty" json:"deploy,omitempty"`
DeviceCgroupRules []string `mapstructure:"device_cgroup_rules" yaml:"device_cgroup_rules,omitempty" json:"device_cgroup_rules,omitempty"`
Devices []string `yaml:",omitempty" json:"devices,omitempty"`
DNS StringList `yaml:",omitempty" json:"dns,omitempty"`
DNSOpts []string `mapstructure:"dns_opt" yaml:"dns_opt,omitempty" json:"dns_opt,omitempty"`
DNSSearch StringList `mapstructure:"dns_search" yaml:"dns_search,omitempty" json:"dns_search,omitempty"`
Dockerfile string `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"`
DomainName string `mapstructure:"domainname" yaml:"domainname,omitempty" json:"domainname,omitempty"`
Entrypoint ShellCommand `yaml:",omitempty" json:"entrypoint,omitempty"`
Environment MappingWithEquals `yaml:",omitempty" json:"environment,omitempty"`
EnvFile StringList `mapstructure:"env_file" yaml:"env_file,omitempty" json:"env_file,omitempty"`
Expose StringOrNumberList `yaml:",omitempty" json:"expose,omitempty"`
Extends ExtendsConfig `yaml:"extends,omitempty" json:"extends,omitempty"`
ExternalLinks []string `mapstructure:"external_links" yaml:"external_links,omitempty" json:"external_links,omitempty"`
ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
GroupAdd []string `mapstructure:"group_add" yaml:"group_add,omitempty" json:"group_add,omitempty"`
Hostname string `yaml:",omitempty" json:"hostname,omitempty"`
HealthCheck *HealthCheckConfig `yaml:",omitempty" json:"healthcheck,omitempty"`
Image string `yaml:",omitempty" json:"image,omitempty"`
Init *bool `yaml:",omitempty" json:"init,omitempty"`
Ipc string `yaml:",omitempty" json:"ipc,omitempty"`
Isolation string `mapstructure:"isolation" yaml:"isolation,omitempty" json:"isolation,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
CustomLabels Labels `yaml:"-" json:"-"`
Links []string `yaml:",omitempty" json:"links,omitempty"`
Logging *LoggingConfig `yaml:",omitempty" json:"logging,omitempty"`
LogDriver string `mapstructure:"log_driver" yaml:"log_driver,omitempty" json:"log_driver,omitempty"`
LogOpt map[string]string `mapstructure:"log_opt" yaml:"log_opt,omitempty" json:"log_opt,omitempty"`
MemLimit UnitBytes `mapstructure:"mem_limit" yaml:"mem_limit,omitempty" json:"mem_limit,omitempty"`
MemReservation UnitBytes `mapstructure:"mem_reservation" yaml:"mem_reservation,omitempty" json:"mem_reservation,omitempty"`
MemSwapLimit UnitBytes `mapstructure:"memswap_limit" yaml:"memswap_limit,omitempty" json:"memswap_limit,omitempty"`
MemSwappiness UnitBytes `mapstructure:"mem_swappiness" yaml:"mem_swappiness,omitempty" json:"mem_swappiness,omitempty"`
MacAddress string `mapstructure:"mac_address" yaml:"mac_address,omitempty" json:"mac_address,omitempty"`
Net string `yaml:"net,omitempty" json:"net,omitempty"`
NetworkMode string `mapstructure:"network_mode" yaml:"network_mode,omitempty" json:"network_mode,omitempty"`
Networks map[string]*ServiceNetworkConfig `yaml:",omitempty" json:"networks,omitempty"`
OomKillDisable bool `mapstructure:"oom_kill_disable" yaml:"oom_kill_disable,omitempty" json:"oom_kill_disable,omitempty"`
OomScoreAdj int64 `mapstructure:"oom_score_adj" yaml:"oom_score_adj,omitempty" json:"oom_score_adj,omitempty"`
Pid string `yaml:",omitempty" json:"pid,omitempty"`
PidsLimit int64 `mapstructure:"pids_limit" yaml:"pids_limit,omitempty" json:"pids_limit,omitempty"`
Platform string `yaml:",omitempty" json:"platform,omitempty"`
Ports []ServicePortConfig `yaml:",omitempty" json:"ports,omitempty"`
Privileged bool `yaml:",omitempty" json:"privileged,omitempty"`
PullPolicy string `mapstructure:"pull_policy" yaml:"pull_policy,omitempty" json:"pull_policy,omitempty"`
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:"-" 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"`
StdinOpen bool `mapstructure:"stdin_open" yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"`
StopGracePeriod *Duration `mapstructure:"stop_grace_period" yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"`
StopSignal string `mapstructure:"stop_signal" yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
Sysctls Mapping `yaml:",omitempty" json:"sysctls,omitempty"`
Tmpfs StringList `yaml:",omitempty" json:"tmpfs,omitempty"`
Tty bool `mapstructure:"tty" yaml:"tty,omitempty" json:"tty,omitempty"`
Ulimits map[string]*UlimitsConfig `yaml:",omitempty" json:"ulimits,omitempty"`
User string `yaml:",omitempty" json:"user,omitempty"`
UserNSMode string `mapstructure:"userns_mode" yaml:"userns_mode,omitempty" json:"userns_mode,omitempty"`
Uts string `yaml:"uts,omitempty" json:"uts,omitempty"`
VolumeDriver string `mapstructure:"volume_driver" yaml:"volume_driver,omitempty" json:"volume_driver,omitempty"`
Volumes []ServiceVolumeConfig `yaml:",omitempty" json:"volumes,omitempty"`
VolumesFrom []string `mapstructure:"volumes_from" yaml:"volumes_from,omitempty" json:"volumes_from,omitempty"`
WorkingDir string `mapstructure:"working_dir" yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
Extensions map[string]interface{} `yaml:",inline" json:"-"`
}
@ -292,8 +294,12 @@ type BuildConfig struct {
Context string `yaml:",omitempty" json:"context,omitempty"`
Dockerfile string `yaml:",omitempty" json:"dockerfile,omitempty"`
Args MappingWithEquals `yaml:",omitempty" json:"args,omitempty"`
SSH SSHConfig `yaml:"ssh,omitempty" json:"ssh,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
CacheFrom StringList `mapstructure:"cache_from" yaml:"cache_from,omitempty" json:"cache_from,omitempty"`
CacheTo StringList `mapstructure:"cache_to" yaml:"cache_to,omitempty" json:"cache_to,omitempty"`
NoCache bool `mapstructure:"no_cache" yaml:"no_cache,omitempty" json:"no_cache,omitempty"`
Pull bool `mapstructure:"pull" yaml:"pull,omitempty" json:"pull,omitempty"`
ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
Isolation string `yaml:",omitempty" json:"isolation,omitempty"`
Network string `yaml:",omitempty" json:"network,omitempty"`
@ -305,11 +311,11 @@ type BuildConfig struct {
// BlkioConfig define blkio config
type BlkioConfig struct {
Weight uint16 `yaml:",omitempty" json:"weight,omitempty"`
WeightDevice []WeightDevice `yaml:",omitempty" json:"weight_device,omitempty"`
DeviceReadBps []ThrottleDevice `yaml:",omitempty" json:"device_read_bps,omitempty"`
DeviceReadIOps []ThrottleDevice `yaml:",omitempty" json:"device_read_iops,omitempty"`
DeviceWriteBps []ThrottleDevice `yaml:",omitempty" json:"device_write_bps,omitempty"`
DeviceWriteIOps []ThrottleDevice `yaml:",omitempty" json:"device_write_iops,omitempty"`
WeightDevice []WeightDevice `mapstructure:"weight_device" yaml:",omitempty" json:"weight_device,omitempty"`
DeviceReadBps []ThrottleDevice `mapstructure:"device_read_bps" yaml:",omitempty" json:"device_read_bps,omitempty"`
DeviceReadIOps []ThrottleDevice `mapstructure:"device_read_iops" yaml:",omitempty" json:"device_read_iops,omitempty"`
DeviceWriteBps []ThrottleDevice `mapstructure:"device_write_bps" yaml:",omitempty" json:"device_write_bps,omitempty"`
DeviceWriteIOps []ThrottleDevice `mapstructure:"device_write_iops" yaml:",omitempty" json:"device_write_iops,omitempty"`
Extensions map[string]interface{} `yaml:",inline" json:"-"`
}
@ -423,6 +429,39 @@ func (l Labels) Add(key, value string) Labels {
return l
}
type SSHKey struct {
ID string
Path string
}
// SSHConfig is a mapping type for SSH build config
type SSHConfig []SSHKey
func (s SSHConfig) Get(id string) (string, error) {
for _, sshKey := range s {
if sshKey.ID == id {
return sshKey.Path, nil
}
}
return "", fmt.Errorf("ID %s not found in SSH keys", id)
}
// MarshalYAML makes SSHKey implement yaml.Marshaller
func (s SSHKey) MarshalYAML() (interface{}, error) {
if s.Path == "" {
return s.ID, nil
}
return fmt.Sprintf("%s: %s", s.ID, s.Path), nil
}
// MarshalJSON makes SSHKey implement json.Marshaller
func (s SSHKey) MarshalJSON() ([]byte, error) {
if s.Path == "" {
return []byte(fmt.Sprintf(`"%s"`, s.ID)), nil
}
return []byte(fmt.Sprintf(`"%s": %s`, s.ID, s.Path)), nil
}
// MappingWithColon is a mapping type that can be converted from a list of
// 'key: value' strings
type MappingWithColon map[string]string
@ -493,6 +532,7 @@ type Resource struct {
// TODO: types to convert from units and ratios
NanoCPUs string `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"`
MemoryBytes UnitBytes `mapstructure:"memory" yaml:"memory,omitempty" json:"memory,omitempty"`
PIds int64 `mapstructure:"pids" yaml:"pids,omitempty" json:"pids,omitempty"`
Devices []DeviceRequest `mapstructure:"devices" yaml:"devices,omitempty" json:"devices,omitempty"`
GenericResources []GenericResource `mapstructure:"generic_resources" yaml:"generic_resources,omitempty" json:"generic_resources,omitempty"`
@ -579,7 +619,7 @@ type ServicePortConfig struct {
Mode string `yaml:",omitempty" json:"mode,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"`
Published string `yaml:",omitempty" json:"published,omitempty"`
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
Extensions map[string]interface{} `yaml:",inline" json:"-"`
@ -613,21 +653,13 @@ func ParsePortConfig(value string) ([]ServicePortConfig, error) {
func convertPortToPortConfig(port nat.Port, portBindings map[nat.Port][]nat.PortBinding) ([]ServicePortConfig, error) {
var portConfigs []ServicePortConfig
for _, binding := range portBindings[port] {
startHostPort, endHostPort, err := nat.ParsePortRange(binding.HostPort)
if err != nil && binding.HostPort != "" {
return nil, fmt.Errorf("invalid hostport binding (%s) for port (%s)", binding.HostPort, port.Port())
}
for i := startHostPort; i <= endHostPort; i++ {
portConfigs = append(portConfigs, ServicePortConfig{
HostIP: binding.HostIP,
Protocol: strings.ToLower(port.Proto()),
Target: uint32(port.Int()),
Published: uint32(i),
Mode: "ingress",
})
}
portConfigs = append(portConfigs, ServicePortConfig{
HostIP: binding.HostIP,
Protocol: strings.ToLower(port.Proto()),
Target: uint32(port.Int()),
Published: binding.HostPort,
Mode: "ingress",
})
}
return portConfigs, nil
}
@ -655,16 +687,30 @@ const (
VolumeTypeTmpfs = "tmpfs"
// VolumeTypeNamedPipe is the type for mounting Windows named pipes
VolumeTypeNamedPipe = "npipe"
// SElinuxShared share the volume content
SElinuxShared = "z"
// SElinuxUnshared label content as private unshared
SElinuxUnshared = "Z"
)
// ServiceVolumeBind are options for a service volume of type bind
type ServiceVolumeBind struct {
SELinux string `mapstructure:"selinux" yaml:",omitempty" json:"selinux,omitempty"`
Propagation string `yaml:",omitempty" json:"propagation,omitempty"`
CreateHostPath bool `mapstructure:"create_host_path" yaml:"create_host_path,omitempty" json:"create_host_path,omitempty"`
Extensions map[string]interface{} `yaml:",inline" json:"-"`
}
// SELinux represents the SELinux re-labeling options.
const (
// SELinuxShared option indicates that the bind mount content is shared among multiple containers
SELinuxShared string = "z"
// SELinuxPrivate option indicates that the bind mount content is private and unshared
SELinuxPrivate string = "Z"
)
// Propagation represents the propagation of a mount.
const (
// PropagationRPrivate RPRIVATE

View File

@ -1 +0,0 @@
.DS_Store

View File

@ -1,27 +0,0 @@
ARG GOLANG_VERSION=1.17.1
ARG ALPINE_VERSION=3.14
FROM golang:${GOLANG_VERSION}-alpine${ALPINE_VERSION}
WORKDIR /code
code:
FROM +base
COPY . .
golangci:
ARG GOLANGCI_VERSION=v1.40.1
FROM golangci/golangci-lint:${GOLANGCI_VERSION}-alpine
SAVE ARTIFACT /usr/bin/golangci-lint
lint:
FROM +code
COPY +golangci/golangci-lint /usr/bin/golangci-lint
RUN golangci-lint run --timeout 5m ./...
test:
FROM +code
RUN go test ./...
all:
BUILD +lint
BUILD +test

View File

@ -1,18 +0,0 @@
# GoDotEnv
A Go (golang) port of the Ruby dotenv project (which loads env vars from a .env file)
From the original Library:
> Storing configuration in the environment is one of the tenets of a twelve-factor app. Anything that is likely to change between deployment environmentssuch as resource handles for databases or credentials for external servicesshould be extracted from the code into environment variables.
>
> But it is not always practical to set environment variables on development machines or continuous integration servers where multiple projects are run. Dotenv load variables from a .env file into ENV when the environment is bootstrapped.
This is a fork of [joho/godotenv](https://github.com/joho/godotenv) focussing on `.env` file support by the compose specification
To run linter and tests, please install [Earthly](https://earthly.dev/get-earthly) and run:
```sh
earthly +all
```

View File

@ -1,3 +0,0 @@
module github.com/compose-spec/godotenv
go 1.16

View File

View File

@ -1,3 +1,7 @@
## 1.4.3
* Fix cases where `json.Number` didn't decode properly [GH-261]
## 1.4.2
* Custom name matchers to support any sort of casing, formatting, etc. for

View File

@ -684,16 +684,12 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e
}
case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number":
jn := data.(json.Number)
i, err := jn.Int64()
i, err := strconv.ParseUint(string(jn), 0, 64)
if err != nil {
return fmt.Errorf(
"error decoding json.Number into %s: %s", name, err)
}
if i < 0 && !d.config.WeaklyTypedInput {
return fmt.Errorf("cannot parse '%s', %d overflows uint",
name, i)
}
val.SetUint(uint64(i))
val.SetUint(i)
default:
return fmt.Errorf(
"'%s' expected type '%s', got unconvertible type '%s', value: '%v'",

8
vendor/modules.txt vendored
View File

@ -32,16 +32,16 @@ github.com/cenkalti/backoff/v4
github.com/cespare/xxhash/v2
# github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e
## explicit
# github.com/compose-spec/compose-go v1.0.8
# github.com/compose-spec/compose-go v1.2.1
## explicit
github.com/compose-spec/compose-go/consts
github.com/compose-spec/compose-go/dotenv
github.com/compose-spec/compose-go/errdefs
github.com/compose-spec/compose-go/interpolation
github.com/compose-spec/compose-go/loader
github.com/compose-spec/compose-go/schema
github.com/compose-spec/compose-go/template
github.com/compose-spec/compose-go/types
# github.com/compose-spec/godotenv v1.1.1
github.com/compose-spec/godotenv
# github.com/containerd/console v1.0.3
## explicit
github.com/containerd/console
@ -292,7 +292,7 @@ github.com/matttproud/golang_protobuf_extensions/pbutil
github.com/miekg/pkcs11
# github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7
github.com/mitchellh/go-wordwrap
# github.com/mitchellh/mapstructure v1.4.2
# github.com/mitchellh/mapstructure v1.4.3
github.com/mitchellh/mapstructure
# github.com/moby/buildkit v0.10.0
## explicit