Skip to content

Commit 4c4d7de

Browse files
author
Priya Wadhwa
committed
Get working dir from image and use as relative directory if necessary
2 parents b7ef0c7 + 49ef4ce commit 4c4d7de

File tree

6 files changed

+73
-50
lines changed

6 files changed

+73
-50
lines changed

pkg/skaffold/docker/image.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (l *localDaemon) ConfigFile(ctx context.Context, image string) (*v1.ConfigF
110110
return nil, err
111111
}
112112
} else {
113-
cfg, err = retrieveRemoteConfig(image)
113+
cfg, err = RetrieveRemoteConfig(image)
114114
if err != nil {
115115
return nil, errors.Wrap(err, "getting remote config")
116116
}

pkg/skaffold/docker/remote.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ func RemoteDigest(identifier string) (string, error) {
6161
return h.String(), nil
6262
}
6363

64-
func retrieveRemoteConfig(identifier string) (*v1.ConfigFile, error) {
64+
// RetrieveRemoteConfig retrieves the remote config file for an image
65+
func RetrieveRemoteConfig(identifier string) (*v1.ConfigFile, error) {
6566
img, err := remoteImage(identifier)
6667
if err != nil {
6768
return nil, errors.Wrap(err, "getting image")

pkg/skaffold/runner/dev_test.go

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525

2626
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
2727
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
28+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/sync"
2829
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/watch"
2930
"github.com/GoogleContainerTools/skaffold/testutil"
3031
)
@@ -327,6 +328,13 @@ func TestDevSync(t *testing.T) {
327328

328329
for _, test := range tests {
329330
t.Run(test.description, func(t *testing.T) {
331+
originalWorkingDir := sync.WorkingDir
332+
sync.WorkingDir = func(image string) (string, error) {
333+
return "/", nil
334+
}
335+
defer func() {
336+
sync.WorkingDir = originalWorkingDir
337+
}()
330338
runner := createRunner(t, test.testBench)
331339
runner.Watcher = &TestWatcher{
332340
events: test.watchEvents,

pkg/skaffold/sync/kubectl/kubectl.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func copyFileFn(ctx context.Context, pod v1.Pod, container v1.Container, files m
7474
// Use "m" flag to touch the files as they are copied.
7575
reader, writer := io.Pipe()
7676
copy := exec.CommandContext(ctx, "kubectl", "exec", pod.Name, "--namespace", pod.Namespace, "-c", container.Name, "-i",
77-
"--", "tar", "xmf", "-", "-C", "/", "--no-same-owner")
77+
"--", "tar", "xmf", "-", "--no-same-owner")
7878
copy.Stdin = reader
7979
go func() {
8080
defer writer.Close()

pkg/skaffold/sync/sync.go

+35-18
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ import (
2121
"fmt"
2222
"os/exec"
2323
"path/filepath"
24-
"strings"
2524

2625
"github.com/bmatcuk/doublestar"
2726
"github.com/sirupsen/logrus"
2827

2928
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
29+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
3030
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes"
3131
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
3232
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
@@ -36,6 +36,11 @@ import (
3636
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3737
)
3838

39+
var (
40+
// For testing
41+
WorkingDir = retrieveWorkingDir
42+
)
43+
3944
type Syncer interface {
4045
Sync(context.Context, *Item) error
4146
}
@@ -52,12 +57,22 @@ func NewItem(a *latest.Artifact, e watch.Events, builds []build.Artifact) (*Item
5257
return nil, nil
5358
}
5459

55-
toCopy, err := intersect(a.Workspace, a.Sync, append(e.Added, e.Modified...))
60+
tag := latestTag(a.ImageName, builds)
61+
if tag == "" {
62+
return nil, fmt.Errorf("could not find latest tag for image %s in builds: %v", a.ImageName, builds)
63+
}
64+
65+
wd, err := WorkingDir(tag)
66+
if err != nil {
67+
return nil, errors.Wrapf(err, "retrieving working dir for %s", tag)
68+
}
69+
70+
toCopy, err := intersect(a.Workspace, a.Sync, append(e.Added, e.Modified...), wd)
5671
if err != nil {
5772
return nil, errors.Wrap(err, "intersecting sync map and added, modified files")
5873
}
5974

60-
toDelete, err := intersect(a.Workspace, a.Sync, e.Deleted)
75+
toDelete, err := intersect(a.Workspace, a.Sync, e.Deleted, wd)
6176
if err != nil {
6277
return nil, errors.Wrap(err, "intersecting sync map and deleted files")
6378
}
@@ -67,18 +82,24 @@ func NewItem(a *latest.Artifact, e watch.Events, builds []build.Artifact) (*Item
6782
return nil, nil
6883
}
6984

70-
tag := latestTag(a.ImageName, builds)
71-
if tag == "" {
72-
return nil, fmt.Errorf("could not find latest tag for image %s in builds: %v", a.ImageName, builds)
73-
}
74-
7585
return &Item{
7686
Image: tag,
7787
Copy: toCopy,
7888
Delete: toDelete,
7989
}, nil
8090
}
8191

92+
func retrieveWorkingDir(image string) (string, error) {
93+
cf, err := docker.RetrieveRemoteConfig(image)
94+
if err != nil {
95+
return "", errors.Wrap(err, "retrieving remote config")
96+
}
97+
if cf.Config.WorkingDir == "" {
98+
return "/", nil
99+
}
100+
return cf.Config.WorkingDir, nil
101+
}
102+
82103
func latestTag(image string, builds []build.Artifact) string {
83104
for _, build := range builds {
84105
if build.ImageName == image {
@@ -88,7 +109,7 @@ func latestTag(image string, builds []build.Artifact) string {
88109
return ""
89110
}
90111

91-
func intersect(context string, syncMap map[string]string, files []string) (map[string]string, error) {
112+
func intersect(context string, syncMap map[string]string, files []string, workingDir string) (map[string]string, error) {
92113
ret := map[string]string{}
93114

94115
for _, f := range files {
@@ -103,18 +124,14 @@ func intersect(context string, syncMap map[string]string, files []string) (map[s
103124
return nil, errors.Wrapf(err, "pattern error for %s", relPath)
104125
}
105126
if match {
106-
staticPath := strings.Split(filepath.FromSlash(p), "*")[0]
127+
if filepath.IsAbs(dst) {
128+
dst = filepath.ToSlash(filepath.Join(dst, filepath.Base(relPath)))
129+
} else {
130+
dst = filepath.ToSlash(filepath.Join(workingDir, dst, filepath.Base(relPath)))
131+
}
107132
// Every file must match at least one sync pattern, if not we'll have to
108133
// skip the entire sync
109134
matches = true
110-
// If the source has special match characters,
111-
// the destination must be a directory
112-
// The path package must be used here to enforce slashes,
113-
// since the destination is always a linux filesystem.
114-
if util.HasMeta(p) {
115-
relPathDynamic := strings.TrimPrefix(relPath, staticPath)
116-
dst = filepath.ToSlash(filepath.Join(dst, filepath.Base(relPathDynamic)))
117-
}
118135
ret[f] = dst
119136
}
120137
}

pkg/skaffold/sync/sync_test.go

+26-29
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func TestNewSyncItem(t *testing.T) {
4444
builds []build.Artifact
4545
shouldErr bool
4646
expected *Item
47+
workingDir string
4748
}{
4849
{
4950
description: "match copy",
@@ -142,10 +143,11 @@ func TestNewSyncItem(t *testing.T) {
142143
evt: watch.Events{
143144
Modified: []string{filepath.Join("node", "src/app/server/server.js")},
144145
},
146+
workingDir: "/",
145147
expected: &Item{
146148
Image: "test:123",
147149
Copy: map[string]string{
148-
filepath.Join("node", "src/app/server/server.js"): "src/server.js",
150+
filepath.Join("node", "src/app/server/server.js"): "/src/server.js",
149151
},
150152
Delete: map[string]string{},
151153
},
@@ -193,6 +195,12 @@ func TestNewSyncItem(t *testing.T) {
193195
Added: []string{"main.go"},
194196
Deleted: []string{"index.html"},
195197
},
198+
builds: []build.Artifact{
199+
{
200+
ImageName: "",
201+
Tag: "placeholder",
202+
},
203+
},
196204
},
197205
{
198206
description: "not delete syncable",
@@ -206,6 +214,12 @@ func TestNewSyncItem(t *testing.T) {
206214
Added: []string{"index.html"},
207215
Deleted: []string{"some/other/file"},
208216
},
217+
builds: []build.Artifact{
218+
{
219+
ImageName: "",
220+
Tag: "placeholder",
221+
},
222+
},
209223
},
210224
{
211225
description: "err bad pattern",
@@ -245,6 +259,7 @@ func TestNewSyncItem(t *testing.T) {
245259
},
246260
Workspace: ".",
247261
},
262+
workingDir: "/some/dir",
248263
builds: []build.Artifact{
249264
{
250265
ImageName: "test",
@@ -257,33 +272,7 @@ func TestNewSyncItem(t *testing.T) {
257272
expected: &Item{
258273
Image: "test:123",
259274
Copy: map[string]string{
260-
filepath.Join("dir1", "dir2/node.js"): "node.js",
261-
},
262-
Delete: map[string]string{},
263-
},
264-
},
265-
{
266-
description: "copy subdirectory",
267-
artifact: &latest.Artifact{
268-
ImageName: "test",
269-
Sync: map[string]string{
270-
"**/*.py": ".",
271-
},
272-
Workspace: "python",
273-
},
274-
builds: []build.Artifact{
275-
{
276-
ImageName: "test",
277-
Tag: "test:123",
278-
},
279-
},
280-
evt: watch.Events{
281-
Modified: []string{filepath.Join("src", "app.py")},
282-
},
283-
expected: &Item{
284-
Image: "test:123",
285-
Copy: map[string]string{
286-
filepath.Join("src", "app.py"): "app.py",
275+
filepath.Join("dir1", "dir2/node.js"): "/some/dir/node.js",
287276
},
288277
Delete: map[string]string{},
289278
},
@@ -292,6 +281,13 @@ func TestNewSyncItem(t *testing.T) {
292281

293282
for _, test := range tests {
294283
t.Run(test.description, func(t *testing.T) {
284+
originalWorkingDir := WorkingDir
285+
WorkingDir = func(image string) (string, error) {
286+
return test.workingDir, nil
287+
}
288+
defer func() {
289+
WorkingDir = originalWorkingDir
290+
}()
295291
actual, err := NewItem(test.artifact, test.evt, test.builds)
296292
testutil.CheckErrorAndDeepEqual(t, test.shouldErr, err, test.expected, actual)
297293
})
@@ -305,6 +301,7 @@ func TestIntersect(t *testing.T) {
305301
syncPatterns map[string]string
306302
files []string
307303
context string
304+
workingDir string
308305
expected map[string]string
309306
shouldErr bool
310307
}{
@@ -347,7 +344,7 @@ func TestIntersect(t *testing.T) {
347344

348345
for _, test := range tests {
349346
t.Run(test.description, func(t *testing.T) {
350-
actual, err := intersect(test.context, test.syncPatterns, test.files)
347+
actual, err := intersect(test.context, test.syncPatterns, test.files, test.workingDir)
351348
testutil.CheckErrorAndDeepEqual(t, test.shouldErr, err, test.expected, actual)
352349
})
353350
}

0 commit comments

Comments
 (0)