mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-01 00:23:56 +08:00 
			
		
		
		
	vendor: github.com/compose-spec/compose-go v1.18.3
- Parse service device count to int if possible - introduce ResourceResolver to accept remote resources - use include.env_file to resolve variables in included compose.yaml file - remove potential dependencies to disabled services in ForServices - ability to convert a mapping (back) to KEY=VALUE strings - load: include details about included files on Project - include disabled services - local environment to override included .env - load: move env var profile detection to option - add support for multi-document yaml full diff: https://github.com/compose-spec/compose-go/compare/v1.17.0...v1.18.3 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
		
							
								
								
									
										52
									
								
								vendor/github.com/compose-spec/compose-go/cli/options.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/compose-spec/compose-go/cli/options.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,6 +17,7 @@ | ||||
| package cli | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| @@ -35,6 +36,8 @@ import ( | ||||
|  | ||||
| // ProjectOptions provides common configuration for loading a project. | ||||
| type ProjectOptions struct { | ||||
| 	ctx context.Context | ||||
|  | ||||
| 	// Name is a valid Compose project name to be used or empty. | ||||
| 	// | ||||
| 	// If empty, the project loader will automatically infer a reasonable | ||||
| @@ -63,7 +66,7 @@ type ProjectOptions struct { | ||||
| 	// NOTE: For security, the loader does not automatically expose any | ||||
| 	// process environment variables. For convenience, WithOsEnv can be | ||||
| 	// used if appropriate. | ||||
| 	Environment map[string]string | ||||
| 	Environment types.Mapping | ||||
|  | ||||
| 	// EnvFiles are file paths to ".env" files with additional environment | ||||
| 	// variable data. | ||||
| @@ -191,7 +194,7 @@ func WithEnv(env []string) ProjectOptionsFn { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithDiscardEnvFiles sets discards the `env_file` section after resolving to | ||||
| // WithDiscardEnvFile sets discards the `env_file` section after resolving to | ||||
| // the `environment` section | ||||
| func WithDiscardEnvFile(o *ProjectOptions) error { | ||||
| 	o.loadOptions = append(o.loadOptions, loader.WithDiscardEnvFiles) | ||||
| @@ -206,6 +209,15 @@ func WithLoadOptions(loadOptions ...func(*loader.Options)) ProjectOptionsFn { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithDefaultProfiles uses the provided profiles (if any), and falls back to | ||||
| // profiles specified via the COMPOSE_PROFILES environment variable otherwise. | ||||
| func WithDefaultProfiles(profile ...string) ProjectOptionsFn { | ||||
| 	if len(profile) == 0 { | ||||
| 		profile = strings.Split(os.Getenv(consts.ComposeProfiles), ",") | ||||
| 	} | ||||
| 	return WithProfiles(profile) | ||||
| } | ||||
|  | ||||
| // WithProfiles sets profiles to be activated | ||||
| func WithProfiles(profiles []string) ProjectOptionsFn { | ||||
| 	return func(o *ProjectOptions) error { | ||||
| @@ -225,8 +237,9 @@ func WithOsEnv(o *ProjectOptions) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // WithEnvFile set an alternate env file | ||||
| // deprecated - use WithEnvFiles | ||||
| // WithEnvFile sets an alternate env file. | ||||
| // | ||||
| // Deprecated: use WithEnvFiles instead. | ||||
| func WithEnvFile(file string) ProjectOptionsFn { | ||||
| 	var files []string | ||||
| 	if file != "" { | ||||
| @@ -253,11 +266,7 @@ func WithDotEnv(o *ProjectOptions) error { | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for k, v := range envMap { | ||||
| 		if _, set := o.Environment[k]; !set { | ||||
| 			o.Environment[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	o.Environment.Merge(envMap) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -301,6 +310,24 @@ func WithResolvedPaths(resolve bool) ProjectOptionsFn { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithContext sets the context used to load model and resources | ||||
| func WithContext(ctx context.Context) ProjectOptionsFn { | ||||
| 	return func(o *ProjectOptions) error { | ||||
| 		o.ctx = ctx | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // WithResourceLoader register support for ResourceLoader to manage remote resources | ||||
| func WithResourceLoader(r loader.ResourceLoader) ProjectOptionsFn { | ||||
| 	return func(o *ProjectOptions) error { | ||||
| 		o.loadOptions = append(o.loadOptions, func(options *loader.Options) { | ||||
| 			options.ResourceLoaders = append(options.ResourceLoaders, r) | ||||
| 		}) | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DefaultFileNames defines the Compose file names for auto-discovery (in order of preference) | ||||
| var DefaultFileNames = []string{"compose.yaml", "compose.yml", "docker-compose.yml", "docker-compose.yaml"} | ||||
|  | ||||
| @@ -367,7 +394,12 @@ func ProjectFromOptions(options *ProjectOptions) (*types.Project, error) { | ||||
| 		withNamePrecedenceLoad(absWorkingDir, options), | ||||
| 		withConvertWindowsPaths(options)) | ||||
|  | ||||
| 	project, err := loader.Load(types.ConfigDetails{ | ||||
| 	ctx := options.ctx | ||||
| 	if ctx == nil { | ||||
| 		ctx = context.Background() | ||||
| 	} | ||||
|  | ||||
| 	project, err := loader.LoadWithContext(ctx, types.ConfigDetails{ | ||||
| 		ConfigFiles: configs, | ||||
| 		WorkingDir:  workingDir, | ||||
| 		Environment: options.Environment, | ||||
|   | ||||
							
								
								
									
										50
									
								
								vendor/github.com/compose-spec/compose-go/loader/include.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										50
									
								
								vendor/github.com/compose-spec/compose-go/loader/include.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,10 +17,12 @@ | ||||
| package loader | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/compose-spec/compose-go/dotenv" | ||||
| 	interp "github.com/compose-spec/compose-go/interpolation" | ||||
| 	"github.com/compose-spec/compose-go/types" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
| @@ -43,12 +45,23 @@ var transformIncludeConfig TransformerFunc = func(data interface{}) (interface{} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func loadInclude(configDetails types.ConfigDetails, model *types.Config, options *Options, loaded []string) (*types.Config, error) { | ||||
| func loadInclude(ctx context.Context, filename string, configDetails types.ConfigDetails, model *types.Config, options *Options, loaded []string) (*types.Config, map[string][]types.IncludeConfig, error) { | ||||
| 	included := make(map[string][]types.IncludeConfig) | ||||
| 	for _, r := range model.Include { | ||||
| 		included[filename] = append(included[filename], r) | ||||
|  | ||||
| 		for i, p := range r.Path { | ||||
| 			if !filepath.IsAbs(p) { | ||||
| 				r.Path[i] = filepath.Join(configDetails.WorkingDir, p) | ||||
| 			for _, loader := range options.ResourceLoaders { | ||||
| 				if loader.Accept(p) { | ||||
| 					path, err := loader.Load(ctx, p) | ||||
| 					if err != nil { | ||||
| 						return nil, nil, err | ||||
| 					} | ||||
| 					p = path | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			r.Path[i] = absPath(configDetails.WorkingDir, p) | ||||
| 		} | ||||
| 		if r.ProjectDirectory == "" { | ||||
| 			r.ProjectDirectory = filepath.Dir(r.Path[0]) | ||||
| @@ -60,27 +73,36 @@ func loadInclude(configDetails types.ConfigDetails, model *types.Config, options | ||||
| 		loadOptions.SkipNormalization = true | ||||
| 		loadOptions.SkipConsistencyCheck = true | ||||
|  | ||||
| 		env, err := dotenv.GetEnvFromFile(configDetails.Environment, r.ProjectDirectory, r.EnvFile) | ||||
| 		envFromFile, err := dotenv.GetEnvFromFile(configDetails.Environment, r.ProjectDirectory, r.EnvFile) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
|  | ||||
| 		imported, err := load(types.ConfigDetails{ | ||||
| 		config := types.ConfigDetails{ | ||||
| 			WorkingDir:  r.ProjectDirectory, | ||||
| 			ConfigFiles: types.ToConfigFiles(r.Path), | ||||
| 			Environment: env, | ||||
| 		}, loadOptions, loaded) | ||||
| 			Environment: configDetails.Environment.Clone().Merge(envFromFile), | ||||
| 		} | ||||
| 		loadOptions.Interpolate = &interp.Options{ | ||||
| 			Substitute:      options.Interpolate.Substitute, | ||||
| 			LookupValue:     config.LookupEnv, | ||||
| 			TypeCastMapping: options.Interpolate.TypeCastMapping, | ||||
| 		} | ||||
| 		imported, err := load(ctx, config, loadOptions, loaded) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		for k, v := range imported.IncludeReferences { | ||||
| 			included[k] = append(included[k], v...) | ||||
| 		} | ||||
|  | ||||
| 		err = importResources(model, imported, r.Path) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	model.Include = nil | ||||
| 	return model, nil | ||||
| 	return model, included, nil | ||||
| } | ||||
|  | ||||
| // importResources import into model all resources defined by imported, and report error on conflict | ||||
| @@ -92,6 +114,12 @@ func importResources(model *types.Config, imported *types.Project, path []string | ||||
| 		} | ||||
| 		model.Services = append(model.Services, service) | ||||
| 	} | ||||
| 	for _, service := range imported.DisabledServices { | ||||
| 		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) | ||||
|   | ||||
							
								
								
									
										191
									
								
								vendor/github.com/compose-spec/compose-go/loader/loader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										191
									
								
								vendor/github.com/compose-spec/compose-go/loader/loader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,7 +17,10 @@ | ||||
| package loader | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	paths "path" | ||||
| 	"path/filepath" | ||||
| @@ -68,6 +71,16 @@ type Options struct { | ||||
| 	projectNameImperativelySet bool | ||||
| 	// Profiles set profiles to enable | ||||
| 	Profiles []string | ||||
| 	// ResourceLoaders manages support for remote resources | ||||
| 	ResourceLoaders []ResourceLoader | ||||
| } | ||||
|  | ||||
| // ResourceLoader is a plugable remote resource resolver | ||||
| type ResourceLoader interface { | ||||
| 	// Accept returns `true` is the resource reference matches ResourceLoader supported protocol(s) | ||||
| 	Accept(path string) bool | ||||
| 	// Load returns the path to a local copy of remote resource identified by `path`. | ||||
| 	Load(ctx context.Context, path string) (string, error) | ||||
| } | ||||
|  | ||||
| func (o *Options) clone() *Options { | ||||
| @@ -85,6 +98,7 @@ func (o *Options) clone() *Options { | ||||
| 		projectName:                o.projectName, | ||||
| 		projectNameImperativelySet: o.projectNameImperativelySet, | ||||
| 		Profiles:                   o.Profiles, | ||||
| 		ResourceLoaders:            o.ResourceLoaders, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -154,7 +168,9 @@ func WithProfiles(profiles []string) func(*Options) { | ||||
| // ParseYAML reads the bytes from a file, parses the bytes into a mapping | ||||
| // structure, and returns it. | ||||
| func ParseYAML(source []byte) (map[string]interface{}, error) { | ||||
| 	m, _, err := parseYAML(source) | ||||
| 	r := bytes.NewReader(source) | ||||
| 	decoder := yaml.NewDecoder(r) | ||||
| 	m, _, err := parseYAML(decoder) | ||||
| 	return m, err | ||||
| } | ||||
|  | ||||
| @@ -167,11 +183,11 @@ type PostProcessor interface { | ||||
| 	Apply(config *types.Config) error | ||||
| } | ||||
|  | ||||
| func parseYAML(source []byte) (map[string]interface{}, PostProcessor, error) { | ||||
| func parseYAML(decoder *yaml.Decoder) (map[string]interface{}, PostProcessor, error) { | ||||
| 	var cfg interface{} | ||||
| 	processor := ResetProcessor{target: &cfg} | ||||
|  | ||||
| 	if err := yaml.Unmarshal(source, &processor); err != nil { | ||||
| 	if err := decoder.Decode(&processor); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	stringMap, ok := cfg.(map[string]interface{}) | ||||
| @@ -193,8 +209,14 @@ func parseYAML(source []byte) (map[string]interface{}, PostProcessor, error) { | ||||
| 	return converted.(map[string]interface{}), &processor, nil | ||||
| } | ||||
|  | ||||
| // Load reads a ConfigDetails and returns a fully loaded configuration | ||||
| // Load reads a ConfigDetails and returns a fully loaded configuration. | ||||
| // Deprecated: use LoadWithContext. | ||||
| func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.Project, error) { | ||||
| 	return LoadWithContext(context.Background(), configDetails, options...) | ||||
| } | ||||
|  | ||||
| // LoadWithContext reads a ConfigDetails and returns a fully loaded configuration | ||||
| func LoadWithContext(ctx context.Context, configDetails types.ConfigDetails, options ...func(*Options)) (*types.Project, error) { | ||||
| 	if len(configDetails.ConfigFiles) < 1 { | ||||
| 		return nil, errors.Errorf("No files specified") | ||||
| 	} | ||||
| @@ -217,10 +239,10 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types. | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	opts.projectName = projectName | ||||
| 	return load(configDetails, opts, nil) | ||||
| 	return load(ctx, configDetails, opts, nil) | ||||
| } | ||||
|  | ||||
| func load(configDetails types.ConfigDetails, opts *Options, loaded []string) (*types.Project, error) { | ||||
| func load(ctx context.Context, configDetails types.ConfigDetails, opts *Options, loaded []string) (*types.Project, error) { | ||||
| 	var model *types.Config | ||||
|  | ||||
| 	mainFile := configDetails.ConfigFiles[0].Filename | ||||
| @@ -232,9 +254,56 @@ func load(configDetails types.ConfigDetails, opts *Options, loaded []string) (*t | ||||
| 	} | ||||
| 	loaded = append(loaded, mainFile) | ||||
|  | ||||
| 	for i, file := range configDetails.ConfigFiles { | ||||
| 	includeRefs := make(map[string][]types.IncludeConfig) | ||||
| 	first := true | ||||
| 	for _, file := range configDetails.ConfigFiles { | ||||
| 		var postProcessor PostProcessor | ||||
| 		configDict := file.Config | ||||
|  | ||||
| 		processYaml := func() error { | ||||
| 			if !opts.SkipValidation { | ||||
| 				if err := schema.Validate(configDict); err != nil { | ||||
| 					return fmt.Errorf("validating %s: %w", file.Filename, err) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			configDict = groupXFieldsIntoExtensions(configDict) | ||||
|  | ||||
| 			cfg, err := loadSections(ctx, file.Filename, configDict, configDetails, opts) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			if !opts.SkipInclude { | ||||
| 				var included map[string][]types.IncludeConfig | ||||
| 				cfg, included, err = loadInclude(ctx, file.Filename, configDetails, cfg, opts, loaded) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				for k, v := range included { | ||||
| 					includeRefs[k] = append(includeRefs[k], v...) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if first { | ||||
| 				first = false | ||||
| 				model = cfg | ||||
| 				return nil | ||||
| 			} | ||||
| 			merged, err := merge([]*types.Config{model, cfg}) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if postProcessor != nil { | ||||
| 				err = postProcessor.Apply(merged) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			model = merged | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		if configDict == nil { | ||||
| 			if len(file.Content) == 0 { | ||||
| 				content, err := os.ReadFile(file.Filename) | ||||
| @@ -243,52 +312,29 @@ func load(configDetails types.ConfigDetails, opts *Options, loaded []string) (*t | ||||
| 				} | ||||
| 				file.Content = content | ||||
| 			} | ||||
| 			dict, p, err := parseConfig(file.Content, opts) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("parsing %s: %w", file.Filename, err) | ||||
|  | ||||
| 			r := bytes.NewReader(file.Content) | ||||
| 			decoder := yaml.NewDecoder(r) | ||||
| 			for { | ||||
| 				dict, p, err := parseConfig(decoder, opts) | ||||
| 				if err != nil { | ||||
| 					if err != io.EOF { | ||||
| 						return nil, fmt.Errorf("parsing %s: %w", file.Filename, err) | ||||
| 					} | ||||
| 					break | ||||
| 				} | ||||
| 				configDict = dict | ||||
| 				postProcessor = p | ||||
|  | ||||
| 				if err := processYaml(); err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 			} | ||||
| 			configDict = dict | ||||
| 			file.Config = dict | ||||
| 			configDetails.ConfigFiles[i] = file | ||||
| 			postProcessor = p | ||||
| 		} | ||||
|  | ||||
| 		if !opts.SkipValidation { | ||||
| 			if err := schema.Validate(configDict); err != nil { | ||||
| 				return nil, fmt.Errorf("validating %s: %w", file.Filename, err) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		configDict = groupXFieldsIntoExtensions(configDict) | ||||
|  | ||||
| 		cfg, err := loadSections(file.Filename, configDict, configDetails, opts) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		if !opts.SkipInclude { | ||||
| 			cfg, err = loadInclude(configDetails, cfg, opts, loaded) | ||||
| 			if err != nil { | ||||
| 		} else { | ||||
| 			if err := processYaml(); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if i == 0 { | ||||
| 			model = cfg | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		merged, err := merge([]*types.Config{model, cfg}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if postProcessor != nil { | ||||
| 			err = postProcessor.Apply(merged) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
| 		model = merged | ||||
| 	} | ||||
|  | ||||
| 	project := &types.Project{ | ||||
| @@ -303,6 +349,10 @@ func load(configDetails types.ConfigDetails, opts *Options, loaded []string) (*t | ||||
| 		Extensions:  model.Extensions, | ||||
| 	} | ||||
|  | ||||
| 	if len(includeRefs) != 0 { | ||||
| 		project.IncludeReferences = includeRefs | ||||
| 	} | ||||
|  | ||||
| 	if !opts.SkipNormalization { | ||||
| 		err := Normalize(project) | ||||
| 		if err != nil { | ||||
| @@ -333,9 +383,6 @@ func load(configDetails types.ConfigDetails, opts *Options, loaded []string) (*t | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if profiles, ok := project.Environment[consts.ComposeProfiles]; ok && len(opts.Profiles) == 0 { | ||||
| 		opts.Profiles = strings.Split(profiles, ",") | ||||
| 	} | ||||
| 	project.ApplyProfiles(opts.Profiles) | ||||
|  | ||||
| 	err := project.ResolveServicesEnvironment(opts.discardEnvFiles) | ||||
| @@ -422,8 +469,8 @@ func NormalizeProjectName(s string) string { | ||||
| 	return strings.TrimLeft(s, "_-") | ||||
| } | ||||
|  | ||||
| func parseConfig(b []byte, opts *Options) (map[string]interface{}, PostProcessor, error) { | ||||
| 	yml, postProcessor, err := parseYAML(b) | ||||
| func parseConfig(decoder *yaml.Decoder, opts *Options) (map[string]interface{}, PostProcessor, error) { | ||||
| 	yml, postProcessor, err := parseYAML(decoder) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| @@ -453,7 +500,7 @@ func groupXFieldsIntoExtensions(dict map[string]interface{}) map[string]interfac | ||||
| 	return dict | ||||
| } | ||||
|  | ||||
| func loadSections(filename string, config map[string]interface{}, configDetails types.ConfigDetails, opts *Options) (*types.Config, error) { | ||||
| func loadSections(ctx context.Context, filename string, config map[string]interface{}, configDetails types.ConfigDetails, opts *Options) (*types.Config, error) { | ||||
| 	var err error | ||||
| 	cfg := types.Config{ | ||||
| 		Filename: filename, | ||||
| @@ -466,7 +513,7 @@ func loadSections(filename string, config map[string]interface{}, configDetails | ||||
| 		} | ||||
| 	} | ||||
| 	cfg.Name = name | ||||
| 	cfg.Services, err = LoadServices(filename, getSection(config, "services"), configDetails.WorkingDir, configDetails.LookupEnv, opts) | ||||
| 	cfg.Services, err = LoadServices(ctx, filename, getSection(config, "services"), configDetails.WorkingDir, configDetails.LookupEnv, opts) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -659,7 +706,7 @@ func formatInvalidKeyError(keyPrefix string, key interface{}) error { | ||||
|  | ||||
| // LoadServices produces a ServiceConfig map from a compose file Dict | ||||
| // the servicesDict is not validated if directly used. Use Load() to enable validation | ||||
| func LoadServices(filename string, servicesDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, opts *Options) ([]types.ServiceConfig, error) { | ||||
| func LoadServices(ctx context.Context, filename string, servicesDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, opts *Options) ([]types.ServiceConfig, error) { | ||||
| 	var services []types.ServiceConfig | ||||
|  | ||||
| 	x, ok := servicesDict[extensions] | ||||
| @@ -672,7 +719,7 @@ func LoadServices(filename string, servicesDict map[string]interface{}, workingD | ||||
| 	} | ||||
|  | ||||
| 	for name := range servicesDict { | ||||
| 		serviceConfig, err := loadServiceWithExtends(filename, name, servicesDict, workingDir, lookupEnv, opts, &cycleTracker{}) | ||||
| 		serviceConfig, err := loadServiceWithExtends(ctx, filename, name, servicesDict, workingDir, lookupEnv, opts, &cycleTracker{}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -683,7 +730,7 @@ func LoadServices(filename string, servicesDict map[string]interface{}, workingD | ||||
| 	return services, nil | ||||
| } | ||||
|  | ||||
| func loadServiceWithExtends(filename, name string, servicesDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, opts *Options, ct *cycleTracker) (*types.ServiceConfig, error) { | ||||
| func loadServiceWithExtends(ctx context.Context, filename, name string, servicesDict map[string]interface{}, workingDir string, lookupEnv template.Mapping, opts *Options, ct *cycleTracker) (*types.ServiceConfig, error) { | ||||
| 	if err := ct.Add(filename, name); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -707,11 +754,21 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter | ||||
| 		var baseService *types.ServiceConfig | ||||
| 		file := serviceConfig.Extends.File | ||||
| 		if file == "" { | ||||
| 			baseService, err = loadServiceWithExtends(filename, baseServiceName, servicesDict, workingDir, lookupEnv, opts, ct) | ||||
| 			baseService, err = loadServiceWithExtends(ctx, filename, baseServiceName, servicesDict, workingDir, lookupEnv, opts, ct) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} else { | ||||
| 			for _, loader := range opts.ResourceLoaders { | ||||
| 				if loader.Accept(file) { | ||||
| 					path, err := loader.Load(ctx, file) | ||||
| 					if err != nil { | ||||
| 						return nil, err | ||||
| 					} | ||||
| 					file = path | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			// Resolve the path to the imported file, and load it. | ||||
| 			baseFilePath := absPath(workingDir, file) | ||||
|  | ||||
| @@ -720,13 +777,16 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			baseFile, _, err := parseConfig(b, opts) | ||||
| 			r := bytes.NewReader(b) | ||||
| 			decoder := yaml.NewDecoder(r) | ||||
|  | ||||
| 			baseFile, _, err := parseConfig(decoder, opts) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			baseFileServices := getSection(baseFile, "services") | ||||
| 			baseService, err = loadServiceWithExtends(baseFilePath, baseServiceName, baseFileServices, filepath.Dir(baseFilePath), lookupEnv, opts, ct) | ||||
| 			baseService, err = loadServiceWithExtends(ctx, baseFilePath, baseServiceName, baseFileServices, filepath.Dir(baseFilePath), lookupEnv, opts, ct) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| @@ -1038,7 +1098,12 @@ var transformServiceDeviceRequest TransformerFunc = func(data interface{}) (inte | ||||
| 					value["count"] = -1 | ||||
| 					return value, nil | ||||
| 				} | ||||
| 				return data, errors.Errorf("invalid string value for 'count' (the only value allowed is 'all')") | ||||
| 				i, err := strconv.ParseInt(val, 10, 64) | ||||
| 				if err == nil { | ||||
| 					value["count"] = i | ||||
| 					return value, nil | ||||
| 				} | ||||
| 				return data, errors.Errorf("invalid string value for 'count' (the only value allowed is 'all' or a number)") | ||||
| 			default: | ||||
| 				return data, errors.Errorf("invalid type %T for device count", val) | ||||
| 			} | ||||
|   | ||||
							
								
								
									
										30
									
								
								vendor/github.com/compose-spec/compose-go/loader/paths.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/compose-spec/compose-go/loader/paths.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -64,6 +64,25 @@ func ResolveRelativePaths(project *types.Project) error { | ||||
| 			project.Volumes[name] = config | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// don't coerce a nil map to an empty map | ||||
| 	if project.IncludeReferences != nil { | ||||
| 		absIncludes := make(map[string][]types.IncludeConfig, len(project.IncludeReferences)) | ||||
| 		for filename, config := range project.IncludeReferences { | ||||
| 			filename = absPath(project.WorkingDir, filename) | ||||
| 			absConfigs := make([]types.IncludeConfig, len(config)) | ||||
| 			for i, c := range config { | ||||
| 				absConfigs[i] = types.IncludeConfig{ | ||||
| 					Path:             resolvePaths(project.WorkingDir, c.Path), | ||||
| 					ProjectDirectory: absPath(project.WorkingDir, c.ProjectDirectory), | ||||
| 					EnvFile:          resolvePaths(project.WorkingDir, c.EnvFile), | ||||
| 				} | ||||
| 			} | ||||
| 			absIncludes[filename] = absConfigs | ||||
| 		} | ||||
| 		project.IncludeReferences = absIncludes | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -133,3 +152,14 @@ func isRemoteContext(maybeURL string) bool { | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func resolvePaths(basePath string, in types.StringList) types.StringList { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	ret := make(types.StringList, len(in)) | ||||
| 	for i := range in { | ||||
| 		ret[i] = absPath(basePath, in[i]) | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/compose-spec/compose-go/types/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/compose-spec/compose-go/types/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -34,7 +34,7 @@ type ConfigDetails struct { | ||||
| 	Version     string | ||||
| 	WorkingDir  string | ||||
| 	ConfigFiles []ConfigFile | ||||
| 	Environment map[string]string | ||||
| 	Environment Mapping | ||||
| } | ||||
|  | ||||
| // LookupEnv provides a lookup function for environment variables | ||||
|   | ||||
							
								
								
									
										39
									
								
								vendor/github.com/compose-spec/compose-go/types/project.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/compose-spec/compose-go/types/project.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -36,16 +36,22 @@ import ( | ||||
|  | ||||
| // Project is the result of loading a set of compose files | ||||
| type Project struct { | ||||
| 	Name         string     `yaml:"name,omitempty" json:"name,omitempty"` | ||||
| 	WorkingDir   string     `yaml:"-" json:"-"` | ||||
| 	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:"#extensions,inline" json:"-"` // https://github.com/golang/go/issues/6213 | ||||
| 	ComposeFiles []string   `yaml:"-" json:"-"` | ||||
| 	Environment  Mapping    `yaml:"-" json:"-"` | ||||
| 	Name       string     `yaml:"name,omitempty" json:"name,omitempty"` | ||||
| 	WorkingDir string     `yaml:"-" json:"-"` | ||||
| 	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:"#extensions,inline" json:"-"` // https://github.com/golang/go/issues/6213 | ||||
|  | ||||
| 	// IncludeReferences is keyed by Compose YAML filename and contains config for | ||||
| 	// other Compose YAML files it directly triggered a load of via `include`. | ||||
| 	// | ||||
| 	// Note: this is | ||||
| 	IncludeReferences map[string][]IncludeConfig `yaml:"-" json:"-"` | ||||
| 	ComposeFiles      []string                   `yaml:"-" json:"-"` | ||||
| 	Environment       Mapping                    `yaml:"-" json:"-"` | ||||
|  | ||||
| 	// DisabledServices track services which have been disable as profile is not active | ||||
| 	DisabledServices Services `yaml:"-" json:"-"` | ||||
| @@ -423,13 +429,24 @@ func (p *Project) ForServices(names []string, options ...DependencyOption) error | ||||
| 			} | ||||
| 			enabled = append(enabled, s) | ||||
| 		} else { | ||||
| 			p.DisabledServices = append(p.DisabledServices, s) | ||||
| 			p.DisableService(s) | ||||
| 		} | ||||
| 	} | ||||
| 	p.Services = enabled | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *Project) DisableService(service ServiceConfig) { | ||||
| 	// We should remove all dependencies which reference the disabled service | ||||
| 	for i, s := range p.Services { | ||||
| 		if _, ok := s.DependsOn[service.Name]; ok { | ||||
| 			delete(s.DependsOn, service.Name) | ||||
| 			p.Services[i] = s | ||||
| 		} | ||||
| 	} | ||||
| 	p.DisabledServices = append(p.DisabledServices, service) | ||||
| } | ||||
|  | ||||
| // ResolveImages updates services images to include digest computed by a resolver function | ||||
| func (p *Project) ResolveImages(resolver func(named reference.Named) (godigest.Digest, error)) error { | ||||
| 	eg := errgroup.Group{} | ||||
|   | ||||
							
								
								
									
										28
									
								
								vendor/github.com/compose-spec/compose-go/types/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/compose-spec/compose-go/types/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -491,6 +491,16 @@ func NewMapping(values []string) Mapping { | ||||
| 	return mapping | ||||
| } | ||||
|  | ||||
| // convert values into a set of KEY=VALUE strings | ||||
| func (m Mapping) Values() []string { | ||||
| 	values := make([]string, 0, len(m)) | ||||
| 	for k, v := range m { | ||||
| 		values = append(values, fmt.Sprintf("%s=%s", k, v)) | ||||
| 	} | ||||
| 	sort.Strings(values) | ||||
| 	return values | ||||
| } | ||||
|  | ||||
| // ToMappingWithEquals converts Mapping into a MappingWithEquals with pointer references | ||||
| func (m Mapping) ToMappingWithEquals() MappingWithEquals { | ||||
| 	mapping := MappingWithEquals{} | ||||
| @@ -506,6 +516,24 @@ func (m Mapping) Resolve(s string) (string, bool) { | ||||
| 	return v, ok | ||||
| } | ||||
|  | ||||
| func (m Mapping) Clone() Mapping { | ||||
| 	clone := Mapping{} | ||||
| 	for k, v := range m { | ||||
| 		clone[k] = v | ||||
| 	} | ||||
| 	return clone | ||||
| } | ||||
|  | ||||
| // Merge adds all values from second mapping which are not already defined | ||||
| func (m Mapping) Merge(o Mapping) Mapping { | ||||
| 	for k, v := range o { | ||||
| 		if _, set := m[k]; !set { | ||||
| 			m[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return m | ||||
| } | ||||
|  | ||||
| // Labels is a mapping type for labels | ||||
| type Labels map[string]string | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sebastiaan van Stijn
					Sebastiaan van Stijn