Skip to content

Commit 94fdbe4

Browse files
committed
Improve Docker dependencies code
Fixes GoogleContainerTools#386
1 parent 64b44b3 commit 94fdbe4

File tree

8 files changed

+99
-221
lines changed

8 files changed

+99
-221
lines changed

pkg/skaffold/bazel/bazel.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package bazel
1919
import (
2020
"fmt"
2121
"os/exec"
22-
"path/filepath"
2322
"strings"
2423

2524
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1alpha2"
@@ -52,9 +51,7 @@ func (*BazelDependencyResolver) GetDependencies(a *v1alpha2.Artifact) ([]string,
5251
continue
5352
}
5453

55-
dep := filepath.Join(a.Workspace, depToPath(l))
56-
57-
deps = append(deps, dep)
54+
deps = append(deps, depToPath(l))
5855
}
5956
return deps, nil
6057
}

pkg/skaffold/build/deps.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package build
1818

1919
import (
2020
"fmt"
21+
"path/filepath"
2122
"sort"
2223
"strings"
2324

@@ -119,7 +120,7 @@ func pathsForArtifact(a *v1alpha2.Artifact) ([]string, error) {
119120
logrus.Debugf("Ignoring %s for artifact dependencies", dep)
120121
continue
121122
}
122-
filteredDeps = append(filteredDeps, dep)
123+
filteredDeps = append(filteredDeps, filepath.Join(a.Workspace, dep))
123124
}
124125
return filteredDeps, nil
125126
}

pkg/skaffold/docker/context.go

+2-6
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,8 @@ import (
2525
"github.com/pkg/errors"
2626
)
2727

