mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-01 00:23:56 +08:00 
			
		
		
		
	bump compose-go version to v1.17.0 to fix issue with depends_on
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
This commit is contained in:
		 Guillaume Lours
					Guillaume Lours
				
			
				
					committed by
					
						 CrazyMax
						CrazyMax
					
				
			
			
				
	
			
			
			 CrazyMax
						CrazyMax
					
				
			
						parent
						
							50fbdd86f9
						
					
				
				
					commit
					f3775c0046
				
			
							
								
								
									
										62
									
								
								vendor/github.com/compose-spec/compose-go/cli/options.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										62
									
								
								vendor/github.com/compose-spec/compose-go/cli/options.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,7 +17,6 @@ | ||||
| package cli | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| @@ -250,7 +249,7 @@ func WithDotEnv(o *ProjectOptions) error { | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	envMap, err := GetEnvFromFile(o.Environment, wd, o.EnvFiles) | ||||
| 	envMap, err := dotenv.GetEnvFromFile(o.Environment, wd, o.EnvFiles) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -262,65 +261,6 @@ func WithDotEnv(o *ProjectOptions) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func GetEnvFromFile(currentEnv map[string]string, workingDir string, filenames []string) (map[string]string, error) { | ||||
| 	envMap := make(map[string]string) | ||||
|  | ||||
| 	dotEnvFiles := filenames | ||||
| 	if len(dotEnvFiles) == 0 { | ||||
| 		dotEnvFiles = append(dotEnvFiles, filepath.Join(workingDir, ".env")) | ||||
| 	} | ||||
| 	for _, dotEnvFile := range dotEnvFiles { | ||||
| 		abs, err := filepath.Abs(dotEnvFile) | ||||
| 		if err != nil { | ||||
| 			return envMap, err | ||||
| 		} | ||||
| 		dotEnvFile = abs | ||||
|  | ||||
| 		s, err := os.Stat(dotEnvFile) | ||||
| 		if os.IsNotExist(err) { | ||||
| 			if len(filenames) == 0 { | ||||
| 				return envMap, nil | ||||
| 			} | ||||
| 			return envMap, errors.Errorf("Couldn't find env file: %s", dotEnvFile) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return envMap, err | ||||
| 		} | ||||
|  | ||||
| 		if s.IsDir() { | ||||
| 			if len(filenames) == 0 { | ||||
| 				return envMap, nil | ||||
| 			} | ||||
| 			return envMap, errors.Errorf("%s is a directory", dotEnvFile) | ||||
| 		} | ||||
|  | ||||
| 		b, err := os.ReadFile(dotEnvFile) | ||||
| 		if os.IsNotExist(err) { | ||||
| 			return nil, errors.Errorf("Couldn't read env file: %s", dotEnvFile) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return envMap, err | ||||
| 		} | ||||
|  | ||||
| 		env, err := dotenv.ParseWithLookup(bytes.NewReader(b), func(k string) (string, bool) { | ||||
| 			v, ok := currentEnv[k] | ||||
| 			if ok { | ||||
| 				return v, true | ||||
| 			} | ||||
| 			v, ok = envMap[k] | ||||
| 			return v, ok | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile) | ||||
| 		} | ||||
| 		for k, v := range env { | ||||
| 			envMap[k] = v | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return envMap, nil | ||||
| } | ||||
|  | ||||
| // WithInterpolation set ProjectOptions to enable/skip interpolation | ||||
| func WithInterpolation(interpolation bool) ProjectOptionsFn { | ||||
| 	return func(o *ProjectOptions) error { | ||||
|   | ||||
							
								
								
									
										84
									
								
								vendor/github.com/compose-spec/compose-go/dotenv/env.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								vendor/github.com/compose-spec/compose-go/dotenv/env.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| /* | ||||
|    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 dotenv | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| func GetEnvFromFile(currentEnv map[string]string, workingDir string, filenames []string) (map[string]string, error) { | ||||
| 	envMap := make(map[string]string) | ||||
|  | ||||
| 	dotEnvFiles := filenames | ||||
| 	if len(dotEnvFiles) == 0 { | ||||
| 		dotEnvFiles = append(dotEnvFiles, filepath.Join(workingDir, ".env")) | ||||
| 	} | ||||
| 	for _, dotEnvFile := range dotEnvFiles { | ||||
| 		abs, err := filepath.Abs(dotEnvFile) | ||||
| 		if err != nil { | ||||
| 			return envMap, err | ||||
| 		} | ||||
| 		dotEnvFile = abs | ||||
|  | ||||
| 		s, err := os.Stat(dotEnvFile) | ||||
| 		if os.IsNotExist(err) { | ||||
| 			if len(filenames) == 0 { | ||||
| 				return envMap, nil | ||||
| 			} | ||||
| 			return envMap, errors.Errorf("Couldn't find env file: %s", dotEnvFile) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return envMap, err | ||||
| 		} | ||||
|  | ||||
| 		if s.IsDir() { | ||||
| 			if len(filenames) == 0 { | ||||
| 				return envMap, nil | ||||
| 			} | ||||
| 			return envMap, errors.Errorf("%s is a directory", dotEnvFile) | ||||
| 		} | ||||
|  | ||||
| 		b, err := os.ReadFile(dotEnvFile) | ||||
| 		if os.IsNotExist(err) { | ||||
| 			return nil, errors.Errorf("Couldn't read env file: %s", dotEnvFile) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return envMap, err | ||||
| 		} | ||||
|  | ||||
| 		env, err := ParseWithLookup(bytes.NewReader(b), func(k string) (string, bool) { | ||||
| 			v, ok := currentEnv[k] | ||||
| 			if ok { | ||||
| 				return v, true | ||||
| 			} | ||||
| 			v, ok = envMap[k] | ||||
| 			return v, ok | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile) | ||||
| 		} | ||||
| 		for k, v := range env { | ||||
| 			envMap[k] = v | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return envMap, nil | ||||
| } | ||||
							
								
								
									
										13
									
								
								vendor/github.com/compose-spec/compose-go/dotenv/parser.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/compose-spec/compose-go/dotenv/parser.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -123,8 +123,8 @@ loop: | ||||
| 			} | ||||
|  | ||||
| 			return "", "", inherited, fmt.Errorf( | ||||
| 				`line %d: unexpected character %q in variable name`, | ||||
| 				p.line, string(rune)) | ||||
| 				`line %d: unexpected character %q in variable name %q`, | ||||
| 				p.line, string(rune), strings.Split(src, "\n")[0]) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -153,17 +153,24 @@ func (p *parser) extractVarValue(src string, envMap map[string]string, lookupFn | ||||
| 		return retVal, rest, err | ||||
| 	} | ||||
|  | ||||
| 	previousCharIsEscape := false | ||||
| 	// lookup quoted string terminator | ||||
| 	for i := 1; i < len(src); i++ { | ||||
| 		if src[i] == '\n' { | ||||
| 			p.line++ | ||||
| 		} | ||||
| 		if char := src[i]; char != quote { | ||||
| 			if !previousCharIsEscape && char == '\\' { | ||||
| 				previousCharIsEscape = true | ||||
| 			} else { | ||||
| 				previousCharIsEscape = false | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// skip escaped quote symbol (\" or \', depends on quote) | ||||
| 		if prevChar := src[i-1]; prevChar == '\\' { | ||||
| 		if previousCharIsEscape { | ||||
| 			previousCharIsEscape = false | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/compose-spec/compose-go/loader/full-example.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/compose-spec/compose-go/loader/full-example.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -24,7 +24,7 @@ services: | ||||
|         - bar | ||||
|       labels: [FOO=BAR] | ||||
|       additional_contexts: | ||||
|         foo: /bar | ||||
|         foo: ./bar | ||||
|       secrets: | ||||
|         - secret1 | ||||
|         - source: secret2 | ||||
| @@ -181,6 +181,7 @@ services: | ||||
|       timeout: 1s | ||||
|       retries: 5 | ||||
|       start_period: 15s | ||||
|       start_interval: 5s | ||||
|  | ||||
|     # Any valid image reference - repo, tag, id, sha | ||||
|     image: redis | ||||
|   | ||||
							
								
								
									
										120
									
								
								vendor/github.com/compose-spec/compose-go/loader/include.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								vendor/github.com/compose-spec/compose-go/loader/include.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| /* | ||||
|    Copyright 2020 The Compose Specification Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package loader | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/compose-spec/compose-go/dotenv" | ||||
| 	"github.com/compose-spec/compose-go/types" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // LoadIncludeConfig parse the require config from raw yaml | ||||
| func LoadIncludeConfig(source []interface{}) ([]types.IncludeConfig, error) { | ||||
| 	var requires []types.IncludeConfig | ||||
| 	err := Transform(source, &requires) | ||||
| 	return requires, err | ||||
| } | ||||
|  | ||||
| var transformIncludeConfig TransformerFunc = func(data interface{}) (interface{}, error) { | ||||
| 	switch value := data.(type) { | ||||
| 	case string: | ||||
| 		return map[string]interface{}{"path": value}, nil | ||||
| 	case map[string]interface{}: | ||||
| 		return value, nil | ||||
| 	default: | ||||
| 		return data, errors.Errorf("invalid type %T for `include` configuration", value) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func loadInclude(configDetails types.ConfigDetails, model *types.Config, options *Options, loaded []string) (*types.Config, error) { | ||||
| 	for _, r := range model.Include { | ||||
| 		for i, p := range r.Path { | ||||
| 			if !filepath.IsAbs(p) { | ||||
| 				r.Path[i] = filepath.Join(configDetails.WorkingDir, p) | ||||
| 			} | ||||
| 		} | ||||
| 		if r.ProjectDirectory == "" { | ||||
| 			r.ProjectDirectory = filepath.Dir(r.Path[0]) | ||||
| 		} | ||||
|  | ||||
| 		loadOptions := options.clone() | ||||
| 		loadOptions.SetProjectName(model.Name, true) | ||||
| 		loadOptions.ResolvePaths = true | ||||
| 		loadOptions.SkipNormalization = true | ||||
| 		loadOptions.SkipConsistencyCheck = true | ||||
|  | ||||
| 		env, err := dotenv.GetEnvFromFile(configDetails.Environment, r.ProjectDirectory, r.EnvFile) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		imported, err := load(types.ConfigDetails{ | ||||
| 			WorkingDir:  r.ProjectDirectory, | ||||
| 			ConfigFiles: types.ToConfigFiles(r.Path), | ||||
| 			Environment: env, | ||||
| 		}, loadOptions, loaded) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		err = importResources(model, imported, r.Path) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	model.Include = nil | ||||
| 	return model, nil | ||||
| } | ||||
|  | ||||
| // importResources import into model all resources defined by imported, and report error on conflict | ||||
| func importResources(model *types.Config, imported *types.Project, path []string) error { | ||||
| 	services := mapByName(model.Services) | ||||
| 	for _, service := range imported.Services { | ||||
| 		if _, ok := services[service.Name]; ok { | ||||
| 			return fmt.Errorf("imported compose file %s defines conflicting service %s", path, service.Name) | ||||
| 		} | ||||
| 		model.Services = append(model.Services, service) | ||||
| 	} | ||||
| 	for n, network := range imported.Networks { | ||||
| 		if _, ok := model.Networks[n]; ok { | ||||
| 			return fmt.Errorf("imported compose file %s defines conflicting network %s", path, n) | ||||
| 		} | ||||
| 		model.Networks[n] = network | ||||
| 	} | ||||
| 	for n, volume := range imported.Volumes { | ||||
| 		if _, ok := model.Volumes[n]; ok { | ||||
| 			return fmt.Errorf("imported compose file %s defines conflicting volume %s", path, n) | ||||
| 		} | ||||
| 		model.Volumes[n] = volume | ||||
| 	} | ||||
| 	for n, secret := range imported.Secrets { | ||||
| 		if _, ok := model.Secrets[n]; ok { | ||||
| 			return fmt.Errorf("imported compose file %s defines conflicting secret %s", path, n) | ||||
| 		} | ||||
| 		model.Secrets[n] = secret | ||||
| 	} | ||||
| 	for n, config := range imported.Configs { | ||||
| 		if _, ok := model.Configs[n]; ok { | ||||
| 			return fmt.Errorf("imported compose file %s defines conflicting config %s", path, n) | ||||
| 		} | ||||
| 		model.Configs[n] = config | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										203
									
								
								vendor/github.com/compose-spec/compose-go/loader/loader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										203
									
								
								vendor/github.com/compose-spec/compose-go/loader/loader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -56,6 +56,8 @@ type Options struct { | ||||
| 	SkipConsistencyCheck bool | ||||
| 	// Skip extends | ||||
| 	SkipExtends bool | ||||
| 	// SkipInclude will ignore `include` and only load model from file(s) set by ConfigDetails | ||||
| 	SkipInclude bool | ||||
| 	// Interpolation options | ||||
| 	Interpolate *interp.Options | ||||
| 	// Discard 'env_file' entries after resolving to 'environment' section | ||||
| @@ -68,6 +70,24 @@ type Options struct { | ||||
| 	Profiles []string | ||||
| } | ||||
|  | ||||
| func (o *Options) clone() *Options { | ||||
| 	return &Options{ | ||||
| 		SkipValidation:             o.SkipValidation, | ||||
| 		SkipInterpolation:          o.SkipInterpolation, | ||||
| 		SkipNormalization:          o.SkipNormalization, | ||||
| 		ResolvePaths:               o.ResolvePaths, | ||||
| 		ConvertWindowsPaths:        o.ConvertWindowsPaths, | ||||
| 		SkipConsistencyCheck:       o.SkipConsistencyCheck, | ||||
| 		SkipExtends:                o.SkipExtends, | ||||
| 		SkipInclude:                o.SkipInclude, | ||||
| 		Interpolate:                o.Interpolate, | ||||
| 		discardEnvFiles:            o.discardEnvFiles, | ||||
| 		projectName:                o.projectName, | ||||
| 		projectNameImperativelySet: o.projectNameImperativelySet, | ||||
| 		Profiles:                   o.Profiles, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *Options) SetProjectName(name string, imperativelySet bool) { | ||||
| 	o.projectName = name | ||||
| 	o.projectNameImperativelySet = imperativelySet | ||||
| @@ -185,6 +205,7 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types. | ||||
| 			LookupValue:     configDetails.LookupEnv, | ||||
| 			TypeCastMapping: interpolateTypeCastMapping, | ||||
| 		}, | ||||
| 		ResolvePaths: true, | ||||
| 	} | ||||
|  | ||||
| 	for _, op := range options { | ||||
| @@ -195,8 +216,22 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types. | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	opts.projectName = projectName | ||||
| 	return load(configDetails, opts, nil) | ||||
| } | ||||
|  | ||||
| func load(configDetails types.ConfigDetails, opts *Options, loaded []string) (*types.Project, error) { | ||||
| 	var model *types.Config | ||||
|  | ||||
| 	mainFile := configDetails.ConfigFiles[0].Filename | ||||
| 	for _, f := range loaded { | ||||
| 		if f == mainFile { | ||||
| 			loaded = append(loaded, mainFile) | ||||
| 			return nil, errors.Errorf("include cycle detected:\n%s\n include %s", loaded[0], strings.Join(loaded[1:], "\n include ")) | ||||
| 		} | ||||
| 	} | ||||
| 	loaded = append(loaded, mainFile) | ||||
|  | ||||
| 	for i, file := range configDetails.ConfigFiles { | ||||
| 		var postProcessor PostProcessor | ||||
| 		configDict := file.Config | ||||
| @@ -231,10 +266,18 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types. | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		if !opts.SkipInclude { | ||||
| 			cfg, err = loadInclude(configDetails, cfg, opts, loaded) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if i == 0 { | ||||
| 			model = cfg | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		merged, err := merge([]*types.Config{model, cfg}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| @@ -248,16 +291,8 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types. | ||||
| 		model = merged | ||||
| 	} | ||||
|  | ||||
| 	for _, s := range model.Services { | ||||
| 		var newEnvFiles types.StringList | ||||
| 		for _, ef := range s.EnvFile { | ||||
| 			newEnvFiles = append(newEnvFiles, absPath(configDetails.WorkingDir, ef)) | ||||
| 		} | ||||
| 		s.EnvFile = newEnvFiles | ||||
| 	} | ||||
|  | ||||
| 	project := &types.Project{ | ||||
| 		Name:        projectName, | ||||
| 		Name:        opts.projectName, | ||||
| 		WorkingDir:  configDetails.WorkingDir, | ||||
| 		Services:    model.Services, | ||||
| 		Networks:    model.Networks, | ||||
| @@ -269,14 +304,30 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types. | ||||
| 	} | ||||
|  | ||||
| 	if !opts.SkipNormalization { | ||||
| 		err = Normalize(project, opts.ResolvePaths) | ||||
| 		err := Normalize(project) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if opts.ResolvePaths { | ||||
| 		err := ResolveRelativePaths(project) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if opts.ConvertWindowsPaths { | ||||
| 		for i, service := range project.Services { | ||||
| 			for j, volume := range service.Volumes { | ||||
| 				service.Volumes[j] = convertVolumePath(volume) | ||||
| 			} | ||||
| 			project.Services[i] = service | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !opts.SkipConsistencyCheck { | ||||
| 		err = checkConsistency(project) | ||||
| 		err := checkConsistency(project) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -287,7 +338,7 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types. | ||||
| 	} | ||||
| 	project.ApplyProfiles(opts.Profiles) | ||||
|  | ||||
| 	err = project.ResolveServicesEnvironment(opts.discardEnvFiles) | ||||
| 	err := project.ResolveServicesEnvironment(opts.discardEnvFiles) | ||||
|  | ||||
| 	return project, err | ||||
| } | ||||
| @@ -419,7 +470,6 @@ func loadSections(filename string, config map[string]interface{}, configDetails | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	cfg.Networks, err = LoadNetworks(getSection(config, "networks")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @@ -428,11 +478,15 @@ func loadSections(filename string, config map[string]interface{}, configDetails | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cfg.Secrets, err = LoadSecrets(getSection(config, "secrets"), configDetails, opts.ResolvePaths) | ||||
| 	cfg.Secrets, err = LoadSecrets(getSection(config, "secrets")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cfg.Configs, err = LoadConfigObjs(getSection(config, "configs"), configDetails, opts.ResolvePaths) | ||||
| 	cfg.Configs, err = LoadConfigObjs(getSection(config, "configs")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cfg.Include, err = LoadIncludeConfig(getSequence(config, "include")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -451,6 +505,14 @@ func getSection(config map[string]interface{}, key string) map[string]interface{ | ||||
| 	return section.(map[string]interface{}) | ||||
| } | ||||
|  | ||||
| func getSequence(config map[string]interface{}, key string) []interface{} { | ||||
| 	section, ok := config[key] | ||||
| 	if !ok { | ||||
| 		return make([]interface{}, 0) | ||||
| 	} | ||||
| 	return section.([]interface{}) | ||||
| } | ||||
|  | ||||
| // ForbiddenPropertiesError is returned when there are properties in the Compose | ||||
| // file that are forbidden. | ||||
| type ForbiddenPropertiesError struct { | ||||
| @@ -515,6 +577,7 @@ func createTransformHook(additionalTransformers ...Transformer) mapstructure.Dec | ||||
| 		reflect.TypeOf(types.ExtendsConfig{}):                    transformExtendsConfig, | ||||
| 		reflect.TypeOf(types.DeviceRequest{}):                    transformServiceDeviceRequest, | ||||
| 		reflect.TypeOf(types.SSHConfig{}):                        transformSSHConfig, | ||||
| 		reflect.TypeOf(types.IncludeConfig{}):                    transformIncludeConfig, | ||||
| 	} | ||||
|  | ||||
| 	for _, transformer := range additionalTransformers { | ||||
| @@ -605,6 +668,7 @@ func LoadServices(filename string, servicesDict map[string]interface{}, workingD | ||||
| 		for k, v := range x.(map[string]interface{}) { | ||||
| 			servicesDict[k] = v | ||||
| 		} | ||||
| 		delete(servicesDict, extensions) | ||||
| 	} | ||||
|  | ||||
| 	for name := range servicesDict { | ||||
| @@ -633,7 +697,7 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter | ||||
| 		target = map[string]interface{}{} | ||||
| 	} | ||||
|  | ||||
| 	serviceConfig, err := LoadService(name, target.(map[string]interface{}), workingDir, lookupEnv, opts.ResolvePaths, opts.ConvertWindowsPaths) | ||||
| 	serviceConfig, err := LoadService(name, target.(map[string]interface{})) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -671,21 +735,9 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter | ||||
| 			// make the paths relative to `file` rather than `baseFilePath` so | ||||
| 			// that the resulting paths won't be absolute if `file` isn't an | ||||
| 			// absolute path. | ||||
|  | ||||
| 			baseFileParent := filepath.Dir(file) | ||||
| 			if baseService.Build != nil { | ||||
| 				baseService.Build.Context = resolveBuildContextPath(baseFileParent, baseService.Build.Context) | ||||
| 			} | ||||
|  | ||||
| 			for i, vol := range baseService.Volumes { | ||||
| 				if vol.Type != types.VolumeTypeBind { | ||||
| 					continue | ||||
| 				} | ||||
| 				baseService.Volumes[i].Source = resolveMaybeUnixPath(vol.Source, baseFileParent, lookupEnv) | ||||
| 			} | ||||
|  | ||||
| 			for i, envFile := range baseService.EnvFile { | ||||
| 				baseService.EnvFile[i] = resolveMaybeUnixPath(envFile, baseFileParent, lookupEnv) | ||||
| 			} | ||||
| 			ResolveServiceRelativePaths(baseFileParent, baseService) | ||||
| 		} | ||||
|  | ||||
| 		serviceConfig, err = _merge(baseService, serviceConfig) | ||||
| @@ -698,22 +750,9 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter | ||||
| 	return serviceConfig, nil | ||||
| } | ||||
|  | ||||
| func resolveBuildContextPath(baseFileParent string, context string) string { | ||||
| 	// Checks if the context is an HTTP(S) URL or a remote git repository URL | ||||
| 	for _, prefix := range []string{"https://", "http://", "git://", "github.com/", "git@"} { | ||||
| 		if strings.HasPrefix(context, prefix) { | ||||
| 			return context | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Note that the Dockerfile is always defined relative to the | ||||
| 	// build context, so there's no need to update the Dockerfile field. | ||||
| 	return absPath(baseFileParent, context) | ||||
| } | ||||
|  | ||||
| // 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, resolvePaths bool, convertPaths bool) (*types.ServiceConfig, error) { | ||||
| func LoadService(name string, serviceDict map[string]interface{}) (*types.ServiceConfig, error) { | ||||
| 	serviceConfig := &types.ServiceConfig{ | ||||
| 		Scale: 1, | ||||
| 	} | ||||
| @@ -730,13 +769,6 @@ func LoadService(name string, serviceDict map[string]interface{}, workingDir str | ||||
| 			return nil, errors.New(`invalid mount config for type "bind": field Source must not be empty`) | ||||
| 		} | ||||
|  | ||||
| 		if resolvePaths || convertPaths { | ||||
| 			volume = resolveVolumePath(volume, workingDir, lookupEnv) | ||||
| 		} | ||||
|  | ||||
| 		if convertPaths { | ||||
| 			volume = convertVolumePath(volume) | ||||
| 		} | ||||
| 		serviceConfig.Volumes[i] = volume | ||||
| 	} | ||||
|  | ||||
| @@ -758,8 +790,8 @@ func convertVolumePath(volume types.ServiceVolumeConfig) types.ServiceVolumeConf | ||||
| 	return volume | ||||
| } | ||||
|  | ||||
| func resolveMaybeUnixPath(path string, workingDir string, lookupEnv template.Mapping) string { | ||||
| 	filePath := expandUser(path, lookupEnv) | ||||
| func resolveMaybeUnixPath(workingDir string, path string) string { | ||||
| 	filePath := expandUser(path) | ||||
| 	// Check if source is an absolute path (either Unix or Windows), to | ||||
| 	// handle a Windows client with a Unix daemon or vice-versa. | ||||
| 	// | ||||
| @@ -772,20 +804,8 @@ func resolveMaybeUnixPath(path string, workingDir string, lookupEnv template.Map | ||||
| 	return filePath | ||||
| } | ||||
|  | ||||
| func resolveVolumePath(volume types.ServiceVolumeConfig, workingDir string, lookupEnv template.Mapping) types.ServiceVolumeConfig { | ||||
| 	volume.Source = resolveMaybeUnixPath(volume.Source, workingDir, lookupEnv) | ||||
| 	return volume | ||||
| } | ||||
|  | ||||
| func resolveSecretsPath(secret types.SecretConfig, workingDir string, lookupEnv template.Mapping) types.SecretConfig { | ||||
| 	if !secret.External.External && secret.File != "" { | ||||
| 		secret.File = resolveMaybeUnixPath(secret.File, workingDir, lookupEnv) | ||||
| 	} | ||||
| 	return secret | ||||
| } | ||||
|  | ||||
| // TODO: make this more robust | ||||
| func expandUser(path string, lookupEnv template.Mapping) string { | ||||
| func expandUser(path string) string { | ||||
| 	if strings.HasPrefix(path, "~") { | ||||
| 		home, err := os.UserHomeDir() | ||||
| 		if err != nil { | ||||
| @@ -885,44 +905,39 @@ 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, resolvePaths bool) (map[string]types.SecretConfig, error) { | ||||
| func LoadSecrets(source map[string]interface{}) (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, false) | ||||
| 		obj, err := loadFileObjectConfig(name, "secret", types.FileObjectConfig(secret)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		secretConfig := types.SecretConfig(obj) | ||||
| 		if resolvePaths { | ||||
| 			secretConfig = resolveSecretsPath(secretConfig, details.WorkingDir, details.LookupEnv) | ||||
| 		} | ||||
| 		secrets[name] = secretConfig | ||||
| 		secrets[name] = types.SecretConfig(obj) | ||||
| 	} | ||||
| 	return secrets, nil | ||||
| } | ||||
|  | ||||
| // 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, resolvePaths bool) (map[string]types.ConfigObjConfig, error) { | ||||
| func LoadConfigObjs(source map[string]interface{}) (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, resolvePaths) | ||||
| 		obj, err := loadFileObjectConfig(name, "config", types.FileObjectConfig(config)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		configConfig := types.ConfigObjConfig(obj) | ||||
| 		configs[name] = configConfig | ||||
| 		configs[name] = types.ConfigObjConfig(obj) | ||||
| 	} | ||||
| 	return configs, nil | ||||
| } | ||||
|  | ||||
| func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig, details types.ConfigDetails, resolvePaths bool) (types.FileObjectConfig, error) { | ||||
| func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig) (types.FileObjectConfig, error) { | ||||
| 	// if "external: true" | ||||
| 	switch { | ||||
| 	case obj.External.External: | ||||
| @@ -942,26 +957,11 @@ func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfi | ||||
| 		if obj.File != "" { | ||||
| 			return obj, errors.Errorf("%[1]s %[2]s: %[1]s.driver and %[1]s.file conflict; only use %[1]s.driver", objType, name) | ||||
| 		} | ||||
| 	default: | ||||
| 		if obj.File != "" && resolvePaths { | ||||
| 			obj.File = absPath(details.WorkingDir, obj.File) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return obj, nil | ||||
| } | ||||
|  | ||||
| func absPath(workingDir string, filePath string) string { | ||||
| 	if strings.HasPrefix(filePath, "~") { | ||||
| 		home, _ := os.UserHomeDir() | ||||
| 		return filepath.Join(home, filePath[1:]) | ||||
| 	} | ||||
| 	if filepath.IsAbs(filePath) { | ||||
| 		return filePath | ||||
| 	} | ||||
| 	return filepath.Join(workingDir, filePath) | ||||
| } | ||||
|  | ||||
| var transformMapStringString TransformerFunc = func(data interface{}) (interface{}, error) { | ||||
| 	switch value := data.(type) { | ||||
| 	case map[string]interface{}: | ||||
| @@ -1088,13 +1088,24 @@ 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 elementn, expected string", value) | ||||
| 				return data, errors.Errorf("invalid type %T for service depends_on element, expected string", value) | ||||
| 			} | ||||
| 			transformed[service] = map[string]interface{}{"condition": types.ServiceConditionStarted} | ||||
| 			transformed[service] = map[string]interface{}{"condition": types.ServiceConditionStarted, "required": true} | ||||
| 		} | ||||
| 		return transformed, nil | ||||
| 	case map[string]interface{}: | ||||
| 		return groupXFieldsIntoExtensions(data.(map[string]interface{})), nil | ||||
| 		transformed := map[string]interface{}{} | ||||
| 		for service, val := range value { | ||||
| 			dependsConfigIntf, ok := val.(map[string]interface{}) | ||||
| 			if !ok { | ||||
| 				return data, errors.Errorf("invalid type %T for service depends_on element", value) | ||||
| 			} | ||||
| 			if _, ok := dependsConfigIntf["required"]; !ok { | ||||
| 				dependsConfigIntf["required"] = true | ||||
| 			} | ||||
| 			transformed[service] = dependsConfigIntf | ||||
| 		} | ||||
| 		return groupXFieldsIntoExtensions(transformed), nil | ||||
| 	default: | ||||
| 		return data, errors.Errorf("invalid type %T for service depends_on", value) | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										11
									
								
								vendor/github.com/compose-spec/compose-go/loader/merge.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/compose-spec/compose-go/loader/merge.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -150,13 +150,12 @@ func unique(slice []string) []string { | ||||
| 		return nil | ||||
| 	} | ||||
| 	uniqMap := make(map[string]struct{}) | ||||
| 	var uniqSlice []string | ||||
| 	for _, v := range slice { | ||||
| 		uniqMap[v] = struct{}{} | ||||
| 	} | ||||
|  | ||||
| 	uniqSlice := make([]string, 0, len(uniqMap)) | ||||
| 	for v := range uniqMap { | ||||
| 		uniqSlice = append(uniqSlice, v) | ||||
| 		if _, ok := uniqMap[v]; !ok { | ||||
| 			uniqSlice = append(uniqSlice, v) | ||||
| 			uniqMap[v] = struct{}{} | ||||
| 		} | ||||
| 	} | ||||
| 	return uniqSlice | ||||
| } | ||||
|   | ||||
							
								
								
									
										71
									
								
								vendor/github.com/compose-spec/compose-go/loader/normalize.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/compose-spec/compose-go/loader/normalize.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -18,8 +18,6 @@ package loader | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/compose-spec/compose-go/errdefs" | ||||
| @@ -29,19 +27,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 { | ||||
| 	absWorkingDir, err := filepath.Abs(project.WorkingDir) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	project.WorkingDir = absWorkingDir | ||||
|  | ||||
| 	absComposeFiles, err := absComposeFiles(project.ComposeFiles) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	project.ComposeFiles = absComposeFiles | ||||
|  | ||||
| func Normalize(project *types.Project) error { | ||||
| 	if project.Networks == nil { | ||||
| 		project.Networks = make(map[string]types.NetworkConfig) | ||||
| 	} | ||||
| @@ -51,8 +37,7 @@ func Normalize(project *types.Project, resolvePaths bool) error { | ||||
| 		project.Networks["default"] = types.NetworkConfig{} | ||||
| 	} | ||||
|  | ||||
| 	err = relocateExternalName(project) | ||||
| 	if err != nil { | ||||
| 	if err := relocateExternalName(project); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| @@ -72,38 +57,16 @@ func Normalize(project *types.Project, resolvePaths bool) error { | ||||
| 		} | ||||
|  | ||||
| 		if s.Build != nil { | ||||
| 			if s.Build.Context == "" { | ||||
| 				s.Build.Context = "." | ||||
| 			} | ||||
| 			if s.Build.Dockerfile == "" && s.Build.DockerfileInline == "" { | ||||
| 				s.Build.Dockerfile = "Dockerfile" | ||||
| 			} | ||||
| 			if resolvePaths { | ||||
| 				// Build context 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 | ||||
| 				localContext := absPath(project.WorkingDir, s.Build.Context) | ||||
| 				if _, err := os.Stat(localContext); err == nil { | ||||
| 					s.Build.Context = localContext | ||||
| 				} | ||||
| 				for name, path := range s.Build.AdditionalContexts { | ||||
| 					if strings.Contains(path, "://") { // `docker-image://` or any builder specific context type | ||||
| 						continue | ||||
| 					} | ||||
| 					path = absPath(project.WorkingDir, path) | ||||
| 					if _, err := os.Stat(path); err == nil { | ||||
| 						s.Build.AdditionalContexts[name] = path | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			s.Build.Args = s.Build.Args.Resolve(fn) | ||||
| 		} | ||||
| 		for j, f := range s.EnvFile { | ||||
| 			s.EnvFile[j] = absPath(project.WorkingDir, f) | ||||
| 		} | ||||
| 		s.Environment = s.Environment.Resolve(fn) | ||||
|  | ||||
| 		if s.Extends != nil && s.Extends.File != "" { | ||||
| 			s.Extends.File = absPath(project.WorkingDir, s.Extends.File) | ||||
| 		} | ||||
|  | ||||
| 		for _, link := range s.Links { | ||||
| 			parts := strings.Split(link, ":") | ||||
| 			if len(parts) == 2 { | ||||
| @@ -112,6 +75,7 @@ func Normalize(project *types.Project, resolvePaths bool) error { | ||||
| 			s.DependsOn = setIfMissing(s.DependsOn, link, types.ServiceDependency{ | ||||
| 				Condition: types.ServiceConditionStarted, | ||||
| 				Restart:   true, | ||||
| 				Required:  true, | ||||
| 			}) | ||||
| 		} | ||||
|  | ||||
| @@ -121,6 +85,7 @@ func Normalize(project *types.Project, resolvePaths bool) error { | ||||
| 				s.DependsOn = setIfMissing(s.DependsOn, name, types.ServiceDependency{ | ||||
| 					Condition: types.ServiceConditionStarted, | ||||
| 					Restart:   true, | ||||
| 					Required:  true, | ||||
| 				}) | ||||
| 			} | ||||
| 		} | ||||
| @@ -131,6 +96,7 @@ func Normalize(project *types.Project, resolvePaths bool) error { | ||||
| 				s.DependsOn = setIfMissing(s.DependsOn, spec[0], types.ServiceDependency{ | ||||
| 					Condition: types.ServiceConditionStarted, | ||||
| 					Restart:   false, | ||||
| 					Required:  true, | ||||
| 				}) | ||||
| 			} | ||||
| 		} | ||||
| @@ -160,14 +126,6 @@ func Normalize(project *types.Project, resolvePaths bool) error { | ||||
| 		project.Services[i] = s | ||||
| 	} | ||||
|  | ||||
| 	for name, config := range project.Volumes { | ||||
| 		if config.Driver == "local" && config.DriverOpts["o"] == "bind" { | ||||
| 			// This is actually a bind mount | ||||
| 			config.DriverOpts["device"] = absPath(project.WorkingDir, config.DriverOpts["device"]) | ||||
| 			project.Volumes[name] = config | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	setNameFromKey(project) | ||||
|  | ||||
| 	return nil | ||||
| @@ -223,6 +181,7 @@ func inferImplicitDependencies(service *types.ServiceConfig) { | ||||
| 		if _, ok := service.DependsOn[d]; !ok { | ||||
| 			service.DependsOn[d] = types.ServiceDependency{ | ||||
| 				Condition: types.ServiceConditionStarted, | ||||
| 				Required:  true, | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -254,18 +213,6 @@ func relocateScale(s *types.ServiceConfig) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func absComposeFiles(composeFiles []string) ([]string, error) { | ||||
| 	absComposeFiles := make([]string, len(composeFiles)) | ||||
| 	for i, composeFile := range composeFiles { | ||||
| 		absComposefile, err := filepath.Abs(composeFile) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		absComposeFiles[i] = absComposefile | ||||
| 	} | ||||
| 	return absComposeFiles, nil | ||||
| } | ||||
|  | ||||
| // Resources with no explicit name are actually named by their key in map | ||||
| func setNameFromKey(project *types.Project) { | ||||
| 	for i, n := range project.Networks { | ||||
|   | ||||
							
								
								
									
										135
									
								
								vendor/github.com/compose-spec/compose-go/loader/paths.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								vendor/github.com/compose-spec/compose-go/loader/paths.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| /* | ||||
|    Copyright 2020 The Compose Specification Authors. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| */ | ||||
|  | ||||
| package loader | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/compose-spec/compose-go/types" | ||||
| ) | ||||
|  | ||||
| // ResolveRelativePaths resolves relative paths based on project WorkingDirectory | ||||
| func ResolveRelativePaths(project *types.Project) error { | ||||
| 	absWorkingDir, err := filepath.Abs(project.WorkingDir) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	project.WorkingDir = absWorkingDir | ||||
|  | ||||
| 	absComposeFiles, err := absComposeFiles(project.ComposeFiles) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	project.ComposeFiles = absComposeFiles | ||||
|  | ||||
| 	for i, s := range project.Services { | ||||
| 		ResolveServiceRelativePaths(project.WorkingDir, &s) | ||||
| 		project.Services[i] = s | ||||
| 	} | ||||
|  | ||||
| 	for i, obj := range project.Configs { | ||||
| 		if obj.File != "" { | ||||
| 			obj.File = absPath(project.WorkingDir, obj.File) | ||||
| 			project.Configs[i] = obj | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for i, obj := range project.Secrets { | ||||
| 		if obj.File != "" { | ||||
| 			obj.File = resolveMaybeUnixPath(project.WorkingDir, obj.File) | ||||
| 			project.Secrets[i] = obj | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for name, config := range project.Volumes { | ||||
| 		if config.Driver == "local" && config.DriverOpts["o"] == "bind" { | ||||
| 			// This is actually a bind mount | ||||
| 			config.DriverOpts["device"] = resolveMaybeUnixPath(project.WorkingDir, config.DriverOpts["device"]) | ||||
| 			project.Volumes[name] = config | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func ResolveServiceRelativePaths(workingDir string, s *types.ServiceConfig) { | ||||
| 	if s.Build != nil { | ||||
| 		if !isRemoteContext(s.Build.Context) { | ||||
| 			s.Build.Context = absPath(workingDir, s.Build.Context) | ||||
| 		} | ||||
| 		for name, path := range s.Build.AdditionalContexts { | ||||
| 			if strings.Contains(path, "://") { // `docker-image://` or any builder specific context type | ||||
| 				continue | ||||
| 			} | ||||
| 			if isRemoteContext(path) { | ||||
| 				continue | ||||
| 			} | ||||
| 			s.Build.AdditionalContexts[name] = absPath(workingDir, path) | ||||
| 		} | ||||
| 	} | ||||
| 	for j, f := range s.EnvFile { | ||||
| 		s.EnvFile[j] = absPath(workingDir, f) | ||||
| 	} | ||||
|  | ||||
| 	if s.Extends != nil && s.Extends.File != "" { | ||||
| 		s.Extends.File = absPath(workingDir, s.Extends.File) | ||||
| 	} | ||||
|  | ||||
| 	for i, vol := range s.Volumes { | ||||
| 		if vol.Type != types.VolumeTypeBind { | ||||
| 			continue | ||||
| 		} | ||||
| 		s.Volumes[i].Source = resolveMaybeUnixPath(workingDir, vol.Source) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func absPath(workingDir string, filePath string) string { | ||||
| 	if strings.HasPrefix(filePath, "~") { | ||||
| 		home, _ := os.UserHomeDir() | ||||
| 		return filepath.Join(home, filePath[1:]) | ||||
| 	} | ||||
| 	if filepath.IsAbs(filePath) { | ||||
| 		return filePath | ||||
| 	} | ||||
| 	return filepath.Join(workingDir, filePath) | ||||
| } | ||||
|  | ||||
| func absComposeFiles(composeFiles []string) ([]string, error) { | ||||
| 	for i, composeFile := range composeFiles { | ||||
| 		absComposefile, err := filepath.Abs(composeFile) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		composeFiles[i] = absComposefile | ||||
| 	} | ||||
| 	return composeFiles, nil | ||||
| } | ||||
|  | ||||
| // isRemoteContext returns true if the value is a Git reference or HTTP(S) URL. | ||||
| // | ||||
| // Any other value is assumed to be a local filesystem path and returns false. | ||||
| // | ||||
| // See: https://github.com/moby/buildkit/blob/18fc875d9bfd6e065cd8211abc639434ba65aa56/frontend/dockerui/context.go#L76-L79 | ||||
| func isRemoteContext(maybeURL string) bool { | ||||
| 	for _, prefix := range []string{"https://", "http://", "git://", "ssh://", "github.com/", "git@"} { | ||||
| 		if strings.HasPrefix(maybeURL, prefix) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
							
								
								
									
										35
									
								
								vendor/github.com/compose-spec/compose-go/schema/compose-spec.json
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/compose-spec/compose-go/schema/compose-spec.json
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,5 +1,5 @@ | ||||
| { | ||||
|   "$schema": "http://json-schema.org/draft/2019-09/schema#", | ||||
|   "$schema": "https://json-schema.org/draft/2019-09/schema#", | ||||
|   "id": "compose_spec.json", | ||||
|   "type": "object", | ||||
|   "title": "Compose Specification", | ||||
| @@ -17,6 +17,15 @@ | ||||
|       "description": "define the Compose project name, until user defines one explicitly." | ||||
|     }, | ||||
|  | ||||
|     "include": { | ||||
|       "type": "array", | ||||
|       "items": { | ||||
|         "type": "object", | ||||
|         "$ref": "#/definitions/include" | ||||
|       }, | ||||
|       "description": "compose sub-projects to be included." | ||||
|     }, | ||||
|  | ||||
|     "services": { | ||||
|       "id": "#/properties/services", | ||||
|       "type": "object", | ||||
| @@ -84,6 +93,7 @@ | ||||
|       "properties": { | ||||
|         "deploy": {"$ref": "#/definitions/deployment"}, | ||||
|         "annotations": {"$ref": "#/definitions/list_or_dict"}, | ||||
|         "attach": {"type": "boolean"}, | ||||
|         "build": { | ||||
|           "oneOf": [ | ||||
|             {"type": "string"}, | ||||
| @@ -181,6 +191,10 @@ | ||||
|                   "additionalProperties": false, | ||||
|                   "properties": { | ||||
|                     "restart": {"type": "boolean"}, | ||||
|                     "required": { | ||||
|                       "type":  "boolean", | ||||
|                       "default": true | ||||
|                     }, | ||||
|                     "condition": { | ||||
|                       "type": "string", | ||||
|                       "enum": ["service_started", "service_healthy", "service_completed_successfully"] | ||||
| @@ -443,7 +457,8 @@ | ||||
|           ] | ||||
|         }, | ||||
|         "timeout": {"type": "string", "format": "duration"}, | ||||
|         "start_period": {"type": "string", "format": "duration"} | ||||
|         "start_period": {"type": "string", "format": "duration"}, | ||||
|         "start_interval": {"type": "string", "format": "duration"} | ||||
|       }, | ||||
|       "additionalProperties": false, | ||||
|       "patternProperties": {"^x-": {}} | ||||
| @@ -588,6 +603,22 @@ | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     "include": { | ||||
|       "id": "#/definitions/include", | ||||
|       "oneOf": [ | ||||
|         {"type": "string"}, | ||||
|         { | ||||
|           "type": "object", | ||||
|           "properties": { | ||||
|             "path": {"$ref": "#/definitions/string_or_list"}, | ||||
|             "env_file": {"$ref": "#/definitions/string_or_list"}, | ||||
|             "project_directory": {"type": "string"} | ||||
|           }, | ||||
|           "additionalProperties": false | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|  | ||||
|     "network": { | ||||
|       "id": "#/definitions/network", | ||||
|       "type": ["object", "null"], | ||||
|   | ||||
							
								
								
									
										7
									
								
								vendor/github.com/compose-spec/compose-go/schema/schema.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/compose-spec/compose-go/schema/schema.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,19 +17,18 @@ | ||||
| package schema | ||||
|  | ||||
| import ( | ||||
| 	// Enable support for embedded static resources | ||||
| 	_ "embed" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/xeipuuv/gojsonschema" | ||||
|  | ||||
| 	// Enable support for embedded static resources | ||||
| 	_ "embed" | ||||
| ) | ||||
|  | ||||
| type portsFormatChecker struct{} | ||||
|  | ||||
| func (checker portsFormatChecker) IsFormat(input interface{}) bool { | ||||
| func (checker portsFormatChecker) IsFormat(_ interface{}) bool { | ||||
| 	// TODO: implement this | ||||
| 	return true | ||||
| } | ||||
|   | ||||
							
								
								
									
										190
									
								
								vendor/github.com/compose-spec/compose-go/template/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										190
									
								
								vendor/github.com/compose-spec/compose-go/template/template.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,6 +17,7 @@ | ||||
| package template | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| @@ -71,77 +72,148 @@ type Mapping func(string) (string, bool) | ||||
| // the substitution and an error. | ||||
| type SubstituteFunc func(string, Mapping) (string, bool, error) | ||||
|  | ||||
| // SubstituteWith substitute variables in the string with their values. | ||||
| // It accepts additional substitute function. | ||||
| func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, subsFuncs ...SubstituteFunc) (string, error) { | ||||
| 	var outerErr error | ||||
| // ReplacementFunc is a user-supplied function that is apply to the matching | ||||
| // substring. Returns the value as a string and an error. | ||||
| type ReplacementFunc func(string, Mapping, *Config) (string, error) | ||||
|  | ||||
| type Config struct { | ||||
| 	pattern         *regexp.Regexp | ||||
| 	substituteFunc  SubstituteFunc | ||||
| 	replacementFunc ReplacementFunc | ||||
| 	logging         bool | ||||
| } | ||||
|  | ||||
| type Option func(*Config) | ||||
|  | ||||
| func WithPattern(pattern *regexp.Regexp) Option { | ||||
| 	return func(cfg *Config) { | ||||
| 		cfg.pattern = pattern | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func WithSubstitutionFunction(subsFunc SubstituteFunc) Option { | ||||
| 	return func(cfg *Config) { | ||||
| 		cfg.substituteFunc = subsFunc | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func WithReplacementFunction(replacementFunc ReplacementFunc) Option { | ||||
| 	return func(cfg *Config) { | ||||
| 		cfg.replacementFunc = replacementFunc | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func WithoutLogging(cfg *Config) { | ||||
| 	cfg.logging = false | ||||
| } | ||||
|  | ||||
| // SubstituteWithOptions substitute variables in the string with their values. | ||||
| // It accepts additional options such as a custom function or pattern. | ||||
| func SubstituteWithOptions(template string, mapping Mapping, options ...Option) (string, error) { | ||||
| 	var returnErr error | ||||
|  | ||||
| 	result := pattern.ReplaceAllStringFunc(template, func(substring string) string { | ||||
| 		_, subsFunc := getSubstitutionFunctionForTemplate(substring) | ||||
| 		if len(subsFuncs) > 0 { | ||||
| 			subsFunc = subsFuncs[0] | ||||
| 		} | ||||
| 	cfg := &Config{ | ||||
| 		pattern:         defaultPattern, | ||||
| 		replacementFunc: DefaultReplacementFunc, | ||||
| 		logging:         true, | ||||
| 	} | ||||
| 	for _, o := range options { | ||||
| 		o(cfg) | ||||
| 	} | ||||
|  | ||||
| 		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 != "" { | ||||
| 			return escaped | ||||
| 		} | ||||
|  | ||||
| 		braced := false | ||||
| 		substitution := groups["named"] | ||||
| 		if substitution == "" { | ||||
| 			substitution = groups["braced"] | ||||
| 			braced = true | ||||
| 		} | ||||
|  | ||||
| 		if substitution == "" { | ||||
| 			outerErr = &InvalidTemplateError{Template: template} | ||||
| 	result := cfg.pattern.ReplaceAllStringFunc(template, func(substring string) string { | ||||
| 		replacement, err := cfg.replacementFunc(substring, mapping, cfg) | ||||
| 		if err != nil { | ||||
| 			// Add the template for template errors | ||||
| 			var tmplErr *InvalidTemplateError | ||||
| 			if errors.As(err, &tmplErr) { | ||||
| 				if tmplErr.Template == "" { | ||||
| 					tmplErr.Template = template | ||||
| 				} | ||||
| 			} | ||||
| 			// Save the first error to be returned | ||||
| 			if returnErr == nil { | ||||
| 				returnErr = outerErr | ||||
| 				returnErr = err | ||||
| 			} | ||||
| 			return "" | ||||
| 		} | ||||
|  | ||||
| 		if braced { | ||||
| 			var ( | ||||
| 				value   string | ||||
| 				applied bool | ||||
| 			) | ||||
| 			value, applied, outerErr = subsFunc(substitution, mapping) | ||||
| 			if outerErr != nil { | ||||
| 				if returnErr == nil { | ||||
| 					returnErr = outerErr | ||||
| 				} | ||||
| 				return "" | ||||
| 			} | ||||
| 			if applied { | ||||
| 				interpolatedNested, err := SubstituteWith(rest, mapping, pattern) | ||||
| 				if err != nil { | ||||
| 					return "" | ||||
| 				} | ||||
| 				return value + interpolatedNested | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		value, ok := mapping(substitution) | ||||
| 		if !ok { | ||||
| 			logrus.Warnf("The %q variable is not set. Defaulting to a blank string.", substitution) | ||||
| 		} | ||||
| 		return value | ||||
| 		return replacement | ||||
| 	}) | ||||
|  | ||||
| 	return result, returnErr | ||||
| } | ||||
|  | ||||
| func DefaultReplacementFunc(substring string, mapping Mapping, cfg *Config) (string, error) { | ||||
| 	value, _, err := DefaultReplacementAppliedFunc(substring, mapping, cfg) | ||||
| 	return value, err | ||||
| } | ||||
|  | ||||
| func DefaultReplacementAppliedFunc(substring string, mapping Mapping, cfg *Config) (string, bool, error) { | ||||
| 	pattern := cfg.pattern | ||||
| 	subsFunc := cfg.substituteFunc | ||||
| 	if subsFunc == nil { | ||||
| 		_, subsFunc = getSubstitutionFunctionForTemplate(substring) | ||||
| 	} | ||||
|  | ||||
| 	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 != "" { | ||||
| 		return escaped, true, nil | ||||
| 	} | ||||
|  | ||||
| 	braced := false | ||||
| 	substitution := groups["named"] | ||||
| 	if substitution == "" { | ||||
| 		substitution = groups["braced"] | ||||
| 		braced = true | ||||
| 	} | ||||
|  | ||||
| 	if substitution == "" { | ||||
| 		return "", false, &InvalidTemplateError{} | ||||
| 	} | ||||
|  | ||||
| 	if braced { | ||||
| 		value, applied, err := subsFunc(substitution, mapping) | ||||
| 		if err != nil { | ||||
| 			return "", false, err | ||||
| 		} | ||||
| 		if applied { | ||||
| 			interpolatedNested, err := SubstituteWith(rest, mapping, pattern) | ||||
| 			if err != nil { | ||||
| 				return "", false, err | ||||
| 			} | ||||
| 			return value + interpolatedNested, true, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	value, ok := mapping(substitution) | ||||
| 	if !ok && cfg.logging { | ||||
| 		logrus.Warnf("The %q variable is not set. Defaulting to a blank string.", substitution) | ||||
| 	} | ||||
|  | ||||
| 	return value, ok, nil | ||||
| } | ||||
|  | ||||
| // SubstituteWith substitute variables in the string with their values. | ||||
| // It accepts additional substitute function. | ||||
| func SubstituteWith(template string, mapping Mapping, pattern *regexp.Regexp, subsFuncs ...SubstituteFunc) (string, error) { | ||||
| 	options := []Option{ | ||||
| 		WithPattern(pattern), | ||||
| 	} | ||||
| 	if len(subsFuncs) > 0 { | ||||
| 		options = append(options, WithSubstitutionFunction(subsFuncs[0])) | ||||
| 	} | ||||
|  | ||||
| 	return SubstituteWithOptions(template, mapping, options...) | ||||
| } | ||||
|  | ||||
| func getSubstitutionFunctionForTemplate(template string) (string, SubstituteFunc) { | ||||
| 	interpolationMapping := []struct { | ||||
| 		string | ||||
|   | ||||
							
								
								
									
										24
									
								
								vendor/github.com/compose-spec/compose-go/types/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/compose-spec/compose-go/types/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -67,16 +67,24 @@ type ConfigFile struct { | ||||
| 	Config map[string]interface{} | ||||
| } | ||||
|  | ||||
| func ToConfigFiles(path []string) (f []ConfigFile) { | ||||
| 	for _, p := range path { | ||||
| 		f = append(f, ConfigFile{Filename: p}) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // 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"` | ||||
| 	Secrets    Secrets    `yaml:",omitempty" json:"secrets,omitempty"` | ||||
| 	Configs    Configs    `yaml:",omitempty" json:"configs,omitempty"` | ||||
| 	Extensions Extensions `yaml:",inline" json:"-"` | ||||
| 	Filename   string          `yaml:"-" json:"-"` | ||||
| 	Name       string          `yaml:"name,omitempty" json:"name,omitempty"` | ||||
| 	Services   Services        `yaml:"services" json:"services"` | ||||
| 	Networks   Networks        `yaml:"networks,omitempty" json:"networks,omitempty"` | ||||
| 	Volumes    Volumes         `yaml:"volumes,omitempty" json:"volumes,omitempty"` | ||||
| 	Secrets    Secrets         `yaml:"secrets,omitempty" json:"secrets,omitempty"` | ||||
| 	Configs    Configs         `yaml:"configs,omitempty" json:"configs,omitempty"` | ||||
| 	Extensions Extensions      `yaml:",inline" json:"-"` | ||||
| 	Include    []IncludeConfig `yaml:"include,omitempty" json:"include,omitempty"` | ||||
| } | ||||
|  | ||||
| // Volumes is a map of VolumeConfig | ||||
|   | ||||
							
								
								
									
										50
									
								
								vendor/github.com/compose-spec/compose-go/types/project.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										50
									
								
								vendor/github.com/compose-spec/compose-go/types/project.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -24,6 +24,8 @@ import ( | ||||
| 	"path/filepath" | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/compose-spec/compose-go/utils" | ||||
|  | ||||
| 	"github.com/compose-spec/compose-go/dotenv" | ||||
| 	"github.com/distribution/distribution/v3/reference" | ||||
| 	godigest "github.com/opencontainers/go-digest" | ||||
| @@ -102,10 +104,19 @@ func (p *Project) ConfigNames() []string { | ||||
|  | ||||
| // GetServices retrieve services by names, or return all services if no name specified | ||||
| func (p *Project) GetServices(names ...string) (Services, error) { | ||||
| 	services, servicesNotFound := p.getServicesByNames(names...) | ||||
| 	if len(servicesNotFound) > 0 { | ||||
| 		return services, fmt.Errorf("no such service: %s", servicesNotFound[0]) | ||||
| 	} | ||||
| 	return services, nil | ||||
| } | ||||
|  | ||||
| func (p *Project) getServicesByNames(names ...string) (Services, []string) { | ||||
| 	if len(names) == 0 { | ||||
| 		return p.Services, nil | ||||
| 	} | ||||
| 	services := Services{} | ||||
| 	var servicesNotFound []string | ||||
| 	for _, name := range names { | ||||
| 		var serviceConfig *ServiceConfig | ||||
| 		for _, s := range p.Services { | ||||
| @@ -115,11 +126,12 @@ func (p *Project) GetServices(names ...string) (Services, error) { | ||||
| 			} | ||||
| 		} | ||||
| 		if serviceConfig == nil { | ||||
| 			return services, fmt.Errorf("no such service: %s", name) | ||||
| 			servicesNotFound = append(servicesNotFound, name) | ||||
| 			continue | ||||
| 		} | ||||
| 		services = append(services, *serviceConfig) | ||||
| 	} | ||||
| 	return services, nil | ||||
| 	return services, servicesNotFound | ||||
| } | ||||
|  | ||||
| // GetDisabledService retrieve disabled service by name | ||||
| @@ -159,26 +171,30 @@ func (p *Project) WithServices(names []string, fn ServiceFunc, options ...Depend | ||||
| 		// backward compatibility | ||||
| 		options = []DependencyOption{IncludeDependencies} | ||||
| 	} | ||||
| 	return p.withServices(names, fn, map[string]bool{}, options) | ||||
| 	return p.withServices(names, fn, map[string]bool{}, options, map[string]ServiceDependency{}) | ||||
| } | ||||
|  | ||||
| func (p *Project) withServices(names []string, fn ServiceFunc, seen map[string]bool, options []DependencyOption) error { | ||||
| 	services, err := p.GetServices(names...) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| func (p *Project) withServices(names []string, fn ServiceFunc, seen map[string]bool, options []DependencyOption, dependencies map[string]ServiceDependency) error { | ||||
| 	services, servicesNotFound := p.getServicesByNames(names...) | ||||
| 	if len(servicesNotFound) > 0 { | ||||
| 		for _, serviceNotFound := range servicesNotFound { | ||||
| 			if dependency, ok := dependencies[serviceNotFound]; !ok || dependency.Required { | ||||
| 				return fmt.Errorf("no such service: %s", serviceNotFound) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	for _, service := range services { | ||||
| 		if seen[service.Name] { | ||||
| 			continue | ||||
| 		} | ||||
| 		seen[service.Name] = true | ||||
| 		var dependencies []string | ||||
| 		var dependencies map[string]ServiceDependency | ||||
| 		for _, policy := range options { | ||||
| 			switch policy { | ||||
| 			case IncludeDependents: | ||||
| 				dependencies = append(dependencies, p.GetDependentsForService(service)...) | ||||
| 				dependencies = utils.MapsAppend(dependencies, p.dependentsForService(service)) | ||||
| 			case IncludeDependencies: | ||||
| 				dependencies = append(dependencies, service.GetDependencies()...) | ||||
| 				dependencies = utils.MapsAppend(dependencies, service.DependsOn) | ||||
| 			case IgnoreDependencies: | ||||
| 				// Noop | ||||
| 			default: | ||||
| @@ -186,7 +202,7 @@ func (p *Project) withServices(names []string, fn ServiceFunc, seen map[string]b | ||||
| 			} | ||||
| 		} | ||||
| 		if len(dependencies) > 0 { | ||||
| 			err := p.withServices(dependencies, fn, seen, options) | ||||
| 			err := p.withServices(utils.MapKeys(dependencies), fn, seen, options, dependencies) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| @@ -199,11 +215,15 @@ func (p *Project) withServices(names []string, fn ServiceFunc, seen map[string]b | ||||
| } | ||||
|  | ||||
| func (p *Project) GetDependentsForService(s ServiceConfig) []string { | ||||
| 	var dependent []string | ||||
| 	return utils.MapKeys(p.dependentsForService(s)) | ||||
| } | ||||
|  | ||||
| func (p *Project) dependentsForService(s ServiceConfig) map[string]ServiceDependency { | ||||
| 	dependent := make(map[string]ServiceDependency) | ||||
| 	for _, service := range p.Services { | ||||
| 		for name := range service.DependsOn { | ||||
| 		for name, dependency := range service.DependsOn { | ||||
| 			if name == s.Name { | ||||
| 				dependent = append(dependent, service.Name) | ||||
| 				dependent[service.Name] = dependency | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -507,7 +527,7 @@ func (p Project) ResolveServicesEnvironment(discardEnvFiles bool) error { | ||||
|  | ||||
| 			fileVars, err := dotenv.ParseWithLookup(bytes.NewBuffer(b), resolve) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 				return errors.Wrapf(err, "failed to read %s", envFile) | ||||
| 			} | ||||
| 			environment.OverrideBy(Mapping(fileVars).ToMappingWithEquals()) | ||||
| 		} | ||||
|   | ||||
							
								
								
									
										23
									
								
								vendor/github.com/compose-spec/compose-go/types/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/compose-spec/compose-go/types/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -89,6 +89,7 @@ type ServiceConfig struct { | ||||
| 	Profiles []string `yaml:"profiles,omitempty" json:"profiles,omitempty"` | ||||
|  | ||||
| 	Annotations  Mapping      `yaml:"annotations,omitempty" json:"annotations,omitempty"` | ||||
| 	Attach       *bool        `yaml:"attach,omitempty" json:"attach,omitempty"` | ||||
| 	Build        *BuildConfig `yaml:"build,omitempty" json:"build,omitempty"` | ||||
| 	BlkioConfig  *BlkioConfig `yaml:"blkio_config,omitempty" json:"blkio_config,omitempty"` | ||||
| 	CapAdd       []string     `yaml:"cap_add,omitempty" json:"cap_add,omitempty"` | ||||
| @@ -602,12 +603,13 @@ type DeployConfig struct { | ||||
|  | ||||
| // HealthCheckConfig the healthcheck configuration for a service | ||||
| type HealthCheckConfig struct { | ||||
| 	Test        HealthCheckTest `yaml:"test,omitempty" json:"test,omitempty"` | ||||
| 	Timeout     *Duration       `yaml:"timeout,omitempty" json:"timeout,omitempty"` | ||||
| 	Interval    *Duration       `yaml:"interval,omitempty" json:"interval,omitempty"` | ||||
| 	Retries     *uint64         `yaml:"retries,omitempty" json:"retries,omitempty"` | ||||
| 	StartPeriod *Duration       `yaml:"start_period,omitempty" json:"start_period,omitempty"` | ||||
| 	Disable     bool            `yaml:"disable,omitempty" json:"disable,omitempty"` | ||||
| 	Test          HealthCheckTest `yaml:"test,omitempty" json:"test,omitempty"` | ||||
| 	Timeout       *Duration       `yaml:"timeout,omitempty" json:"timeout,omitempty"` | ||||
| 	Interval      *Duration       `yaml:"interval,omitempty" json:"interval,omitempty"` | ||||
| 	Retries       *uint64         `yaml:"retries,omitempty" json:"retries,omitempty"` | ||||
| 	StartPeriod   *Duration       `yaml:"start_period,omitempty" json:"start_period,omitempty"` | ||||
| 	StartInterval *Duration       `yaml:"start_interval,omitempty" json:"start_interval,omitempty"` | ||||
| 	Disable       bool            `yaml:"disable,omitempty" json:"disable,omitempty"` | ||||
|  | ||||
| 	Extensions Extensions `yaml:"#extensions,inline" json:"-"` | ||||
| } | ||||
| @@ -815,6 +817,8 @@ const ( | ||||
| 	VolumeTypeTmpfs = "tmpfs" | ||||
| 	// VolumeTypeNamedPipe is the type for mounting Windows named pipes | ||||
| 	VolumeTypeNamedPipe = "npipe" | ||||
| 	// VolumeTypeCluster is the type for mounting container storage interface (CSI) volumes | ||||
| 	VolumeTypeCluster = "cluster" | ||||
|  | ||||
| 	// SElinuxShared share the volume content | ||||
| 	SElinuxShared = "z" | ||||
| @@ -1023,6 +1027,7 @@ type ServiceDependency struct { | ||||
| 	Condition  string     `yaml:"condition,omitempty" json:"condition,omitempty"` | ||||
| 	Restart    bool       `yaml:"restart,omitempty" json:"restart,omitempty"` | ||||
| 	Extensions Extensions `yaml:"#extensions,inline" json:"-"` | ||||
| 	Required   bool       `yaml:"required" json:"required"` | ||||
| } | ||||
|  | ||||
| type ExtendsConfig struct { | ||||
| @@ -1035,3 +1040,9 @@ type SecretConfig FileObjectConfig | ||||
|  | ||||
| // ConfigObjConfig is the config for the swarm "Config" object | ||||
| type ConfigObjConfig FileObjectConfig | ||||
|  | ||||
| type IncludeConfig struct { | ||||
| 	Path             StringList `yaml:"path,omitempty" json:"path,omitempty"` | ||||
| 	ProjectDirectory string     `yaml:"project_directory,omitempty" json:"project_directory,omitempty"` | ||||
| 	EnvFile          StringList `yaml:"env_file,omitempty" json:"env_file,omitempty"` | ||||
| } | ||||
|   | ||||
							
								
								
									
										51
									
								
								vendor/github.com/compose-spec/compose-go/utils/collectionutils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/compose-spec/compose-go/utils/collectionutils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| /* | ||||
|    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 utils | ||||
|  | ||||
| import "golang.org/x/exp/slices" | ||||
|  | ||||
| func MapKeys[T comparable, U any](theMap map[T]U) []T { | ||||
| 	var result []T | ||||
| 	for key := range theMap { | ||||
| 		result = append(result, key) | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| func MapsAppend[T comparable, U any](target map[T]U, source map[T]U) map[T]U { | ||||
| 	if target == nil { | ||||
| 		return source | ||||
| 	} | ||||
| 	if source == nil { | ||||
| 		return target | ||||
| 	} | ||||
| 	for key, value := range source { | ||||
| 		if _, ok := target[key]; !ok { | ||||
| 			target[key] = value | ||||
| 		} | ||||
| 	} | ||||
| 	return target | ||||
| } | ||||
|  | ||||
| func ArrayContains[T comparable](source []T, toCheck []T) bool { | ||||
| 	for _, value := range toCheck { | ||||
| 		if !slices.Contains(source, value) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
		Reference in New Issue
	
	Block a user