Sfoglia il codice sorgente

Merge pull request #1233 from fmd/1136-environment-variables

+ Builder: CmdAdd and CmdEnv now respect Dockerfile-set ENV variables
Guillaume J. Charmes 12 anni fa
parent
commit
f35491190a
3 ha cambiato i file con 103 aggiunte e 15 eliminazioni
  1. 60 9
      buildfile.go
  2. 40 2
      buildfile_test.go
  3. 3 4
      utils/utils.go

+ 60 - 9
buildfile.go

@@ -11,6 +11,7 @@ import (
 	"os"
 	"path"
 	"reflect"
+	"regexp"
 	"strings"
 )
 
@@ -67,6 +68,9 @@ func (b *buildFile) CmdFrom(name string) error {
 	}
 	b.image = image.ID
 	b.config = &Config{}
+	if b.config.Env == nil || len(b.config.Env) == 0 {
+		b.config.Env = append(b.config.Env, "HOME=/", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin")
+	}
 	return nil
 }
 
@@ -112,6 +116,40 @@ func (b *buildFile) CmdRun(args string) error {
 	return nil
 }
 
+func (b *buildFile) FindEnvKey(key string) int {
+	for k, envVar := range b.config.Env {
+		envParts := strings.SplitN(envVar, "=", 2)
+		if key == envParts[0] {
+			return k
+		}
+	}
+	return -1
+}
+
+func (b *buildFile) ReplaceEnvMatches(value string) (string, error) {
+	exp, err := regexp.Compile("(\\\\\\\\+|[^\\\\]|\\b|\\A)\\$({?)([[:alnum:]_]+)(}?)")
+	if err != nil {
+		return value, err
+	}
+	matches := exp.FindAllString(value, -1)
+	for _, match := range matches {
+		match = match[strings.Index(match, "$"):]
+		matchKey := strings.Trim(match, "${}")
+
+		for _, envVar := range b.config.Env {
+			envParts := strings.SplitN(envVar, "=", 2)
+			envKey := envParts[0]
+			envValue := envParts[1]
+
+			if envKey == matchKey {
+				value = strings.Replace(value, match, envValue, -1)
+				break
+			}
+		}
+	}
+	return value, nil
+}
+
 func (b *buildFile) CmdEnv(args string) error {
 	tmp := strings.SplitN(args, " ", 2)
 	if len(tmp) != 2 {
@@ -120,14 +158,19 @@ func (b *buildFile) CmdEnv(args string) error {
 	key := strings.Trim(tmp[0], " \t")
 	value := strings.Trim(tmp[1], " \t")
 
-	for i, elem := range b.config.Env {
-		if strings.HasPrefix(elem, key+"=") {
-			b.config.Env[i] = key + "=" + value
-			return nil
-		}
+	envKey := b.FindEnvKey(key)
+	replacedValue, err := b.ReplaceEnvMatches(value)
+	if err != nil {
+		return err
 	}
-	b.config.Env = append(b.config.Env, key+"="+value)
-	return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s=%s", key, value))
+	replacedVar := fmt.Sprintf("%s=%s", key, replacedValue)
+
+	if envKey >= 0 {
+		b.config.Env[envKey] = replacedVar
+		return nil
+	}
+	b.config.Env = append(b.config.Env, replacedVar)
+	return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s", replacedVar))
 }
 
 func (b *buildFile) CmdCmd(args string) error {
@@ -260,8 +303,16 @@ func (b *buildFile) CmdAdd(args string) error {
 	if len(tmp) != 2 {
 		return fmt.Errorf("Invalid ADD format")
 	}
-	orig := strings.Trim(tmp[0], " \t")
-	dest := strings.Trim(tmp[1], " \t")
+
+	orig, err := b.ReplaceEnvMatches(strings.Trim(tmp[0], " \t"))
+	if err != nil {
+		return err
+	}
+
+	dest, err := b.ReplaceEnvMatches(strings.Trim(tmp[1], " \t"))
+	if err != nil {
+		return err
+	}
 
 	cmd := b.config.Cmd
 	b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", orig, dest)}

+ 40 - 2
buildfile_test.go

@@ -129,6 +129,38 @@ CMD Hello world
 		nil,
 		nil,
 	},
+
+	{
+		`
+from {IMAGE}
+env    FOO /foo/baz
+env    BAR /bar
+env    BAZ $BAR
+env    FOOPATH $PATH:$FOO
+run    [ "$BAR" = "$BAZ" ]
+run    [ "$FOOPATH" = "$PATH:/foo/baz" ]
+`,
+		nil,
+		nil,
+	},
+
+	{
+		`
+from {IMAGE}
+env    FOO /bar
+env    TEST testdir
+env    BAZ /foobar
+add    testfile $BAZ/
+add    $TEST $FOO
+run    [ "$(cat /foobar/testfile)" = "test1" ]
+run    [ "$(cat /bar/withfile)" = "test2" ]
+`,
+		[][2]string{
+			{"testfile", "test1"},
+			{"testdir/withfile", "test2"},
+		},
+		nil,
+	},
 }
 
 // FIXME: test building with 2 successive overlapping ADD commands
@@ -242,8 +274,14 @@ func TestBuildEnv(t *testing.T) {
         env port 4243
         `,
 		nil, nil}, t)
-
-	if img.Config.Env[0] != "port=4243" {
+	hasEnv := false
+	for _, envVar := range img.Config.Env {
+		if envVar == "port=4243" {
+			hasEnv = true
+			break
+		}
+	}
+	if !hasEnv {
 		t.Fail()
 	}
 }

+ 3 - 4
utils/utils.go

@@ -611,11 +611,11 @@ type JSONMessage struct {
 	Status   string `json:"status,omitempty"`
 	Progress string `json:"progress,omitempty"`
 	Error    string `json:"error,omitempty"`
-	ID	 string `json:"id,omitempty"`
-	Time	 int64 `json:"time,omitempty"`
+	ID       string `json:"id,omitempty"`
+	Time     int64  `json:"time,omitempty"`
 }
 
-func (jm *JSONMessage) Display(out io.Writer) (error) {
+func (jm *JSONMessage) Display(out io.Writer) error {
 	if jm.Time != 0 {
 		fmt.Fprintf(out, "[%s] ", time.Unix(jm.Time, 0))
 	}
@@ -631,7 +631,6 @@ func (jm *JSONMessage) Display(out io.Writer) (error) {
 	return nil
 }
 
-
 type StreamFormatter struct {
 	json bool
 	used bool