浏览代码

Merge pull request #1838 from jmcvetta/multiline_dockerfile

Implementation of multiline syntax for Dockerfile
Michael Crosby 11 年之前
父节点
当前提交
bd0e4fde9a
共有 4 个文件被更改,包括 42 次插入17 次删除
  1. 1 1
      api_test.go
  2. 12 14
      buildfile.go
  3. 28 0
      buildfile_test.go
  4. 1 2
      utils/utils_test.go

+ 1 - 1
api_test.go

@@ -445,7 +445,7 @@ func TestGetContainersChanges(t *testing.T) {
 }
 
 func TestGetContainersTop(t *testing.T) {
-        t.Skip("Fixme. Skipping test for now. Reported error when testing using dind: 'api_test.go:527: Expected 2 processes, found 0.'")
+	t.Skip("Fixme. Skipping test for now. Reported error when testing using dind: 'api_test.go:527: Expected 2 processes, found 0.'")
 	runtime, err := newTestRuntime()
 	if err != nil {
 		t.Fatal(err)

+ 12 - 14
buildfile.go

@@ -1,7 +1,6 @@
 package docker
 
 import (
-	"bufio"
 	"encoding/json"
 	"fmt"
 	"github.com/dotcloud/docker/utils"
@@ -458,6 +457,9 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
 	return nil
 }
 
+// Long lines can be split with a backslash
+var lineContinuation = regexp.MustCompile(`\s*\\\s*\n`)
+
 func (b *buildFile) Build(context io.Reader) (string, error) {
 	// FIXME: @creack any reason for using /tmp instead of ""?
 	// FIXME: @creack "name" is a terrible variable name
@@ -470,22 +472,18 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
 	}
 	defer os.RemoveAll(name)
 	b.context = name
-	dockerfile, err := os.Open(path.Join(name, "Dockerfile"))
-	if err != nil {
+	filename := path.Join(name, "Dockerfile")
+	if _, err := os.Stat(filename); os.IsNotExist(err) {
 		return "", fmt.Errorf("Can't build a directory with no Dockerfile")
 	}
-	// FIXME: "file" is also a terrible variable name ;)
-	file := bufio.NewReader(dockerfile)
+	fileBytes, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return "", err
+	}
+	dockerfile := string(fileBytes)
+	dockerfile = lineContinuation.ReplaceAllString(dockerfile, " ")
 	stepN := 0
-	for {
-		line, err := file.ReadString('\n')
-		if err != nil {
-			if err == io.EOF && line == "" {
-				break
-			} else if err != io.EOF {
-				return "", err
-			}
-		}
+	for _, line := range strings.Split(dockerfile, "\n") {
 		line = strings.Trim(strings.Replace(line, "\t", " ", -1), " \t\r\n")
 		// Skip comments and empty line
 		if len(line) == 0 || line[0] == '#' {

+ 28 - 0
buildfile_test.go

@@ -45,6 +45,34 @@ run    [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
 		nil,
 	},
 
+	// Exactly the same as above, except uses a line split with a \ to test
+	// multiline support.
+	{
+		`
+from   {IMAGE}
+run    sh -c 'echo root:testpass \
+	> /tmp/passwd'
+run    mkdir -p /var/run/sshd
+run    [ "$(cat /tmp/passwd)" = "root:testpass" ]
+run    [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
+`,
+		nil,
+		nil,
+	},
+
+	// Line containing literal "\n"
+	{
+		`
+from   {IMAGE}
+run    sh -c 'echo root:testpass > /tmp/passwd'
+run    echo "foo \n bar"; echo "baz"
+run    mkdir -p /var/run/sshd
+run    [ "$(cat /tmp/passwd)" = "root:testpass" ]
+run    [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
+`,
+		nil,
+		nil,
+	},
 	{
 		`
 from {IMAGE}

+ 1 - 2
utils/utils_test.go

@@ -366,7 +366,6 @@ func TestParseRelease(t *testing.T) {
 	assertParseRelease(t, "3.8.0-19-generic", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "19-generic"}, 0)
 }
 
-
 func TestDependencyGraphCircular(t *testing.T) {
 	g1 := NewDependencyGraph()
 	a := g1.NewNode("a")
@@ -421,4 +420,4 @@ func TestDependencyGraph(t *testing.T) {
 	if len(res[2]) != 1 || res[2][0] != "d" {
 		t.Fatalf("Expected [d], found %v instead", res[2])
 	}
-}
+}