Merge pull request #67 from surajssd/env_var_substitution

Support for environment variables substitution
This commit is contained in:
Suraj Deshmukh 2016-08-02 06:17:11 +05:30 committed by GitHub
commit a63d641384
9 changed files with 106 additions and 81 deletions

88
Godeps/Godeps.json generated
View File

@ -3,7 +3,7 @@
"GoVersion": "go1.6",
"GodepVersion": "v74",
"Packages": [
"./..."
"./cli/main/"
],
"Deps": [
{
@ -44,77 +44,77 @@
},
{
"ImportPath": "github.com/docker/distribution",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/context",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/digest",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/manifest",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/manifest/schema1",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/manifest/schema2",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/reference",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/registry/api/errcode",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/registry/api/v2",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/registry/client",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/registry/client/auth",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/registry/client/transport",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/registry/storage/cache",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/registry/storage/cache/memory",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
"ImportPath": "github.com/docker/distribution/uuid",
"Comment": "v2.5.0-rc.1-22-g4e17ab5",
"Comment": "docs-v2.4.1-2016-06-28-6-g4e17ab5",
"Rev": "4e17ab5d319ac5b70b2769442947567a83386fbc"
},
{
@ -434,73 +434,73 @@
},
{
"ImportPath": "github.com/docker/libcompose/config",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/docker",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/docker/builder",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/docker/client",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/docker/network",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/labels",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/logger",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/lookup",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/project",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/project/events",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/project/options",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/utils",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/version",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libcompose/yaml",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
"Comment": "v0.2.0-198-gced6fdd",
"Rev": "ced6fddc87aaf1bbf3c01df4530b6069508b8602"
},
{
"ImportPath": "github.com/docker/libtrust",

View File

@ -20,6 +20,7 @@ import (
"fmt"
"math/rand"
"os"
"path/filepath"
"strconv"
"strings"
@ -27,7 +28,9 @@ import (
"github.com/urfave/cli"
"github.com/docker/docker/api/client/bundlefile"
"github.com/docker/libcompose/config"
"github.com/docker/libcompose/docker"
"github.com/docker/libcompose/lookup"
"github.com/docker/libcompose/project"
"encoding/json"
@ -789,6 +792,25 @@ func loadComposeFile(file string) KomposeObject {
}
context.ComposeFiles = []string{file}
if context.ResourceLookup == nil {
context.ResourceLookup = &lookup.FileResourceLookup{}
}
if context.EnvironmentLookup == nil {
cwd, err := os.Getwd()
if err != nil {
return KomposeObject{}
}
context.EnvironmentLookup = &lookup.ComposableEnvLookup{
Lookups: []config.EnvironmentLookup{
&lookup.EnvfileLookup{
Path: filepath.Join(cwd, ".env"),
},
&lookup.OsEnvLookup{},
},
}
}
// load compose file into composeObject
composeObject := project.NewProject(&context.Context, nil, nil)
err := composeObject.Parse()

View File

@ -8,6 +8,8 @@ import (
yaml "github.com/cloudfoundry-incubator/candiedyaml"
"github.com/docker/docker/pkg/urlutil"
"github.com/docker/libcompose/utils"
composeYaml "github.com/docker/libcompose/yaml"
)
var (
@ -86,7 +88,13 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe
if _, ok := serviceData["env_file"]; !ok {
return serviceData, nil
}
envFiles := serviceData["env_file"].([]interface{})
var envFiles composeYaml.Stringorslice
if err := utils.Convert(serviceData["env_file"], &envFiles); err != nil {
return nil, err
}
if len(envFiles) == 0 {
return serviceData, nil
}
@ -95,13 +103,16 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe
return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile)
}
var vars []interface{}
var vars composeYaml.MaporEqualSlice
if _, ok := serviceData["environment"]; ok {
vars = serviceData["environment"].([]interface{})
if err := utils.Convert(serviceData["environment"], &vars); err != nil {
return nil, err
}
}
for i := len(envFiles) - 1; i >= 0; i-- {
envFile := envFiles[i].(string)
envFile := envFiles[i]
content, _, err := resourceLookup.Lookup(envFile, inFile)
if err != nil {
return nil, err
@ -114,18 +125,21 @@ func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawSe
scanner := bufio.NewScanner(bytes.NewBuffer(content))
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
key := strings.SplitAfter(line, "=")[0]
found := false
for _, v := range vars {
if strings.HasPrefix(v.(string), key) {
found = true
break
if len(line) > 0 && !strings.HasPrefix(line, "#") {
key := strings.SplitAfter(line, "=")[0]
found := false
for _, v := range vars {
if strings.HasPrefix(v, key) {
found = true
break
}
}
}
if !found {
vars = append(vars, line)
if !found {
vars = append(vars, line)
}
}
}

View File

@ -23,7 +23,7 @@ const ComposeVersion = "1.5.0"
// NewProject creates a Project with the specified context.
func NewProject(context *Context, parseOptions *config.ParseOptions) (project.APIProject, error) {
if context.ResourceLookup == nil {
context.ResourceLookup = &lookup.FileConfigLookup{}
context.ResourceLookup = &lookup.FileResourceLookup{}
}
if context.EnvironmentLookup == nil {

View File

@ -556,7 +556,7 @@ func (s *Service) Kill(ctx context.Context, signal string) error {
func (s *Service) Delete(ctx context.Context, options options.Delete) error {
return s.collectContainersAndDo(ctx, func(c *Container) error {
running, _ := c.IsRunning(ctx)
if !running {
if !running || options.RemoveRunning {
return c.Remove(ctx, options.RemoveVolume)
}
return nil

View File

@ -20,7 +20,7 @@ func relativePath(file, relativeTo string) string {
// stdin: return the current working directory if possible.
if relativeTo == "-" {
if cwd, err := os.Getwd(); err == nil {
return cwd
return filepath.Join(cwd, file)
}
}
@ -39,15 +39,15 @@ func relativePath(file, relativeTo string) string {
return abs
}
// FileConfigLookup is a "bare" structure that implements the project.ResourceLookup interface
type FileConfigLookup struct {
// FileResourceLookup is a "bare" structure that implements the project.ResourceLookup interface
type FileResourceLookup struct {
}
// Lookup returns the content and the actual filename of the file that is "built" using the
// specified file and relativeTo string. file and relativeTo are supposed to be file path.
// If file starts with a slash ('/'), it tries to load it, otherwise it will build a
// filename using the folder part of relativeTo joined with file.
func (f *FileConfigLookup) Lookup(file, relativeTo string) ([]byte, string, error) {
func (f *FileResourceLookup) Lookup(file, relativeTo string) ([]byte, string, error) {
file = relativePath(file, relativeTo)
logrus.Debugf("Reading file %s", file)
bytes, err := ioutil.ReadFile(file)
@ -56,11 +56,11 @@ func (f *FileConfigLookup) Lookup(file, relativeTo string) ([]byte, string, erro
// ResolvePath returns the path to be used for the given path volume. This
// function already takes care of relative paths.
func (f *FileConfigLookup) ResolvePath(path, inFile string) string {
func (f *FileResourceLookup) ResolvePath(path, relativeTo string) string {
vs := strings.SplitN(path, ":", 2)
if len(vs) != 2 || filepath.IsAbs(vs[0]) {
return path
}
vs[0] = relativePath(vs[0], inFile)
vs[0] = relativePath(vs[0], relativeTo)
return strings.Join(vs, ":")
}

View File

@ -37,6 +37,7 @@ type APIProject interface {
CreateService(name string) (Service, error)
AddConfig(name string, config *config.ServiceConfig) error
Load(bytes []byte) error
ListStoppedContainers(ctx context.Context, services ...string) ([]string, error)
}
// RuntimeProject defines runtime-specific methods for a libcompose implementation.

View File

@ -9,8 +9,8 @@ type Build struct {
// Delete holds options of compose rm.
type Delete struct {
RemoveVolume bool
BeforeDeleteCallback func([]string) bool
RemoveVolume bool
RemoveRunning bool
}
// Down holds options of compose down.

View File

@ -496,8 +496,8 @@ func (p *Project) Pull(ctx context.Context, services ...string) error {
}), nil)
}
// listStoppedContainers lists the stopped containers for the specified services.
func (p *Project) listStoppedContainers(ctx context.Context, services ...string) ([]string, error) {
// ListStoppedContainers lists the stopped containers for the specified services.
func (p *Project) ListStoppedContainers(ctx context.Context, services ...string) ([]string, error) {
stoppedContainers := []string{}
err := p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.NoEvent, events.NoEvent, func(service Service) error {
@ -531,18 +531,6 @@ func (p *Project) listStoppedContainers(ctx context.Context, services ...string)
// Delete removes the specified services (like docker rm).
func (p *Project) Delete(ctx context.Context, options options.Delete, services ...string) error {
stoppedContainers, err := p.listStoppedContainers(ctx, services...)
if err != nil {
return err
}
if len(stoppedContainers) == 0 {
p.Notify(events.ProjectDeleteDone, "", nil)
fmt.Println("No stopped containers")
return nil
}
if options.BeforeDeleteCallback != nil && !options.BeforeDeleteCallback(stoppedContainers) {
return nil
}
return p.perform(events.ProjectDeleteStart, events.ProjectDeleteDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.ServiceDeleteStart, events.ServiceDelete, func(service Service) error {
return service.Delete(ctx, options)