Skip to content

Commit 347bb8d

Browse files
authored
Merge pull request #1 from thaJeztah/integrate_dockerignore
integrate frontend/dockerfile/dockerignore from BuildKit
2 parents 8a1649d + 36a4227 commit 347bb8d

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

ignorefile/ignorefile.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package ignorefile
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"io"
7+
"path/filepath"
8+
"strings"
9+
)
10+
11+
// ReadAll reads an ignore file from a reader and returns the list of file
12+
// patterns to ignore, applying the following rules:
13+
//
14+
// - An UTF8 BOM header (if present) is stripped.
15+
// - Lines starting with "#" are considered comments and are skipped.
16+
//
17+
// For remaining lines:
18+
//
19+
// - Leading and trailing whitespace is removed from each ignore pattern.
20+
// - It uses [filepath.Clean] to get the shortest/cleanest path for
21+
// ignore patterns.
22+
// - Leading forward-slashes ("/") are removed from ignore patterns,
23+
// so "/some/path" and "some/path" are considered equivalent.
24+
func ReadAll(reader io.Reader) ([]string, error) {
25+
if reader == nil {
26+
return nil, nil
27+
}
28+
29+
var excludes []string
30+
currentLine := 0
31+
utf8bom := []byte{0xEF, 0xBB, 0xBF}
32+
33+
scanner := bufio.NewScanner(reader)
34+
for scanner.Scan() {
35+
scannedBytes := scanner.Bytes()
36+
// We trim UTF8 BOM
37+
if currentLine == 0 {
38+
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
39+
}
40+
pattern := string(scannedBytes)
41+
currentLine++
42+
// Lines starting with # (comments) are ignored before processing
43+
if strings.HasPrefix(pattern, "#") {
44+
continue
45+
}
46+
pattern = strings.TrimSpace(pattern)
47+
if pattern == "" {
48+
continue
49+
}
50+
// normalize absolute paths to paths relative to the context
51+
// (taking care of '!' prefix)
52+
invert := pattern[0] == '!'
53+
if invert {
54+
pattern = strings.TrimSpace(pattern[1:])
55+
}
56+
if len(pattern) > 0 {
57+
pattern = filepath.Clean(pattern)
58+
pattern = filepath.ToSlash(pattern)
59+
if len(pattern) > 1 && pattern[0] == '/' {
60+
pattern = pattern[1:]
61+
}
62+
}
63+
if invert {
64+
pattern = "!" + pattern
65+
}
66+
67+
excludes = append(excludes, pattern)
68+
}
69+
if err := scanner.Err(); err != nil {
70+
return nil, err
71+
}
72+
return excludes, nil
73+
}

ignorefile/ignorefile_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package ignorefile
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
func TestReadAll(t *testing.T) {
9+
actual, err := ReadAll(nil)
10+
if err != nil {
11+
t.Errorf("Expected no error, got %v", err)
12+
}
13+
if entries := len(actual); entries != 0 {
14+
t.Fatalf("Expected to have zero entries, got %d", entries)
15+
}
16+
17+
const content = `test1
18+
/test2
19+
/a/file/here
20+
21+
lastfile
22+
# this is a comment
23+
! /inverted/abs/path
24+
!
25+
! `
26+
27+
expected := []string{
28+
"test1",
29+
"test2", // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar
30+
"a/file/here", // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar
31+
"lastfile",
32+
"!inverted/abs/path",
33+
"!",
34+
"!",
35+
}
36+
37+
actual, err = ReadAll(strings.NewReader(content))
38+
if err != nil {
39+
t.Error(err)
40+
}
41+
42+
if len(actual) != len(expected) {
43+
t.Errorf("Expected %d entries, got %v", len(expected), len(actual))
44+
}
45+
for i, expectedLine := range expected {
46+
if i >= len(actual) {
47+
t.Errorf(`missing line %d: expected: "%s", got none`, i+1, expectedLine)
48+
continue
49+
}
50+
if actual[i] != expectedLine {
51+
t.Errorf(`line %d: expected: "%s", got: "%s"`, i+1, expectedLine, actual[i])
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)