forked from LaconicNetwork/kompose
Support for environment variables substitution
Now user can put environment variables in docker-compose file and it will be read by kompose from environment Fixes # 56
This commit is contained in:
+27
-13
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+6
-6
@@ -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, ":")
|
||||
}
|
||||
|
||||
+1
@@ -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.
|
||||
|
||||
+2
-2
@@ -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.
|
||||
|
||||
+2
-14
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user