|  | @@ -1,172 +0,0 @@
 | 
	
		
			
				|  |  | -/*
 | 
	
		
			
				|  |  | -   Copyright 2020 Docker, Inc.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -   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 compose
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import (
 | 
	
		
			
				|  |  | -	"fmt"
 | 
	
		
			
				|  |  | -	"io/ioutil"
 | 
	
		
			
				|  |  | -	"os"
 | 
	
		
			
				|  |  | -	"path/filepath"
 | 
	
		
			
				|  |  | -	"regexp"
 | 
	
		
			
				|  |  | -	"strings"
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	"github.com/compose-spec/compose-go/loader"
 | 
	
		
			
				|  |  | -	"github.com/compose-spec/compose-go/types"
 | 
	
		
			
				|  |  | -	"github.com/sirupsen/logrus"
 | 
	
		
			
				|  |  | -)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -var supportedFilenames = []string{
 | 
	
		
			
				|  |  | -	"compose.yml",
 | 
	
		
			
				|  |  | -	"compose.yaml",
 | 
	
		
			
				|  |  | -	"docker-compose.yml",
 | 
	
		
			
				|  |  | -	"docker-compose.yaml",
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// ProjectOptions configures a compose project
 | 
	
		
			
				|  |  | -type ProjectOptions struct {
 | 
	
		
			
				|  |  | -	Name        string
 | 
	
		
			
				|  |  | -	WorkDir     string
 | 
	
		
			
				|  |  | -	ConfigPaths []string
 | 
	
		
			
				|  |  | -	Environment []string
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// Project represents a compose project with a name
 | 
	
		
			
				|  |  | -type Project struct {
 | 
	
		
			
				|  |  | -	types.Config
 | 
	
		
			
				|  |  | -	projectDir string
 | 
	
		
			
				|  |  | -	Name       string `yaml:"-" json:"-"`
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// ProjectFromOptions load a compose project based on given options
 | 
	
		
			
				|  |  | -func ProjectFromOptions(options *ProjectOptions) (*Project, error) {
 | 
	
		
			
				|  |  | -	configPath, err := getConfigPathFromOptions(options)
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		return nil, err
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	configs, err := parseConfigs(configPath)
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		return nil, err
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	name := options.Name
 | 
	
		
			
				|  |  | -	if name == "" {
 | 
	
		
			
				|  |  | -		r := regexp.MustCompile(`[^a-z0-9\\-_]+`)
 | 
	
		
			
				|  |  | -		absPath, err := filepath.Abs(options.WorkDir)
 | 
	
		
			
				|  |  | -		if err != nil {
 | 
	
		
			
				|  |  | -			return nil, err
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		name = r.ReplaceAllString(strings.ToLower(filepath.Base(absPath)), "")
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	return newProject(types.ConfigDetails{
 | 
	
		
			
				|  |  | -		WorkingDir:  options.WorkDir,
 | 
	
		
			
				|  |  | -		ConfigFiles: configs,
 | 
	
		
			
				|  |  | -		Environment: getAsEqualsMap(options.Environment),
 | 
	
		
			
				|  |  | -	}, name)
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func newProject(config types.ConfigDetails, name string) (*Project, error) {
 | 
	
		
			
				|  |  | -	model, err := loader.Load(config)
 | 
	
		
			
				|  |  | -	if err != nil {
 | 
	
		
			
				|  |  | -		return nil, err
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	p := Project{
 | 
	
		
			
				|  |  | -		Config:     *model,
 | 
	
		
			
				|  |  | -		projectDir: config.WorkingDir,
 | 
	
		
			
				|  |  | -		Name:       name,
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	return &p, nil
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func getConfigPathFromOptions(options *ProjectOptions) ([]string, error) {
 | 
	
		
			
				|  |  | -	var paths []string
 | 
	
		
			
				|  |  | -	pwd := options.WorkDir
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if len(options.ConfigPaths) != 0 {
 | 
	
		
			
				|  |  | -		for _, f := range options.ConfigPaths {
 | 
	
		
			
				|  |  | -			if f == "-" {
 | 
	
		
			
				|  |  | -				paths = append(paths, f)
 | 
	
		
			
				|  |  | -				continue
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			if !filepath.IsAbs(f) {
 | 
	
		
			
				|  |  | -				f = filepath.Join(pwd, f)
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			if _, err := os.Stat(f); err != nil {
 | 
	
		
			
				|  |  | -				return nil, err
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			paths = append(paths, f)
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		return paths, nil
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	for {
 | 
	
		
			
				|  |  | -		var candidates []string
 | 
	
		
			
				|  |  | -		for _, n := range supportedFilenames {
 | 
	
		
			
				|  |  | -			f := filepath.Join(pwd, n)
 | 
	
		
			
				|  |  | -			if _, err := os.Stat(f); err == nil {
 | 
	
		
			
				|  |  | -				candidates = append(candidates, f)
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		if len(candidates) > 0 {
 | 
	
		
			
				|  |  | -			winner := candidates[0]
 | 
	
		
			
				|  |  | -			if len(candidates) > 1 {
 | 
	
		
			
				|  |  | -				logrus.Warnf("Found multiple config files with supported names: %s", strings.Join(candidates, ", "))
 | 
	
		
			
				|  |  | -				logrus.Warnf("Using %s\n", winner)
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			return []string{winner}, nil
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		parent := filepath.Dir(pwd)
 | 
	
		
			
				|  |  | -		if parent == pwd {
 | 
	
		
			
				|  |  | -			return nil, fmt.Errorf("can't find a suitable configuration file in this directory or any parent. Is %q the right directory?", pwd)
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		pwd = parent
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -func parseConfigs(configPaths []string) ([]types.ConfigFile, error) {
 | 
	
		
			
				|  |  | -	var files []types.ConfigFile
 | 
	
		
			
				|  |  | -	for _, f := range configPaths {
 | 
	
		
			
				|  |  | -		var b []byte
 | 
	
		
			
				|  |  | -		var err error
 | 
	
		
			
				|  |  | -		if f == "-" {
 | 
	
		
			
				|  |  | -			b, err = ioutil.ReadAll(os.Stdin)
 | 
	
		
			
				|  |  | -		} else {
 | 
	
		
			
				|  |  | -			b, err = ioutil.ReadFile(f)
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		if err != nil {
 | 
	
		
			
				|  |  | -			return nil, err
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		config, err := loader.ParseYAML(b)
 | 
	
		
			
				|  |  | -		if err != nil {
 | 
	
		
			
				|  |  | -			return nil, err
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		files = append(files, types.ConfigFile{Filename: f, Config: config})
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	return files, nil
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// getAsEqualsMap split key=value formatted strings into a key : value map
 | 
	
		
			
				|  |  | -func getAsEqualsMap(em []string) map[string]string {
 | 
	
		
			
				|  |  | -	m := make(map[string]string)
 | 
	
		
			
				|  |  | -	for _, v := range em {
 | 
	
		
			
				|  |  | -		kv := strings.SplitN(v, "=", 2)
 | 
	
		
			
				|  |  | -		m[kv[0]] = kv[1]
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -	return m
 | 
	
		
			
				|  |  | -}
 |