소스 검색

Add a test for warning on empty continuation lines.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
Daniel Nephin 8 년 전
부모
커밋
b47b375cb8
4개의 변경된 파일53개의 추가작업 그리고 29개의 파일을 삭제
  1. 1 0
      builder/dockerfile/builder.go
  2. 9 1
      builder/dockerfile/parser/parser.go
  3. 38 19
      builder/dockerfile/parser/parser_test.go
  4. 5 9
      builder/remotecontext/detect.go

+ 1 - 0
builder/dockerfile/builder.go

@@ -255,6 +255,7 @@ func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*buil
 		return nil, errors.Errorf("failed to reach build target %s in Dockerfile", b.options.Target)
 		return nil, errors.Errorf("failed to reach build target %s in Dockerfile", b.options.Target)
 	}
 	}
 
 
+	dockerfile.PrintWarnings(b.Stderr)
 	b.buildArgs.WarnOnUnusedBuildArgs(b.Stderr)
 	b.buildArgs.WarnOnUnusedBuildArgs(b.Stderr)
 
 
 	if dispatchState.imageID == "" {
 	if dispatchState.imageID == "" {

+ 9 - 1
builder/dockerfile/parser/parser.go

@@ -246,6 +246,14 @@ type Result struct {
 	Warnings    []string
 	Warnings    []string
 }
 }
 
 
+// PrintWarnings to the writer
+func (r *Result) PrintWarnings(out io.Writer) {
+	if len(r.Warnings) == 0 {
+		return
+	}
+	fmt.Fprintf(out, strings.Join(r.Warnings, "\n")+"\n")
+}
+
 // Parse reads lines from a Reader, parses the lines into an AST and returns
 // Parse reads lines from a Reader, parses the lines into an AST and returns
 // the AST and escape token
 // the AST and escape token
 func Parse(rwc io.Reader) (*Result, error) {
 func Parse(rwc io.Reader) (*Result, error) {
@@ -311,7 +319,7 @@ func Parse(rwc io.Reader) (*Result, error) {
 		AST:         root,
 		AST:         root,
 		Warnings:    warnings,
 		Warnings:    warnings,
 		EscapeToken: d.escapeToken,
 		EscapeToken: d.escapeToken,
-		Platform: d.platformToken,
+		Platform:    d.platformToken,
 	}, nil
 	}, nil
 }
 }
 
 

+ 38 - 19
builder/dockerfile/parser/parser_test.go

@@ -27,40 +27,39 @@ func getDirs(t *testing.T, dir string) []string {
 	return dirs
 	return dirs
 }
 }
 
 
-func TestTestNegative(t *testing.T) {
+func TestParseErrorCases(t *testing.T) {
 	for _, dir := range getDirs(t, negativeTestDir) {
 	for _, dir := range getDirs(t, negativeTestDir) {
 		dockerfile := filepath.Join(negativeTestDir, dir, "Dockerfile")
 		dockerfile := filepath.Join(negativeTestDir, dir, "Dockerfile")
 
 
 		df, err := os.Open(dockerfile)
 		df, err := os.Open(dockerfile)
-		require.NoError(t, err)
+		require.NoError(t, err, dockerfile)
 		defer df.Close()
 		defer df.Close()
 
 
 		_, err = Parse(df)
 		_, err = Parse(df)
-		assert.Error(t, err)
+		assert.Error(t, err, dockerfile)
 	}
 	}
 }
 }
 
 
-func TestTestData(t *testing.T) {
+func TestParseCases(t *testing.T) {
 	for _, dir := range getDirs(t, testDir) {
 	for _, dir := range getDirs(t, testDir) {
 		dockerfile := filepath.Join(testDir, dir, "Dockerfile")
 		dockerfile := filepath.Join(testDir, dir, "Dockerfile")
 		resultfile := filepath.Join(testDir, dir, "result")
 		resultfile := filepath.Join(testDir, dir, "result")
 
 
 		df, err := os.Open(dockerfile)
 		df, err := os.Open(dockerfile)
-		require.NoError(t, err)
+		require.NoError(t, err, dockerfile)
 		defer df.Close()
 		defer df.Close()
 
 
 		result, err := Parse(df)
 		result, err := Parse(df)
-		require.NoError(t, err)
+		require.NoError(t, err, dockerfile)
 
 
 		content, err := ioutil.ReadFile(resultfile)
 		content, err := ioutil.ReadFile(resultfile)
-		require.NoError(t, err)
+		require.NoError(t, err, resultfile)
 
 
 		if runtime.GOOS == "windows" {
 		if runtime.GOOS == "windows" {
 			// CRLF --> CR to match Unix behavior
 			// CRLF --> CR to match Unix behavior
 			content = bytes.Replace(content, []byte{'\x0d', '\x0a'}, []byte{'\x0a'}, -1)
 			content = bytes.Replace(content, []byte{'\x0d', '\x0a'}, []byte{'\x0a'}, -1)
 		}
 		}
-
-		assert.Contains(t, result.AST.Dump()+"\n", string(content), "In "+dockerfile)
+		assert.Equal(t, result.AST.Dump()+"\n", string(content), "In "+dockerfile)
 	}
 	}
 }
 }
 
 
