Functions and types in this package were exported as part of the "compose on kubernetes" feature, which was deprecated and removed. These functions are meant for internal use, and will be removed in the next release. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
186 lines
5.3 KiB
Go
186 lines
5.3 KiB
Go
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
|
//go:build go1.23
|
|
|
|
package loader
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/distribution/reference"
|
|
"github.com/docker/cli/cli/command"
|
|
"github.com/docker/cli/cli/command/stack/options"
|
|
"github.com/docker/cli/cli/compose/loader"
|
|
"github.com/docker/cli/cli/compose/schema"
|
|
composetypes "github.com/docker/cli/cli/compose/types"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// LoadComposefile parse the composefile specified in the cli and returns its Config and version.
|
|
//
|
|
// Deprecated: this function was for internal use and will be removed in the next release.
|
|
func LoadComposefile(dockerCli command.Cli, opts options.Deploy) (*composetypes.Config, error) {
|
|
configDetails, err := GetConfigDetails(opts.Composefiles, dockerCli.In())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dicts := getDictsFrom(configDetails.ConfigFiles)
|
|
config, err := loader.Load(configDetails)
|
|
if err != nil {
|
|
if fpe, ok := err.(*loader.ForbiddenPropertiesError); ok {
|
|
// this error is intentionally formatted multi-line
|
|
return nil, errors.Errorf("Compose file contains unsupported options:\n\n%s\n", propertyWarnings(fpe.Properties))
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
unsupportedProperties := loader.GetUnsupportedProperties(dicts...)
|
|
if len(unsupportedProperties) > 0 {
|
|
_, _ = fmt.Fprintf(dockerCli.Err(), "Ignoring unsupported options: %s\n\n",
|
|
strings.Join(unsupportedProperties, ", "))
|
|
}
|
|
|
|
deprecatedProperties := loader.GetDeprecatedProperties(dicts...)
|
|
if len(deprecatedProperties) > 0 {
|
|
_, _ = fmt.Fprintf(dockerCli.Err(), "Ignoring deprecated options:\n\n%s\n\n",
|
|
propertyWarnings(deprecatedProperties))
|
|
}
|
|
|
|
// Validate if each service has a valid image-reference.
|
|
for _, svc := range config.Services {
|
|
if svc.Image == "" {
|
|
return nil, errors.Errorf("invalid image reference for service %s: no image specified", svc.Name)
|
|
}
|
|
if _, err := reference.ParseAnyReference(svc.Image); err != nil {
|
|
return nil, errors.Wrapf(err, "invalid image reference for service %s", svc.Name)
|
|
}
|
|
}
|
|
|
|
return config, nil
|
|
}
|
|
|
|
func getDictsFrom(configFiles []composetypes.ConfigFile) []map[string]any {
|
|
dicts := []map[string]any{}
|
|
|
|
for _, configFile := range configFiles {
|
|
dicts = append(dicts, configFile.Config)
|
|
}
|
|
|
|
return dicts
|
|
}
|
|
|
|
func propertyWarnings(properties map[string]string) string {
|
|
msgs := make([]string, 0, len(properties))
|
|
for name, description := range properties {
|
|
msgs = append(msgs, fmt.Sprintf("%s: %s", name, description))
|
|
}
|
|
sort.Strings(msgs)
|
|
return strings.Join(msgs, "\n\n")
|
|
}
|
|
|
|
// GetConfigDetails parse the composefiles specified in the cli and returns their ConfigDetails
|
|
//
|
|
// Deprecated: this function was for internal use and will be removed in the next release.
|
|
func GetConfigDetails(composefiles []string, stdin io.Reader) (composetypes.ConfigDetails, error) {
|
|
var details composetypes.ConfigDetails
|
|
|
|
if len(composefiles) == 0 {
|
|
return details, errors.New("Specify a Compose file (with --compose-file)")
|
|
}
|
|
|
|
if composefiles[0] == "-" && len(composefiles) == 1 {
|
|
workingDir, err := os.Getwd()
|
|
if err != nil {
|
|
return details, err
|
|
}
|
|
details.WorkingDir = workingDir
|
|
} else {
|
|
absPath, err := filepath.Abs(composefiles[0])
|
|
if err != nil {
|
|
return details, err
|
|
}
|
|
details.WorkingDir = filepath.Dir(absPath)
|
|
}
|
|
|
|
var err error
|
|
details.ConfigFiles, err = loadConfigFiles(composefiles, stdin)
|
|
if err != nil {
|
|
return details, err
|
|
}
|
|
// Take the first file version (2 files can't have different version)
|
|
details.Version = schema.Version(details.ConfigFiles[0].Config)
|
|
details.Environment, err = buildEnvironment(os.Environ())
|
|
return details, err
|
|
}
|
|
|
|
func buildEnvironment(env []string) (map[string]string, error) {
|
|
result := make(map[string]string, len(env))
|
|
for _, s := range env {
|
|
if runtime.GOOS == "windows" && len(s) > 0 {
|
|
// cmd.exe can have special environment variables which names start with "=".
|
|
// They are only there for MS-DOS compatibility and we should ignore them.
|
|
// See TestBuildEnvironment for examples.
|
|
//
|
|
// https://ss64.com/nt/syntax-variables.html
|
|
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
|
|
// https://github.com/docker/cli/issues/4078
|
|
if s[0] == '=' {
|
|
continue
|
|
}
|
|
}
|
|
|
|
k, v, ok := strings.Cut(s, "=")
|
|
if !ok || k == "" {
|
|
return result, errors.Errorf("unexpected environment variable '%s'", s)
|
|
}
|
|
// value may be set, but empty if "s" is like "K=", not "K".
|
|
result[k] = v
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func loadConfigFiles(filenames []string, stdin io.Reader) ([]composetypes.ConfigFile, error) {
|
|
configFiles := make([]composetypes.ConfigFile, 0, len(filenames))
|
|
|
|
for _, filename := range filenames {
|
|
configFile, err := loadConfigFile(filename, stdin)
|
|
if err != nil {
|
|
return configFiles, err
|
|
}
|
|
configFiles = append(configFiles, *configFile)
|
|
}
|
|
|
|
return configFiles, nil
|
|
}
|
|
|
|
func loadConfigFile(filename string, stdin io.Reader) (*composetypes.ConfigFile, error) {
|
|
var bytes []byte
|
|
var err error
|
|
|
|
if filename == "-" {
|
|
bytes, err = io.ReadAll(stdin)
|
|
} else {
|
|
bytes, err = os.ReadFile(filename)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config, err := loader.ParseYAML(bytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &composetypes.ConfigFile{
|
|
Filename: filename,
|
|
Config: config,
|
|
}, nil
|
|
}
|