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

feat: allow symlink #571

Closed
wants to merge 1 commit into from
Closed
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
19 changes: 19 additions & 0 deletions pkg/commands/options/filestuff.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ func EnumerateFiles(fo *FilenameOptions) chan string {
// processing (unless we are in recursive mode). If we decide to process
// the directory, and we're in watch mode, then we set up a watch on the
// directory.
symlink, err := ResolveSymlink(path, fi)
if err != nil {
return err
}

if fi.IsDir() {
if path != paths && !fo.Recursive {
return filepath.SkipDir
Expand All @@ -67,6 +72,10 @@ func EnumerateFiles(fo *FilenameOptions) chan string {
return nil
}

if symlink != "" {
files <- symlink
}

// Don't check extension if the filepath was passed explicitly
if path != paths {
switch filepath.Ext(path) {
Expand All @@ -87,3 +96,13 @@ func EnumerateFiles(fo *FilenameOptions) chan string {
}()
return files
}

func ResolveSymlink(path string, fi os.FileInfo) (symlink string, err error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be replaced with https://pkg.go.dev/path/filepath#EvalSymlinks ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it didn't work when I switched to EvalSymlink, I don't know why 🤷🏻‍♂️

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to understand better why that's the case. This is getting fairly complicated, and I'd rather depend on stdlib methods as much as possible. If we still need to write significant code to handle symlinks, I'm a bit more inclined not to support symlinks for now.

if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
symlink, err = os.Readlink(path) // TODO: Handle error here
developer-guy marked this conversation as resolved.
Show resolved Hide resolved
if !filepath.IsAbs(symlink) { // Output of os.Readlink is OS-dependent...
symlink = filepath.Join(filepath.Dir(path), symlink)
}
}
return
}
20 changes: 19 additions & 1 deletion pkg/commands/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,25 @@ func resolveFile(
if f == "-" {
b, err = ioutil.ReadAll(os.Stdin)
} else {
b, err = ioutil.ReadFile(f)
fi, err := os.Lstat(f)
if err != nil {
return nil, fmt.Errorf("unable to find file %s selector: %wß", f, err)
}

symlink, err := options.ResolveSymlink(f, fi)
if err != nil {
return nil, fmt.Errorf("unable to resolve symlink of file %s selector: %w", f, err)
}

if symlink != "" {
b, err = ioutil.ReadFile(symlink)
} else {
b, err = ioutil.ReadFile(f)
}

if err != nil {
return nil, fmt.Errorf("unable to read file %s: %w", f, err)
}
}
if err != nil {
return nil, err
Expand Down
68 changes: 67 additions & 1 deletion pkg/commands/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,15 @@ import (
"io/ioutil"
"log"
"net/http/httptest"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"testing"

"gopkg.in/yaml.v3"

"github.com/docker/docker/api/types"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
Expand All @@ -42,7 +47,6 @@ import (
"github.com/google/ko/pkg/build"
"github.com/google/ko/pkg/commands/options"
kotesting "github.com/google/ko/pkg/internal/testing"
"gopkg.in/yaml.v3"
)

var (
Expand All @@ -65,6 +69,12 @@ var (
errImageTag = fmt.Errorf("ImageTag() error")
)

func RootDir() string {
_, b, _, _ := runtime.Caller(0)
d := path.Join(path.Dir(b), "..")
return filepath.Dir(d)
}

type erroringClient struct {
daemon.Client
}
Expand Down Expand Up @@ -131,6 +141,62 @@ func TestResolveMultiDocumentYAMLs(t *testing.T) {
}
}

func TestResolveSymlink(t *testing.T) {
testRef := "github.com/google/ko/test"
refs := []string{testRef}
hashes := []v1.Hash{fooHash}

f := filepath.Join(RootDir(), "test", "test.yaml")
inputYAML, err := os.ReadFile(f)
if err != nil {
t.Fatalf("Readfile(%s) = %v", f, err)
}

m := map[string]v1.Hash{
testRef: fooHash,
}

base := mustRepository("gcr.io/multi-pass")
outYAML, err := resolveFile(
context.Background(),
filepath.Join(RootDir(), "test", "symlink.yaml"),
kotesting.NewFixedBuild(map[string]build.Result{
testRef: foo,
}),
kotesting.NewFixedPublish(base, m),
&options.SelectorOptions{})

if err != nil {
t.Fatalf("ImageReferences(%v) = %v", string(inputYAML), err)
}

rd := bytes.NewReader(outYAML)
decoder := yaml.NewDecoder(rd)
var outStructured []string
for {
var output map[string]interface{}
if err := decoder.Decode(&output); err == nil {
outStructured = append(outStructured, output["spec"].(map[string]interface{})["containers"].([]interface{})[0].(map[string]interface{})["image"].(string))
} else if errors.Is(err, io.EOF) {
break
} else {
t.Errorf("yaml.Unmarshal(%v) = %v", string(outYAML), err)
}
}

expectedStructured := []string{
kotesting.ComputeDigest(base, refs[0], hashes[0]),
}

if want, got := len(expectedStructured), len(outStructured); want != got {
t.Errorf("resolveFile(%v) = %v, want %v", string(inputYAML), got, want)
}

if diff := cmp.Diff(expectedStructured, outStructured, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("resolveFile(%v); (-want +got) = %v", string(inputYAML), diff)
}
}

func TestResolveMultiDocumentYAMLsWithSelector(t *testing.T) {
passesSelector := `apiVersion: something/v1
kind: Foo
Expand Down
1 change: 1 addition & 0 deletions test/symlink.yaml