Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for recursively resolving directory symlinks. #73

Merged
merged 2 commits into from
Aug 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions cmd/ko/test/kodata/HEAD
1 change: 1 addition & 0 deletions cmd/ko/test/kodata/refs
7 changes: 7 additions & 0 deletions cmd/ko/test/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,11 @@ func main() {
log.Fatalf("Error reading %q: %v", file, err)
}
log.Printf(string(bytes))

file = filepath.Join(dp, "refs/heads/master")
bytes, err = ioutil.ReadFile(file)
if err != nil {
log.Fatalf("Error reading %q: %v", file, err)
}
log.Printf(string(bytes))
}
2 changes: 1 addition & 1 deletion cmd/ko/test/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ metadata:
spec:
containers:
- name: obiwan
image: github.com/google/ko/cmd/test
image: github.com/google/ko/cmd/ko/test
restartPolicy: Never
55 changes: 33 additions & 22 deletions pkg/build/gobuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,28 +276,15 @@ func (g *gobuild) kodataPath(s string) (string, error) {
// Where kodata lives in the image.
const kodataRoot = "/var/run/ko"

func (g *gobuild) tarKoData(importpath string) (*bytes.Buffer, error) {
buf := bytes.NewBuffer(nil)
// Compress this before calling tarball.LayerFromOpener, since it eagerly
// calculates digests and diffids. This prevents us from double compressing
// the layer when we have to actually upload the blob.
//
// https://github.com/google/go-containerregistry/issues/413
gw, _ := gzip.NewWriterLevel(buf, gzip.BestSpeed)
defer gw.Close()
tw := tar.NewWriter(gw)
defer tw.Close()

root, err := g.kodataPath(importpath)
if err != nil {
return nil, err
}

err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
// walkRecursive performs a filepath.Walk of the given root directory adding it
// to the provided tar.Writer with root -> chroot. All symlinks are dereferenced,
// which is what leads to recursion when we encounter a directory symlink.
func walkRecursive(tw *tar.Writer, root, chroot string) error {
mattmoor marked this conversation as resolved.
Show resolved Hide resolved
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if path == root {
// Add an entry for /var/run/ko
// Add an entry for the root directory of our walk.
return tw.WriteHeader(&tar.Header{
Name: kodataRoot,
Name: chroot,
mattmoor marked this conversation as resolved.
Show resolved Hide resolved
Typeflag: tar.TypeDir,
// Use a fixed Mode, so that this isn't sensitive to the directory and umask
// under which it was created. Additionally, windows can only set 0222,
Expand All @@ -312,12 +299,22 @@ func (g *gobuild) tarKoData(importpath string) (*bytes.Buffer, error) {
if info.Mode().IsDir() {
return nil
}
newPath := filepath.Join(chroot, path[len(root):])

path, err = filepath.EvalSymlinks(path)
if err != nil {
return err
}

// Chase symlinks.
info, err = os.Stat(path)
if err != nil {
return err
}
// Skip other directories.
mattmoor marked this conversation as resolved.
Show resolved Hide resolved
if info.Mode().IsDir() {
return walkRecursive(tw, path, newPath)
}

// Open the file to copy it into the tarball.
file, err := os.Open(path)
Expand All @@ -327,7 +324,6 @@ func (g *gobuild) tarKoData(importpath string) (*bytes.Buffer, error) {
defer file.Close()

// Copy the file into the image tarball.
newPath := filepath.Join(kodataRoot, path[len(root):])
if err := tw.WriteHeader(&tar.Header{
Name: newPath,
Size: info.Size(),
Expand All @@ -342,11 +338,26 @@ func (g *gobuild) tarKoData(importpath string) (*bytes.Buffer, error) {
_, err = io.Copy(tw, file)
return err
})
}

func (g *gobuild) tarKoData(importpath string) (*bytes.Buffer, error) {
buf := bytes.NewBuffer(nil)
// Compress this before calling tarball.LayerFromOpener, since it eagerly
// calculates digests and diffids. This prevents us from double compressing
// the layer when we have to actually upload the blob.
//
// https://github.com/google/go-containerregistry/issues/413
gw, _ := gzip.NewWriterLevel(buf, gzip.BestSpeed)
mattmoor marked this conversation as resolved.
Show resolved Hide resolved
defer gw.Close()
tw := tar.NewWriter(gw)
defer tw.Close()

root, err := g.kodataPath(importpath)
if err != nil {
return nil, err
}

return buf, nil
return buf, walkRecursive(tw, root, kodataRoot)
}

// Build implements build.Interface
Expand Down
14 changes: 5 additions & 9 deletions pkg/build/gobuild_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,19 +253,15 @@ func TestGoBuild(t *testing.T) {
})

t.Run("check app layer contents", func(t *testing.T) {
expectedHash := v1.Hash{
Algorithm: "sha256",
Hex: "4379f30a6c6f66221c3c54dddd378fcfa5a7304a6655ff783b102069c0f943ab",
}
appLayer := ls[baseLayers]
dataLayer := ls[baseLayers]

if got, err := appLayer.Digest(); err != nil {
if _, err := dataLayer.Digest(); err != nil {
t.Errorf("Digest() = %v", err)
} else if got != expectedHash {
t.Errorf("Digest() = %v, want %v", got, expectedHash)
}
// We don't check the data layer here because it includes a symlink of refs and
// will produce a distinct hash each time we commit something.

r, err := appLayer.Uncompressed()
r, err := dataLayer.Uncompressed()
if err != nil {
t.Errorf("Uncompressed() = %v", err)
}
Expand Down