28-
func contextTarPaths(dockerfilePath string, context string) ([]string, error) {
29-
return GetDockerfileDependencies(dockerfilePath, context)
30-
}
31-
3228
func CreateDockerTarContext(w io.Writer, dockerfilePath, context string) error {
33-
paths, err := contextTarPaths(dockerfilePath, context)
29+
paths, err := GetDockerfileDependencies(dockerfilePath, context)
3430
if err != nil {
3531
return errors.Wrap(err, "getting relative tar paths")
3632
}
@@ -41,7 +37,7 @@ func CreateDockerTarContext(w io.Writer, dockerfilePath, context string) error {
4137
}
4238

4339
func CreateDockerTarGzContext(w io.Writer, dockerfilePath, context string) error {
44-
paths, err := contextTarPaths(dockerfilePath, context)
40+
paths, err := GetDockerfileDependencies(dockerfilePath, context)
4541
if err != nil {
4642
return errors.Wrap(err, "getting relative tar paths")
4743
}

pkg/skaffold/docker/parse.go

+72-60
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,12 @@ import (
2222
"fmt"
2323
"io"
2424
"os"
25-
"path"
2625
"path/filepath"
2726
"sort"
2827
"strings"
2928
"sync"
3029

3130
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/v1alpha2"
32-
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
3331
"github.com/google/go-containerregistry/v1"
3432

3533
"github.com/docker/docker/builder/dockerignore"
@@ -57,11 +55,9 @@ func (d *DockerfileDepResolver) GetDependencies(a *v1alpha2.Artifact) ([]string,
5755
return GetDockerfileDependencies(a.DockerArtifact.DockerfilePath, a.Workspace)
5856
}
5957

60-
// GetDockerfileDependencies parses a dockerfile and returns the full paths
61-
// of all the source files that the resulting docker image depends on.
62-
func GetDockerfileDependencies(dockerfilePath, workspace string) ([]string, error) {
58+
func readDockerfile(workspace, dockerfilePath string) ([]string, error) {
6359
path := filepath.Join(workspace, dockerfilePath)
64-
f, err := util.Fs.Open(path)
60+
f, err := os.Open(path)
6561
if err != nil {
6662
return nil, errors.Wrapf(err, "opening dockerfile: %s", path)
6763
}
@@ -91,7 +87,7 @@ func GetDockerfileDependencies(dockerfilePath, workspace string) ([]string, erro
9187
for _, value := range r.AST.Children {
9288
switch value.Value {
9389
case add, copy:
94-
processCopy(workspace, value, depMap, envs)
90+
processCopy(value, depMap, envs)
9591
case env:
9692
envs[value.Next.Value] = value.Next.Next.Value
9793
}
@@ -109,30 +105,86 @@ func GetDockerfileDependencies(dockerfilePath, workspace string) ([]string, erro
109105

110106
dispatchInstructions(res)
111107

112-
deps := []string{}
108+
var deps []string
113109
for dep := range depMap {
114110
deps = append(deps, dep)
115111
}
116112
logrus.Infof("Found dependencies for dockerfile %s", deps)
117113

118-
expandedDeps, err := util.ExpandPaths(workspace, deps)
114+
return deps, nil
115+
}
116+
117+
func GetDockerfileDependencies(dockerfilePath, workspace string) ([]string, error) {
118+
deps, err := readDockerfile(workspace, dockerfilePath)
119119
if err != nil {
120-
return nil, errors.Wrap(err, "expanding dockerfile paths")
120+
return nil, err
121121
}
122-
logrus.Infof("deps %s", expandedDeps)
123122

124-
if !util.StrSliceContains(expandedDeps, path) {
125-
expandedDeps = append(expandedDeps, path)
123+
// Read patterns to ignore
124+
var excludes []string
125+
dockerignorePath := filepath.Join(workspace, ".dockerignore")
126+
if _, err := os.Stat(dockerignorePath); !os.IsNotExist(err) {
127+
r, err := os.Open(dockerignorePath)
128+
if err != nil {
129+
return nil, err
130+
}
131+
defer r.Close()
132+
133+
excludes, err = dockerignore.ReadAll(r)
134+
if err != nil {
135+
return nil, err
136+
}
137+
}
138+
139+
// Walk the workspace
140+
files := make(map[string]bool)
141+
for _, dep := range deps {
142+
filepath.Walk(filepath.Join(workspace, dep), func(fpath string, info os.FileInfo, err error) error {
143+
if err != nil {
144+
return err
145+
}
146+
147+
relPath, err := filepath.Rel(workspace, fpath)
148+
if err != nil {
149+
return err
150+
}
151+
152+
ignored, err := fileutils.Matches(relPath, excludes)
153+
if err != nil {
154+
return err
155+
}
156+
157+
if info.IsDir() && ignored {
158+
return filepath.SkipDir
159+
}
160+
161+
if !info.IsDir() && !ignored {
162+
files[relPath] = true
163+
}
164+
165+
return nil
166+
})
126167
}
127168

128-
// Look for .dockerignore.
129-
ignorePath := filepath.Join(workspace, ".dockerignore")
130-
filteredDeps, err := ApplyDockerIgnore(expandedDeps, ignorePath)
169+
// Add dockerfile?
170+
m, err := fileutils.Matches(dockerfilePath, excludes)
131171
if err != nil {
132-
return nil, errors.Wrap(err, "applying dockerignore")
172+
return nil, err
173+
}
174+
if !m {
175+
files[dockerfilePath] = true
176+
}
177+
178+
// Ignore .dockerignore
179+
delete(files, ".dockerignore")
180+
181+
var dependencies []string
182+
for file := range files {
183+
dependencies = append(dependencies, file)
133184
}
185+
sort.Strings(dependencies)
134186

135-
return filteredDeps, nil
187+
return dependencies, nil
136188
}
137189

138190
func PortsFromDockerfile(r io.Reader) ([]string, error) {
@@ -242,7 +294,7 @@ func retrieveRemoteConfig(identifier string) (*v1.ConfigFile, error) {
242294
return img.ConfigFile()
243295
}
244296

245-
func processCopy(workspace string, value *parser.Node, paths map[string]struct{}, envs map[string]string) error {
297+
func processCopy(value *parser.Node, paths map[string]struct{}, envs map[string]string) error {
246298
slex := shell.NewLex('\\')
247299
for {
248300
// Skip last node, since it is the destination, and stop if we arrive at a comment
@@ -259,8 +311,7 @@ func processCopy(workspace string, value *parser.Node, paths map[string]struct{}
259311
return nil
260312
}
261313
if !strings.HasPrefix(src, "http://") && !strings.HasPrefix(src, "https://") {
262-
dep := path.Join(workspace, src)
263-
paths[dep] = struct{}{}
314+
paths[src] = struct{}{}
264315
} else {
265316
logrus.Debugf("Skipping watch on remote dependency %s", src)
266317
}
@@ -286,42 +337,3 @@ func hasMultiStageFlag(flags []string) bool {
286337
}
287338
return false
288339
}
289-
290-
func ApplyDockerIgnore(paths []string, dockerIgnorePath string) ([]string, error) {
291-
absPaths, err := util.RelPathToAbsPath(paths)
292-
if err != nil {
293-
return nil, errors.Wrap(err, "getting absolute path of dependencies")
294-
}
295-
excludes := []string{}
296-
if _, err := util.Fs.Stat(dockerIgnorePath); !os.IsNotExist(err) {
297-
r, err := util.Fs.Open(dockerIgnorePath)
298-
if err != nil {
299-
return nil, err
300-
}
301-
defer r.Close()
302-
303-
excludes, err = dockerignore.ReadAll(r)
304-
if err != nil {
305-
return nil, err
306-
}
307-
excludes = append(excludes, ".dockerignore")
308-
}
309-
310-
absPathExcludes, err := util.RelPathToAbsPath(excludes)
311-
if err != nil {
312-
return nil, errors.Wrap(err, "getting absolute path of docker ignored paths")
313-
}
314-
315-
filteredDeps := []string{}
316-
for _, d := range absPaths {
317-
m, err := fileutils.Matches(d, absPathExcludes)
318-
if err != nil {
319-
return nil, err
320-
}
321-
if !m {
322-
filteredDeps = append(filteredDeps, d)
323-
}
324-
}
325-
sort.Strings(filteredDeps)
326-
return filteredDeps, nil
327-
}

pkg/skaffold/docker/parse_test.go

+20-13
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ package docker
1818

1919
import (
2020
"fmt"
21+
"io/ioutil"
22+
"os"
2123
"path/filepath"
2224
"strings"
2325
"testing"
2426

25-
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
2627
"github.com/GoogleContainerTools/skaffold/testutil"
2728

2829
"github.com/google/go-containerregistry/v1"
29-
"github.com/spf13/afero"
3030
)
3131

3232
const copyDockerfile = `
@@ -159,7 +159,7 @@ func TestGetDockerfileDependencies(t *testing.T) {
159159
description: "add dependency",
160160
dockerfile: addDockerfile,
161161
workspace: "docker",
162-
expected: []string{"docker/Dockerfile", "docker/nginx.conf"},
162+
expected: []string{"Dockerfile", "nginx.conf"},
163163
},
164164
{
165165
description: "bad read",
@@ -204,11 +204,18 @@ func TestGetDockerfileDependencies(t *testing.T) {
204204
expected: []string{"Dockerfile", "file", "server.go", "test.conf", "worker.go"},
205205
},
206206
{
207-
description: "dockerignore with context in parent directory test",
207+
description: "dockerignore with non canonical workspace",
208208
dockerfile: contextDockerfile,
209209
workspace: "docker/../docker",
210210
dockerIgnore: true,
211-
expected: []string{},
211+
expected: []string{"Dockerfile", "nginx.conf"},
212+
},
213+
{
214+
description: "dockerignore with context in parent directory",
215+
dockerfile: contextDockerfile,
216+
workspace: "docker/..",
217+
dockerIgnore: true,
218+
expected: []string{"Dockerfile", "file", "server.go", "test.conf", "worker.go"},
212219
},
213220
{
214221
description: "onbuild test",
@@ -231,24 +238,24 @@ func TestGetDockerfileDependencies(t *testing.T) {
231238

232239
for _, test := range tests {
233240
t.Run(test.description, func(t *testing.T) {
234-
defer func(fs afero.Fs) { util.Fs = fs }(util.Fs)
235-
util.Fs = afero.NewMemMapFs()
241+
tmpDir, cleanup := testutil.TempDir(t)
242+
defer cleanup()
236243

237-
util.Fs.MkdirAll("docker", 0750)
244+
os.MkdirAll(filepath.Join(tmpDir, "docker"), 0750)
238245
for _, file := range []string{"docker/nginx.conf", "docker/bar", "server.go", "test.conf", "worker.go", "bar", "file"} {
239-
afero.WriteFile(util.Fs, file, []byte(""), 0644)
246+
ioutil.WriteFile(filepath.Join(tmpDir, file), []byte(""), 0644)
240247
}
241248

249+
workspace := filepath.Join(tmpDir, test.workspace)
242250
if !test.badReader {
243-
afero.WriteFile(util.Fs, filepath.Join(test.workspace, "Dockerfile"), []byte(test.dockerfile), 0644)
251+
ioutil.WriteFile(filepath.Join(workspace, "Dockerfile"), []byte(test.dockerfile), 0644)
244252
}
245253

246254
if test.dockerIgnore {
247-
afero.WriteFile(util.Fs, ".dockerignore", []byte(dockerIgnore), 0644)
248-
afero.WriteFile(util.Fs, filepath.Join("docker", ".dockerignore"), []byte(dockerIgnore), 0644)
255+
ioutil.WriteFile(filepath.Join(workspace, ".dockerignore"), []byte(dockerIgnore), 0644)
249256
}
250257

251-
deps, err := GetDockerfileDependencies("Dockerfile", test.workspace)
258+
deps, err := GetDockerfileDependencies("Dockerfile", workspace)
252259
testutil.CheckErrorAndDeepEqual(t, test.shouldErr, err, test.expected, deps)
253260
})
254261
}

pkg/skaffold/util/tar.go

+2-14
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,10 @@ func CreateTar(w io.Writer, root string, paths []string) error {
3131
tw := tar.NewWriter(w)
3232
defer tw.Close()
3333

34-
absContext, err := filepath.Abs(root)
35-
if err != nil {
36-
return err
37-
}
3834
for _, p := range paths {
39-
absPath, err := filepath.Abs(p)
40-
if err != nil {
41-
return err
42-
}
43-
44-
tarPath, err := filepath.Rel(absContext, absPath)
45-
if err != nil {
46-
return err
47-
}
35+
tarPath := filepath.ToSlash(filepath.Join(root, p))
4836

49-
if err := addFileToTar(p, filepath.ToSlash(tarPath), tw); err != nil {
37+
if err := addFileToTar(tarPath, p, tw); err != nil {
5038
return err
5139
}
5240

0 commit comments

Comments
 (0)