@@ -106,7 +105,7 @@ func TestParseWords(t *testing.T) {
 	}
 	}
 }
 }
 
 
-func TestLineInformation(t *testing.T) {
+func TestParseIncludesLineNumbers(t *testing.T) {
 	df, err := os.Open(testFileLineInfo)
 	df, err := os.Open(testFileLineInfo)
 	require.NoError(t, err)
 	require.NoError(t, err)
 	defer df.Close()
 	defer df.Close()
@@ -115,10 +114,8 @@ func TestLineInformation(t *testing.T) {
 	require.NoError(t, err)
 	require.NoError(t, err)
 
 
 	ast := result.AST
 	ast := result.AST
-	if ast.StartLine != 5 || ast.endLine != 31 {
-		fmt.Fprintf(os.Stderr, "Wrong root line information: expected(%d-%d), actual(%d-%d)\n", 5, 31, ast.StartLine, ast.endLine)
-		t.Fatal("Root line information doesn't match result.")
-	}
+	assert.Equal(t, 5, ast.StartLine)
+	assert.Equal(t, 31, ast.endLine)
 	assert.Len(t, ast.Children, 3)
 	assert.Len(t, ast.Children, 3)
 	expected := [][]int{
 	expected := [][]int{
 		{5, 5},
 		{5, 5},
@@ -126,10 +123,32 @@ func TestLineInformation(t *testing.T) {
 		{17, 31},
 		{17, 31},
 	}
 	}
 	for i, child := range ast.Children {
 	for i, child := range ast.Children {
-		if child.StartLine != expected[i][0] || child.endLine != expected[i][1] {
-			t.Logf("Wrong line information for child %d: expected(%d-%d), actual(%d-%d)\n",
-				i, expected[i][0], expected[i][1], child.StartLine, child.endLine)
-			t.Fatal("Root line information doesn't match result.")
-		}
+		msg := fmt.Sprintf("Child %d", i)
+		assert.Equal(t, expected[i], []int{child.StartLine, child.endLine}, msg)
 	}
 	}
 }
 }
+
+func TestParseWarnsOnEmptyContinutationLine(t *testing.T) {
+	dockerfile := bytes.NewBufferString(`
+FROM alpine:3.6
+
+RUN something \
+
+    following \
+
+    more
+
+RUN another \
+
+    thing
+	`)
+
+	result, err := Parse(dockerfile)
+	require.NoError(t, err)
+	warnings := result.Warnings
+	assert.Len(t, warnings, 3)
+	assert.Contains(t, warnings[0], "Empty continuation line found in")
+	assert.Contains(t, warnings[0], "RUN something     following     more")
+	assert.Contains(t, warnings[1], "RUN another     thing")
+	assert.Contains(t, warnings[2], "will become errors in a future release")
+}

+ 5 - 9
builder/remotecontext/detect.go

@@ -110,17 +110,13 @@ func newURLRemote(url string, dockerfilePath string, progressReader func(in io.R
 			return progressReader(rc), nil
 			return progressReader(rc), nil
 		},
 		},
 	})
 	})
-	if err != nil {
-		if err == dockerfileFoundErr {
-			res, err := parser.Parse(dockerfile)
-			if err != nil {
-				return nil, nil, err
-			}
-			return nil, res, nil
-		}
+	switch {
+	case err == dockerfileFoundErr:
+		res, err := parser.Parse(dockerfile)
+		return nil, res, err
+	case err != nil:
 		return nil, nil, err
 		return nil, nil, err
 	}
 	}
-
 	return withDockerfileFromContext(c.(modifiableContext), dockerfilePath)
 	return withDockerfileFromContext(c.(modifiableContext), dockerfilePath)
 }
 }