podman

Форк
0
121 строка · 3.3 Кб
1
// Copyright 2014 go-dockerclient authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4

5
package docker
6

7
import (
8
	"fmt"
9
	"io"
10
	"os"
11
	"path"
12
	"path/filepath"
13
	"strings"
14

15
	"github.com/docker/docker/pkg/archive"
16
	"github.com/moby/patternmatcher"
17
)
18

19
func createTarStream(srcPath, dockerfilePath string) (io.ReadCloser, error) {
20
	srcPath, err := filepath.Abs(srcPath)
21
	if err != nil {
22
		return nil, err
23
	}
24

25
	excludes, err := parseDockerignore(srcPath)
26
	if err != nil {
27
		return nil, err
28
	}
29

30
	includes := []string{"."}
31

32
	// If .dockerignore mentions .dockerignore or the Dockerfile
33
	// then make sure we send both files over to the daemon
34
	// because Dockerfile is, obviously, needed no matter what, and
35
	// .dockerignore is needed to know if either one needs to be
36
	// removed.  The deamon will remove them for us, if needed, after it
37
	// parses the Dockerfile.
38
	//
39
	// https://github.com/docker/docker/issues/8330
40
	//
41
	forceIncludeFiles := []string{".dockerignore", dockerfilePath}
42

43
	for _, includeFile := range forceIncludeFiles {
44
		if includeFile == "" {
45
			continue
46
		}
47
		keepThem, err := patternmatcher.Matches(includeFile, excludes)
48
		if err != nil {
49
			return nil, fmt.Errorf("cannot match .dockerfileignore: '%s', error: %w", includeFile, err)
50
		}
51
		if keepThem {
52
			includes = append(includes, includeFile)
53
		}
54
	}
55

56
	if err := validateContextDirectory(srcPath, excludes); err != nil {
57
		return nil, err
58
	}
59
	tarOpts := &archive.TarOptions{
60
		ExcludePatterns: excludes,
61
		IncludeFiles:    includes,
62
		Compression:     archive.Uncompressed,
63
		NoLchown:        true,
64
	}
65
	return archive.TarWithOptions(srcPath, tarOpts)
66
}
67

68
// validateContextDirectory checks if all the contents of the directory
69
// can be read and returns an error if some files can't be read.
70
// Symlinks which point to non-existing files don't trigger an error
71
func validateContextDirectory(srcPath string, excludes []string) error {
72
	return filepath.Walk(filepath.Join(srcPath, "."), func(filePath string, f os.FileInfo, err error) error {
73
		// skip this directory/file if it's not in the path, it won't get added to the context
74
		if relFilePath, relErr := filepath.Rel(srcPath, filePath); relErr != nil {
75
			return relErr
76
		} else if skip, matchErr := patternmatcher.Matches(relFilePath, excludes); matchErr != nil {
77
			return matchErr
78
		} else if skip {
79
			if f.IsDir() {
80
				return filepath.SkipDir
81
			}
82
			return nil
83
		}
84

85
		if err != nil {
86
			if os.IsPermission(err) {
87
				return fmt.Errorf("cannot stat %q: %w", filePath, err)
88
			}
89
			if os.IsNotExist(err) {
90
				return nil
91
			}
92
			return err
93
		}
94

95
		// skip checking if symlinks point to non-existing files, such symlinks can be useful
96
		// also skip named pipes, because they hanging on open
97
		if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 {
98
			return nil
99
		}
100

101
		if !f.IsDir() {
102
			currentFile, err := os.Open(filePath)
103
			if err != nil {
104
				return fmt.Errorf("cannot open %q for reading: %w", filePath, err)
105
			}
106
			currentFile.Close()
107
		}
108
		return nil
109
	})
110
}
111

112
func parseDockerignore(root string) ([]string, error) {
113
	var excludes []string
114
	ignore, err := os.ReadFile(path.Join(root, ".dockerignore"))
115
	if err != nil && !os.IsNotExist(err) {
116
		return excludes, fmt.Errorf("error reading .dockerignore: %w", err)
117
	}
118
	excludes = strings.Split(string(ignore), "\n")
119

120
	return excludes, nil
121
}
122

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.