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

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2022-08-01 14:12:33 +02:00
parent 7b25e2cffc
commit 52fd555bdd
145 changed files with 10391 additions and 2854 deletions

View File

@ -1,5 +1,7 @@
# passed through
FOO=foo_from_env_file
ENV.WITH.DOT=ok
ENV_WITH_UNDERSCORE=ok
# overridden in example2.env
BAR=bar_from_env_file

View File

@ -25,6 +25,7 @@ services:
tags:
- foo:v1.0.0
- docker.io/username/foo:my-other-tag
- ${COMPOSE_PROJECT_NAME}:1.0.0
cap_add:

View File

@ -17,10 +17,11 @@
package loader
import (
"bytes"
"fmt"
"io/ioutil"
"io"
"os"
"path"
paths "path"
"path/filepath"
"reflect"
"regexp"
@ -42,6 +43,11 @@ import (
"gopkg.in/yaml.v2"
)
const (
DefaultSeparator = "-"
CompatibilitySeparator = "_"
)
// Options supported by Load
type Options struct {
// Skip schema validation
@ -66,6 +72,8 @@ type Options struct {
projectName string
// Indicates when the projectName was imperatively set or guessed from path
projectNameImperativelySet bool
// Set separator used for naming resources
Separator string
}
func (o *Options) SetProjectName(name string, imperativelySet bool) {
@ -154,12 +162,15 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
LookupValue: configDetails.LookupEnv,
TypeCastMapping: interpolateTypeCastMapping,
},
Separator: DefaultSeparator,
}
for _, op := range options {
op(opts)
}
projectName := projectName(configDetails, opts)
var configs []*types.Config
for i, file := range configDetails.ConfigFiles {
configDict := file.Config
@ -207,15 +218,6 @@ 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: projectName,
WorkingDir: configDetails.WorkingDir,
@ -229,7 +231,7 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
}
if !opts.SkipNormalization {
err = normalize(project, opts.ResolvePaths)
err = normalize(project, opts.ResolvePaths, opts.Separator)
if err != nil {
return nil, err
}
@ -245,6 +247,30 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
return project, nil
}
func projectName(details types.ConfigDetails, opts *Options) string {
projectName, projectNameImperativelySet := opts.GetProjectName()
var pjNameFromConfigFile string
for _, configFile := range details.ConfigFiles {
yml, err := ParseYAML(configFile.Content)
if err != nil {
return ""
}
if val, ok := yml["name"]; ok && val != "" {
pjNameFromConfigFile = yml["name"].(string)
}
}
pjNameFromConfigFile = NormalizeProjectName(pjNameFromConfigFile)
if !projectNameImperativelySet && pjNameFromConfigFile != "" {
projectName = pjNameFromConfigFile
}
if _, ok := details.Environment[consts.ComposeProjectName]; !ok && projectName != "" {
details.Environment[consts.ComposeProjectName] = projectName
}
return projectName
}
func NormalizeProjectName(s string) string {
r := regexp.MustCompile("[a-z0-9_-]")
s = strings.ToLower(s)
@ -507,12 +533,12 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
// Resolve the path to the imported file, and load it.
baseFilePath := absPath(workingDir, *file)
bytes, err := ioutil.ReadFile(baseFilePath)
b, err := os.ReadFile(baseFilePath)
if err != nil {
return nil, err
}
baseFile, err := parseConfig(bytes, opts)
baseFile, err := parseConfig(b, opts)
if err != nil {
return nil, err
}
@ -606,14 +632,25 @@ func resolveEnvironment(serviceConfig *types.ServiceConfig, workingDir string, l
environment := types.MappingWithEquals{}
if len(serviceConfig.EnvFile) > 0 {
if serviceConfig.Environment == nil {
serviceConfig.Environment = types.MappingWithEquals{}
}
for _, envFile := range serviceConfig.EnvFile {
filePath := absPath(workingDir, envFile)
file, err := os.Open(filePath)
if err != nil {
return err
}
defer file.Close()
fileVars, err := dotenv.ParseWithLookup(file, dotenv.LookupFn(lookupEnv))
b, err := io.ReadAll(file)
if err != nil {
return err
}
// Do not defer to avoid it inside a loop
file.Close() //nolint:errcheck
fileVars, err := dotenv.ParseWithLookup(bytes.NewBuffer(b), dotenv.LookupFn(lookupEnv))
if err != nil {
return err
}
@ -639,7 +676,7 @@ func resolveVolumePath(volume types.ServiceVolumeConfig, workingDir string, look
// 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) {
if !paths.IsAbs(filePath) && !isAbs(filePath) {
filePath = absPath(workingDir, filePath)
}
volume.Source = filePath
@ -793,10 +830,8 @@ func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfi
logrus.Warnf("%[1]s %[2]s: %[1]s.external.name is deprecated in favor of %[1]s.name", objType, name)
obj.Name = obj.External.Name
obj.External.Name = ""
} else {
if obj.Name == "" {
obj.Name = name
}
} else if obj.Name == "" {
obj.Name = name
}
// if not "external: true"
case obj.Driver != "":
@ -928,7 +963,7 @@ func cleanTarget(target string) string {
if target == "" {
return ""
}
return path.Clean(target)
return paths.Clean(target)
}
var transformBuildConfig TransformerFunc = func(data interface{}) (interface{}, error) {

View File

@ -299,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())
@ -307,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

@ -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, resolvePaths bool) error {
func normalize(project *types.Project, resolvePaths bool, separator string) error {
absWorkingDir, err := filepath.Abs(project.WorkingDir)
if err != nil {
return err
@ -110,7 +110,7 @@ func normalize(project *types.Project, resolvePaths bool) error {
project.Services[i] = s
}
setNameFromKey(project)
setNameFromKey(project, separator)
return nil
}
@ -143,31 +143,31 @@ func absComposeFiles(composeFiles []string) ([]string, error) {
}
// Resources with no explicit name are actually named by their key in map
func setNameFromKey(project *types.Project) {
func setNameFromKey(project *types.Project, separator string) {
for i, n := range project.Networks {
if n.Name == "" {
n.Name = fmt.Sprintf("%s_%s", project.Name, i)
n.Name = fmt.Sprintf("%s%s%s", project.Name, separator, i)
project.Networks[i] = n
}
}
for i, v := range project.Volumes {
if v.Name == "" {
v.Name = fmt.Sprintf("%s_%s", project.Name, i)
v.Name = fmt.Sprintf("%s%s%s", project.Name, separator, i)
project.Volumes[i] = v
}
}
for i, c := range project.Configs {
if c.Name == "" {
c.Name = fmt.Sprintf("%s_%s", project.Name, i)
c.Name = fmt.Sprintf("%s%s%s", project.Name, separator, i)
project.Configs[i] = c
}
}
for i, s := range project.Secrets {
if s.Name == "" {
s.Name = fmt.Sprintf("%s_%s", project.Name, i)
s.Name = fmt.Sprintf("%s%s%s", project.Name, separator, i)
project.Secrets[i] = s
}
}

View File

@ -38,6 +38,12 @@ func checkConsistency(project *types.Project) error {
}
}
for dependedService := range s.DependsOn {
if _, err := project.GetService(dependedService); err != nil {
return errors.Wrap(errdefs.ErrInvalid, fmt.Sprintf("service %q depends on undefined service %s", s.Name, dependedService))
}
}
if strings.HasPrefix(s.NetworkMode, types.ServicePrefix) {
serviceName := s.NetworkMode[len(types.ServicePrefix):]
if _, err := project.GetServices(serviceName); err != nil {
@ -46,12 +52,9 @@ func checkConsistency(project *types.Project) error {
}
for _, volume := range s.Volumes {
switch volume.Type {
case types.VolumeTypeVolume:
if volume.Source != "" { // non anonymous volumes
if _, ok := project.Volumes[volume.Source]; !ok {
return errors.Wrap(errdefs.ErrInvalid, fmt.Sprintf("service %q refers to undefined volume %s", s.Name, volume.Source))
}
if volume.Type == types.VolumeTypeVolume && volume.Source != "" { // non anonymous volumes
if _, ok := project.Volumes[volume.Source]; !ok {
return errors.Wrap(errdefs.ErrInvalid, fmt.Sprintf("service %q refers to undefined volume %s", s.Name, volume.Source))
}
}
}

View File

@ -44,7 +44,7 @@ func isAbs(path string) (b bool) {
// volumeNameLen returns length of the leading volume name on Windows.
// It returns 0 elsewhere.
// nolint: gocyclo
//nolint: gocyclo
func volumeNameLen(path string) int {
if len(path) < 2 {
return 0