]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/fsouza/go-dockerclient/tar.go
48042cbda05b7f2584d45483da27bb88f7639500
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / fsouza / go-dockerclient / tar.go
1 // Copyright 2015 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 "io/ioutil"
11 "os"
12 "path"
13 "path/filepath"
14 "strings"
15
16 "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/archive"
17 "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/fileutils"
18 )
19
20 func createTarStream(srcPath, dockerfilePath string) (io.ReadCloser, error) {
21 excludes, err := parseDockerignore(srcPath)
22 if err != nil {
23 return nil, err
24 }
25
26 includes := []string{"."}
27
28 // If .dockerignore mentions .dockerignore or the Dockerfile
29 // then make sure we send both files over to the daemon
30 // because Dockerfile is, obviously, needed no matter what, and
31 // .dockerignore is needed to know if either one needs to be
32 // removed. The deamon will remove them for us, if needed, after it
33 // parses the Dockerfile.
34 //
35 // https://github.com/docker/docker/issues/8330
36 //
37 forceIncludeFiles := []string{".dockerignore", dockerfilePath}
38
39 for _, includeFile := range forceIncludeFiles {
40 if includeFile == "" {
41 continue
42 }
43 keepThem, err := fileutils.Matches(includeFile, excludes)
44 if err != nil {
45 return nil, fmt.Errorf("cannot match .dockerfile: '%s', error: %s", includeFile, err)
46 }
47 if keepThem {
48 includes = append(includes, includeFile)
49 }
50 }
51
52 if err := validateContextDirectory(srcPath, excludes); err != nil {
53 return nil, err
54 }
55 tarOpts := &archive.TarOptions{
56 ExcludePatterns: excludes,
57 IncludeFiles: includes,
58 Compression: archive.Uncompressed,
59 NoLchown: true,
60 }
61 return archive.TarWithOptions(srcPath, tarOpts)
62 }
63
64 // validateContextDirectory checks if all the contents of the directory
65 // can be read and returns an error if some files can't be read.
66 // Symlinks which point to non-existing files don't trigger an error
67 func validateContextDirectory(srcPath string, excludes []string) error {
68 return filepath.Walk(filepath.Join(srcPath, "."), func(filePath string, f os.FileInfo, err error) error {
69 // skip this directory/file if it's not in the path, it won't get added to the context
70 if relFilePath, err := filepath.Rel(srcPath, filePath); err != nil {
71 return err
72 } else if skip, err := fileutils.Matches(relFilePath, excludes); err != nil {
73 return err
74 } else if skip {
75 if f.IsDir() {
76 return filepath.SkipDir
77 }
78 return nil
79 }
80
81 if err != nil {
82 if os.IsPermission(err) {
83 return fmt.Errorf("can't stat '%s'", filePath)
84 }
85 if os.IsNotExist(err) {
86 return nil
87 }
88 return err
89 }
90
91 // skip checking if symlinks point to non-existing files, such symlinks can be useful
92 // also skip named pipes, because they hanging on open
93 if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 {
94 return nil
95 }
96
97 if !f.IsDir() {
98 currentFile, err := os.Open(filePath)
99 if err != nil && os.IsPermission(err) {
100 return fmt.Errorf("no permission to read from '%s'", filePath)
101 }
102 currentFile.Close()
103 }
104 return nil
105 })
106 }
107
108 func parseDockerignore(root string) ([]string, error) {
109 var excludes []string
110 ignore, err := ioutil.ReadFile(path.Join(root, ".dockerignore"))
111 if err != nil && !os.IsNotExist(err) {
112 return excludes, fmt.Errorf("error reading .dockerignore: '%s'", err)
113 }
114 excludes = strings.Split(string(ignore), "\n")
115
116 return excludes, nil
117 }