From 39efa46b244cd8f40f3cdc401018abf3baec2e06 Mon Sep 17 00:00:00 2001 From: Tibor Vass Date: Mon, 14 Dec 2015 11:15:00 +0100 Subject: [PATCH 01/19] utils: move dockerignore function to builder/dockerignore Signed-off-by: Tibor Vass --- ignorefile/ignorefile.go | 34 ++++++++++++++++++++++ ignorefile/ignorefile_test.go | 55 +++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 ignorefile/ignorefile.go create mode 100644 ignorefile/ignorefile_test.go diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go new file mode 100644 index 0000000..8170f1e --- /dev/null +++ b/ignorefile/ignorefile.go @@ -0,0 +1,34 @@ +package dockerignore + +import ( + "bufio" + "fmt" + "io" + "path/filepath" + "strings" +) + +// ReadAll reads a .dockerignore file and returns the list of file patterns +// to ignore. Note this will trim whitespace from each line as well +// as use GO's "clean" func to get the shortest/cleanest path for each. +func ReadAll(reader io.ReadCloser) ([]string, error) { + if reader == nil { + return nil, nil + } + defer reader.Close() + scanner := bufio.NewScanner(reader) + var excludes []string + + for scanner.Scan() { + pattern := strings.TrimSpace(scanner.Text()) + if pattern == "" { + continue + } + pattern = filepath.Clean(pattern) + excludes = append(excludes, pattern) + } + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("Error reading .dockerignore: %v", err) + } + return excludes, nil +} diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go new file mode 100644 index 0000000..361b041 --- /dev/null +++ b/ignorefile/ignorefile_test.go @@ -0,0 +1,55 @@ +package dockerignore + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +func TestReadAll(t *testing.T) { + tmpDir, err := ioutil.TempDir("", "dockerignore-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + di, err := ReadAll(nil) + if err != nil { + t.Fatalf("Expected not to have error, got %v", err) + } + + if diLen := len(di); diLen != 0 { + t.Fatalf("Expected to have zero dockerignore entry, got %d", diLen) + } + + diName := filepath.Join(tmpDir, ".dockerignore") + content := fmt.Sprintf("test1\n/test2\n/a/file/here\n\nlastfile") + err = ioutil.WriteFile(diName, []byte(content), 0777) + if err != nil { + t.Fatal(err) + } + + diFd, err := os.Open(diName) + if err != nil { + t.Fatal(err) + } + di, err = ReadAll(diFd) + if err != nil { + t.Fatal(err) + } + + if di[0] != "test1" { + t.Fatalf("First element is not test1") + } + if di[1] != "/test2" { + t.Fatalf("Second element is not /test2") + } + if di[2] != "/a/file/here" { + t.Fatalf("Third element is not /a/file/here") + } + if di[3] != "lastfile" { + t.Fatalf("Fourth element is not lastfile") + } +} From 9d31dee8921164a8719c8a24106d66cea91d1048 Mon Sep 17 00:00:00 2001 From: Anusha Ragunathan Date: Thu, 4 Feb 2016 13:52:31 -0800 Subject: [PATCH 02/19] Fix ReadAll to run on Windows. filepath.Clean converts filenames to filenames with native path separators. Use ToSlash to normalize. Signed-off-by: Anusha Ragunathan --- ignorefile/ignorefile.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index 8170f1e..1fed319 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -25,6 +25,7 @@ func ReadAll(reader io.ReadCloser) ([]string, error) { continue } pattern = filepath.Clean(pattern) + pattern = filepath.ToSlash(pattern) excludes = append(excludes, pattern) } if err := scanner.Err(); err != nil { From 3afd61410b813498e26f7df4272b08c35a1a5766 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Wed, 1 Jun 2016 15:20:54 -0700 Subject: [PATCH 03/19] Add support for comment in .dockerignore This fix tries to address the issue raised in #20083 where comment is not supported in `.dockerignore`. This fix updated the processing of `.dockerignore` so that any lines starting with `#` are ignored, which is similiar to the behavior of `.gitignore`. Related documentation has been updated. Additional tests have been added to cover the changes. This fix fixes #20083. Signed-off-by: Yong Tang --- ignorefile/ignorefile.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index 1fed319..4e09b05 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -20,7 +20,12 @@ func ReadAll(reader io.ReadCloser) ([]string, error) { var excludes []string for scanner.Scan() { - pattern := strings.TrimSpace(scanner.Text()) + // Lines starting with # (comments) are ignored before processing + pattern := scanner.Text() + if strings.HasPrefix(pattern, "#") { + continue + } + pattern = strings.TrimSpace(pattern) if pattern == "" { continue } From b933817323435935a4f8d79423342a3f3edbde54 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Fri, 3 Jun 2016 07:26:36 -0700 Subject: [PATCH 04/19] Skip UTF-8 BOM bytes from Dockerignore if exist This fix tries to address issues related to #23221 where Dockerignore may consists of UTF-8 BOM. This likely happens when Notepad tries to save a file as UTF-8 in Windows. This fix skips the UTF-8 BOM bytes from the beginning of the Dockerignore if exists. Additional tests has been added to cover the changes in this fix. This fix is related to #23221 (UTF-8 BOM in Dockerfile). Signed-off-by: Yong Tang --- ignorefile/ignorefile.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index 4e09b05..9ddf5dd 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -2,6 +2,7 @@ package dockerignore import ( "bufio" + "bytes" "fmt" "io" "path/filepath" @@ -18,10 +19,18 @@ func ReadAll(reader io.ReadCloser) ([]string, error) { defer reader.Close() scanner := bufio.NewScanner(reader) var excludes []string + currentLine := 0 + utf8bom := []byte{0xEF, 0xBB, 0xBF} for scanner.Scan() { + scannedBytes := scanner.Bytes() + // We trim UTF8 BOM + if currentLine == 0 { + scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom) + } + pattern := string(scannedBytes) + currentLine++ // Lines starting with # (comments) are ignored before processing - pattern := scanner.Text() if strings.HasPrefix(pattern, "#") { continue } From f8efb83802b9bf2546c52918fcc9134be177a2ef Mon Sep 17 00:00:00 2001 From: allencloud Date: Sat, 25 Jun 2016 11:57:21 +0800 Subject: [PATCH 05/19] add defer file.Close to avoid potential fd leak Signed-off-by: allencloud --- ignorefile/ignorefile.go | 4 ++-- ignorefile/ignorefile_test.go | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index 9ddf5dd..2db67be 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -12,11 +12,11 @@ import ( // ReadAll reads a .dockerignore file and returns the list of file patterns // to ignore. Note this will trim whitespace from each line as well // as use GO's "clean" func to get the shortest/cleanest path for each. -func ReadAll(reader io.ReadCloser) ([]string, error) { +func ReadAll(reader io.Reader) ([]string, error) { if reader == nil { return nil, nil } - defer reader.Close() + scanner := bufio.NewScanner(reader) var excludes []string currentLine := 0 diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index 361b041..612a139 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -35,6 +35,8 @@ func TestReadAll(t *testing.T) { if err != nil { t.Fatal(err) } + defer diFd.Close() + di, err = ReadAll(diFd) if err != nil { t.Fatal(err) From e7ecef90319e6ba8e9eab400bc6a240f59b56257 Mon Sep 17 00:00:00 2001 From: fate-grand-order Date: Tue, 21 Feb 2017 16:53:29 +0800 Subject: [PATCH 06/19] use t.Fatal() to output the err message where the values used for formatting text does not appear to contain a placeholder Signed-off-by: Helen Xie --- ignorefile/ignorefile_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index 612a139..948f9d8 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -43,15 +43,15 @@ func TestReadAll(t *testing.T) { } if di[0] != "test1" { - t.Fatalf("First element is not test1") + t.Fatal("First element is not test1") } if di[1] != "/test2" { - t.Fatalf("Second element is not /test2") + t.Fatal("Second element is not /test2") } if di[2] != "/a/file/here" { - t.Fatalf("Third element is not /a/file/here") + t.Fatal("Third element is not /a/file/here") } if di[3] != "lastfile" { - t.Fatalf("Fourth element is not lastfile") + t.Fatal("Fourth element is not lastfile") } } From 1a7cb46e5f788415ef71f77b8827a1f07685ac5f Mon Sep 17 00:00:00 2001 From: Simon Ferquel Date: Fri, 24 Mar 2017 15:39:47 +0100 Subject: [PATCH 07/19] Fix behavior of absolute paths in .dockerignore According to documentation (https://docs.docker.com/engine/reference/builder/#dockerignore-file), absolute paths like `/foo/bar` should have the same effect as `foo/bar`. This is not the case today. This fix normalize paths when reading the .dockerignore file by removing leading slashes. Signed-off-by: Simon Ferquel --- ignorefile/ignorefile.go | 19 +++++++++++++++++-- ignorefile/ignorefile_test.go | 22 +++++++++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index 2db67be..cc22381 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -38,8 +38,23 @@ func ReadAll(reader io.Reader) ([]string, error) { if pattern == "" { continue } - pattern = filepath.Clean(pattern) - pattern = filepath.ToSlash(pattern) + // normalize absolute paths to paths relative to the context + // (taking care of '!' prefix) + invert := pattern[0] == '!' + if invert { + pattern = strings.TrimSpace(pattern[1:]) + } + if len(pattern) > 0 { + pattern = filepath.Clean(pattern) + pattern = filepath.ToSlash(pattern) + if len(pattern) > 1 && pattern[0] == '/' { + pattern = pattern[1:] + } + } + if invert { + pattern = "!" + pattern + } + excludes = append(excludes, pattern) } if err := scanner.Err(); err != nil { diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index 948f9d8..bda3874 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -25,7 +25,7 @@ func TestReadAll(t *testing.T) { } diName := filepath.Join(tmpDir, ".dockerignore") - content := fmt.Sprintf("test1\n/test2\n/a/file/here\n\nlastfile") + content := fmt.Sprintf("test1\n/test2\n/a/file/here\n\nlastfile\n# this is a comment\n! /inverted/abs/path\n!\n! \n") err = ioutil.WriteFile(diName, []byte(content), 0777) if err != nil { t.Fatal(err) @@ -42,16 +42,28 @@ func TestReadAll(t *testing.T) { t.Fatal(err) } + if len(di) != 7 { + t.Fatalf("Expected 5 entries, got %v", len(di)) + } if di[0] != "test1" { t.Fatal("First element is not test1") } - if di[1] != "/test2" { - t.Fatal("Second element is not /test2") + if di[1] != "test2" { // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar + t.Fatal("Second element is not test2") } - if di[2] != "/a/file/here" { - t.Fatal("Third element is not /a/file/here") + if di[2] != "a/file/here" { // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar + t.Fatal("Third element is not a/file/here") } if di[3] != "lastfile" { t.Fatal("Fourth element is not lastfile") } + if di[4] != "!inverted/abs/path" { + t.Fatal("Fifth element is not !inverted/abs/path") + } + if di[5] != "!" { + t.Fatalf("Sixth element is not !, but %s", di[5]) + } + if di[6] != "!" { + t.Fatalf("Sixth element is not !, but %s", di[6]) + } } From 1302228707d71d1d7674e582aee04c2292d283ec Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 17 Apr 2017 17:34:02 -0400 Subject: [PATCH 08/19] init Signed-off-by: Daniel Nephin From 572f5de9346e13e81cd550506d1906880c2e85f6 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Mon, 5 Feb 2018 16:05:59 -0500 Subject: [PATCH 09/19] Add canonical import comment Signed-off-by: Daniel Nephin --- ignorefile/ignorefile.go | 2 +- ignorefile/ignorefile_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index cc22381..57f224a 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -1,4 +1,4 @@ -package dockerignore +package dockerignore // import "github.com/docker/docker/builder/dockerignore" import ( "bufio" diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index bda3874..06186cc 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -1,4 +1,4 @@ -package dockerignore +package dockerignore // import "github.com/docker/docker/builder/dockerignore" import ( "fmt" From cb601c5effa49f010daf648282e9caa59e3b056c Mon Sep 17 00:00:00 2001 From: wingkwong Date: Mon, 10 Feb 2020 20:59:04 +0800 Subject: [PATCH 10/19] Fix typos Signed-off-by: wingkwong --- ignorefile/ignorefile_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index 06186cc..655bd6f 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -43,7 +43,7 @@ func TestReadAll(t *testing.T) { } if len(di) != 7 { - t.Fatalf("Expected 5 entries, got %v", len(di)) + t.Fatalf("Expected 7 entries, got %v", len(di)) } if di[0] != "test1" { t.Fatal("First element is not test1") @@ -64,6 +64,6 @@ func TestReadAll(t *testing.T) { t.Fatalf("Sixth element is not !, but %s", di[5]) } if di[6] != "!" { - t.Fatalf("Sixth element is not !, but %s", di[6]) + t.Fatalf("Seventh element is not !, but %s", di[6]) } } From 3ae2925211aff2d7b0db1b0cbe4b14280fa80aac Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 30 Oct 2020 11:52:59 +0100 Subject: [PATCH 11/19] dockerignore: remove import path enforcement comments Signed-off-by: Sebastiaan van Stijn --- ignorefile/ignorefile.go | 2 +- ignorefile/ignorefile_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index 57f224a..cc22381 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -1,4 +1,4 @@ -package dockerignore // import "github.com/docker/docker/builder/dockerignore" +package dockerignore import ( "bufio" diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index 655bd6f..4082436 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -1,4 +1,4 @@ -package dockerignore // import "github.com/docker/docker/builder/dockerignore" +package dockerignore import ( "fmt" From 5de040449c7cebd8c4ff73ed1906fe0d6629a915 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 10 Mar 2022 00:57:07 +0100 Subject: [PATCH 12/19] Remove uses of deprecated io/ioutil Signed-off-by: Sebastiaan van Stijn --- ignorefile/ignorefile_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index 4082436..7327c26 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -2,14 +2,13 @@ package dockerignore import ( "fmt" - "io/ioutil" "os" "path/filepath" "testing" ) func TestReadAll(t *testing.T) { - tmpDir, err := ioutil.TempDir("", "dockerignore-test") + tmpDir, err := os.MkdirTemp("", "dockerignore-test") if err != nil { t.Fatal(err) } @@ -26,7 +25,7 @@ func TestReadAll(t *testing.T) { diName := filepath.Join(tmpDir, ".dockerignore") content := fmt.Sprintf("test1\n/test2\n/a/file/here\n\nlastfile\n# this is a comment\n! /inverted/abs/path\n!\n! \n") - err = ioutil.WriteFile(diName, []byte(content), 0777) + err = os.WriteFile(diName, []byte(content), 0777) if err != nil { t.Fatal(err) } From 5ab4be0a66f5fd1d57a8b981d28433f2937d5842 Mon Sep 17 00:00:00 2001 From: David Gageot Date: Sat, 23 Apr 2022 23:44:56 +0200 Subject: [PATCH 13/19] Enable gosimple linter Signed-off-by: David Gageot --- ignorefile/ignorefile_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index 7327c26..b12810c 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -1,7 +1,6 @@ package dockerignore import ( - "fmt" "os" "path/filepath" "testing" @@ -24,7 +23,7 @@ func TestReadAll(t *testing.T) { } diName := filepath.Join(tmpDir, ".dockerignore") - content := fmt.Sprintf("test1\n/test2\n/a/file/here\n\nlastfile\n# this is a comment\n! /inverted/abs/path\n!\n! \n") + content := "test1\n/test2\n/a/file/here\n\nlastfile\n# this is a comment\n! /inverted/abs/path\n!\n! \n" err = os.WriteFile(diName, []byte(content), 0777) if err != nil { t.Fatal(err) From 0439ad433d9bb78705ee6905a59646980666264b Mon Sep 17 00:00:00 2001 From: Eng Zer Jun Date: Sun, 24 Jul 2022 02:27:26 +0800 Subject: [PATCH 14/19] test: use `T.TempDir` to create temporary test directory This commit replaces `os.MkdirTemp` with `t.TempDir` in tests. The directory created by `t.TempDir` is automatically removed when the test and all its subtests complete. Prior to this commit, temporary directory created using `os.MkdirTemp` needs to be removed manually by calling `os.RemoveAll`, which is omitted in some tests. The error handling boilerplate e.g. defer func() { if err := os.RemoveAll(dir); err != nil { t.Fatal(err) } } is also tedious, but `t.TempDir` handles this for us nicely. Reference: https://pkg.go.dev/testing#T.TempDir Signed-off-by: Eng Zer Jun --- ignorefile/ignorefile_test.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index b12810c..28f0cd7 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -7,12 +7,6 @@ import ( ) func TestReadAll(t *testing.T) { - tmpDir, err := os.MkdirTemp("", "dockerignore-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - di, err := ReadAll(nil) if err != nil { t.Fatalf("Expected not to have error, got %v", err) @@ -22,7 +16,7 @@ func TestReadAll(t *testing.T) { t.Fatalf("Expected to have zero dockerignore entry, got %d", diLen) } - diName := filepath.Join(tmpDir, ".dockerignore") + diName := filepath.Join(t.TempDir(), ".dockerignore") content := "test1\n/test2\n/a/file/here\n\nlastfile\n# this is a comment\n! /inverted/abs/path\n!\n! \n" err = os.WriteFile(diName, []byte(content), 0777) if err != nil { From 80d9cee09de9006a8693f144da95d94aad89dca1 Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Tue, 25 Oct 2022 12:28:19 +0100 Subject: [PATCH 15/19] chore: fixup test magic numbers Required for gosec Signed-off-by: Justin Chadwell --- ignorefile/ignorefile_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index 28f0cd7..c3cd078 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -18,7 +18,7 @@ func TestReadAll(t *testing.T) { diName := filepath.Join(t.TempDir(), ".dockerignore") content := "test1\n/test2\n/a/file/here\n\nlastfile\n# this is a comment\n! /inverted/abs/path\n!\n! \n" - err = os.WriteFile(diName, []byte(content), 0777) + err = os.WriteFile(diName, []byte(content), 0600) if err != nil { t.Fatal(err) } From 00aab4f6f863931189dd1d85ccc0f22d4e6ce8c8 Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Wed, 23 Nov 2022 11:05:28 +0000 Subject: [PATCH 16/19] chore: refactor dockerfile to use errors pkg Signed-off-by: Justin Chadwell --- ignorefile/ignorefile.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index cc22381..e7f29ae 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -3,10 +3,11 @@ package dockerignore import ( "bufio" "bytes" - "fmt" "io" "path/filepath" "strings" + + "github.com/pkg/errors" ) // ReadAll reads a .dockerignore file and returns the list of file patterns @@ -58,7 +59,7 @@ func ReadAll(reader io.Reader) ([]string, error) { excludes = append(excludes, pattern) } if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("Error reading .dockerignore: %v", err) + return nil, errors.Wrap(err, "error reading .dockerignore") } return excludes, nil } From 318a4a5baad77d63a2309d4d88be4d2a4eed070a Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 25 Jul 2023 10:03:39 +0200 Subject: [PATCH 17/19] frontend/dockerfile/dockerignore: cleanup unit test - don't use a temp-file for the test as all we need is a reader - use a const and string-literal for the test-content, which makes it slightly more readable - don't use hard-coded tests for each line, but use an "expected" slice - don't fail early if line-numbers don't match Signed-off-by: Sebastiaan van Stijn --- ignorefile/ignorefile_test.go | 77 ++++++++++++++++------------------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/ignorefile/ignorefile_test.go b/ignorefile/ignorefile_test.go index c3cd078..86176fd 100644 --- a/ignorefile/ignorefile_test.go +++ b/ignorefile/ignorefile_test.go @@ -1,61 +1,54 @@ package dockerignore import ( - "os" - "path/filepath" + "strings" "testing" ) func TestReadAll(t *testing.T) { - di, err := ReadAll(nil) + actual, err := ReadAll(nil) if err != nil { - t.Fatalf("Expected not to have error, got %v", err) + t.Errorf("Expected no error, got %v", err) } - - if diLen := len(di); diLen != 0 { - t.Fatalf("Expected to have zero dockerignore entry, got %d", diLen) + if entries := len(actual); entries != 0 { + t.Fatalf("Expected to have zero entries, got %d", entries) } - diName := filepath.Join(t.TempDir(), ".dockerignore") - content := "test1\n/test2\n/a/file/here\n\nlastfile\n# this is a comment\n! /inverted/abs/path\n!\n! \n" - err = os.WriteFile(diName, []byte(content), 0600) - if err != nil { - t.Fatal(err) - } + const content = `test1 +/test2 +/a/file/here - diFd, err := os.Open(diName) - if err != nil { - t.Fatal(err) +lastfile +# this is a comment +! /inverted/abs/path +! +! ` + + expected := []string{ + "test1", + "test2", // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar + "a/file/here", // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar + "lastfile", + "!inverted/abs/path", + "!", + "!", } - defer diFd.Close() - di, err = ReadAll(diFd) + actual, err = ReadAll(strings.NewReader(content)) if err != nil { - t.Fatal(err) + t.Error(err) } - if len(di) != 7 { - t.Fatalf("Expected 7 entries, got %v", len(di)) - } - if di[0] != "test1" { - t.Fatal("First element is not test1") - } - if di[1] != "test2" { // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar - t.Fatal("Second element is not test2") - } - if di[2] != "a/file/here" { // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar - t.Fatal("Third element is not a/file/here") - } - if di[3] != "lastfile" { - t.Fatal("Fourth element is not lastfile") - } - if di[4] != "!inverted/abs/path" { - t.Fatal("Fifth element is not !inverted/abs/path") - } - if di[5] != "!" { - t.Fatalf("Sixth element is not !, but %s", di[5]) - } - if di[6] != "!" { - t.Fatalf("Seventh element is not !, but %s", di[6]) + if len(actual) != len(expected) { + t.Errorf("Expected %d entries, got %v", len(expected), len(actual)) + } + for i, expectedLine := range expected { + if i >= len(actual) { + t.Errorf(`missing line %d: expected: "%s", got none`, i+1, expectedLine) + continue + } + if actual[i] != expectedLine { + t.Errorf(`line %d: expected: "%s", got: "%s"`, i+1, expectedLine, actual[i]) + } } } From dba575fa3811a493cf6838b5f78f040fff273cbc Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 25 Jul 2023 10:26:14 +0200 Subject: [PATCH 18/19] frontend/dockerfile/dockerignore: touch-up godoc and code Use "doc links" where possible, and better describe the function. Signed-off-by: Sebastiaan van Stijn --- ignorefile/ignorefile.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index e7f29ae..c4406c4 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -10,19 +10,29 @@ import ( "github.com/pkg/errors" ) -// ReadAll reads a .dockerignore file and returns the list of file patterns -// to ignore. Note this will trim whitespace from each line as well -// as use GO's "clean" func to get the shortest/cleanest path for each. +// ReadAll reads an ignore file from a reader and returns the list of file +// patterns to ignore, applying the following rules: +// +// - An UTF8 BOM header (if present) is stripped. +// - Lines starting with "#" are considered comments and are skipped. +// +// For remaining lines: +// +// - Leading and trailing whitespace is removed from each ignore pattern. +// - It uses [filepath.Clean] to get the shortest/cleanest path for +// ignore patterns. +// - Leading forward-slashes ("/") are removed from ignore patterns, +// so "/some/path" and "some/path" are considered equivalent. func ReadAll(reader io.Reader) ([]string, error) { if reader == nil { return nil, nil } - scanner := bufio.NewScanner(reader) var excludes []string currentLine := 0 - utf8bom := []byte{0xEF, 0xBB, 0xBF} + + scanner := bufio.NewScanner(reader) for scanner.Scan() { scannedBytes := scanner.Bytes() // We trim UTF8 BOM From 666020cb4be259d130ec76420d5d74fa94adcf67 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 25 Jul 2023 10:32:19 +0200 Subject: [PATCH 19/19] frontend/dockerfile/dockerignore: remove hard-coded filename from error While this function would usually be used for read a `.dockerignore` file, it accepts a Reader and can also be used to handle ignore patterns from other files (e.g. `Dockerfile.dockerignore`) or other sources. The error was also wrapped multiple times in some code-paths, which could lead to an error being formatted as: failed to parse dockerignore: error reading .dockerignore: Let's remove mention of the `.dockerignore` filename from the error, and leave it to the caller to include the filename. This patch also brings the MainContext dockerignore error inline with the NamedContext dockerignore error, now printing the exact name of the file. Co-authored-by: Justin Chadwell Signed-off-by: Sebastiaan van Stijn --- ignorefile/ignorefile.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ignorefile/ignorefile.go b/ignorefile/ignorefile.go index c4406c4..2bd9f1c 100644 --- a/ignorefile/ignorefile.go +++ b/ignorefile/ignorefile.go @@ -6,8 +6,6 @@ import ( "io" "path/filepath" "strings" - - "github.com/pkg/errors" ) // ReadAll reads an ignore file from a reader and returns the list of file @@ -69,7 +67,7 @@ func ReadAll(reader io.Reader) ([]string, error) { excludes = append(excludes, pattern) } if err := scanner.Err(); err != nil { - return nil, errors.Wrap(err, "error reading .dockerignore") + return nil, err } return excludes, nil }