Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
39efa46
utils: move dockerignore function to builder/dockerignore
Dec 14, 2015
9d31dee
Fix ReadAll to run on Windows.
anusha-ragunathan Feb 4, 2016
3afd614
Add support for comment in .dockerignore
yongtang Jun 1, 2016
b933817
Skip UTF-8 BOM bytes from Dockerignore if exist
yongtang Jun 3, 2016
f8efb83
add defer file.Close to avoid potential fd leak
allencloud Jun 25, 2016
e7ecef9
use t.Fatal() to output the err message where the values used for for…
Feb 21, 2017
1a7cb46
Fix behavior of absolute paths in .dockerignore
simonferquel Mar 24, 2017
1302228
init
dnephin Apr 17, 2017
572f5de
Add canonical import comment
dnephin Feb 5, 2018
cb601c5
Fix typos
wingkwong Feb 10, 2020
3ae2925
dockerignore: remove import path enforcement comments
thaJeztah Oct 30, 2020
5de0404
Remove uses of deprecated io/ioutil
thaJeztah Mar 9, 2022
5ab4be0
Enable gosimple linter
Apr 23, 2022
c39e087
Merge pull request #2828 from dgageot/add-gosimple-linter
tonistiigi Apr 27, 2022
f1ba6ac
Merge remote-tracking branch 'cli-dockerfile-ref/master' into dockerf…
crazy-max Jun 8, 2022
0439ad4
test: use `T.TempDir` to create temporary test directory
Juneezee Jul 23, 2022
80d9cee
chore: fixup test magic numbers
jedevc Oct 25, 2022
00aab4f
chore: refactor dockerfile to use errors pkg
jedevc Nov 23, 2022
318a4a5
frontend/dockerfile/dockerignore: cleanup unit test
thaJeztah Jul 25, 2023
dba575f
frontend/dockerfile/dockerignore: touch-up godoc and code
thaJeztah Jul 25, 2023
666020c
frontend/dockerfile/dockerignore: remove hard-coded filename from error
thaJeztah Jul 25, 2023
36a4227
integrate frontend/dockerfile/dockerignore from buildkit
thaJeztah Jul 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions ignorefile/ignorefile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package ignorefile

import (
"bufio"
"bytes"
"io"
"path/filepath"
"strings"
)

// 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
}

var excludes []string
currentLine := 0
utf8bom := []byte{0xEF, 0xBB, 0xBF}

scanner := bufio.NewScanner(reader)
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
if strings.HasPrefix(pattern, "#") {
continue
}
pattern = strings.TrimSpace(pattern)
if pattern == "" {
continue
}
// 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 {
return nil, err
}
return excludes, nil
}
54 changes: 54 additions & 0 deletions ignorefile/ignorefile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package ignorefile

import (
"strings"
"testing"
)

func TestReadAll(t *testing.T) {
actual, err := ReadAll(nil)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if entries := len(actual); entries != 0 {
t.Fatalf("Expected to have zero entries, got %d", entries)
}

const content = `test1
/test2
/a/file/here

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",
"!",
"!",
}

actual, err = ReadAll(strings.NewReader(content))
if err != nil {
t.Error(err)
}

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])
}
}
}