From b1a6ad7ef04955b4e9a4b856fbd94a2e2829f83e Mon Sep 17 00:00:00 2001
From: Yukun Wang <airycanon@airycanon.me>
Date: Mon, 10 Apr 2023 21:59:22 +0800
Subject: [PATCH] fix symlink error (#425)

---
 hash/hash.go      | 16 ++++++++++++++--
 hash/hash_test.go | 29 ++++++++++++++++++++++++-----
 2 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/hash/hash.go b/hash/hash.go
index cb7f0880..a00f29e5 100644
--- a/hash/hash.go
+++ b/hash/hash.go
@@ -31,7 +31,7 @@ import (
 	"hash"
 	"hash/fnv"
 	"io/fs"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 
 	"github.com/davecgh/go-spew/spew"
@@ -110,7 +110,19 @@ func HashFolder(ctx context.Context, folder string, filters ...HashFolderFilter)
 			}
 		}
 		if !d.IsDir() {
-			if data, readErr := ioutil.ReadFile(path); readErr == nil {
+			var (
+				link    string
+				data    []byte
+				readErr error
+			)
+			if d.Type() == os.ModeSymlink {
+				link, readErr = os.Readlink(path)
+				data = []byte(link)
+			} else {
+				data, readErr = os.ReadFile(path)
+			}
+
+			if readErr == nil {
 				digestHash := digest.FromBytes(data)
 				log.Debugf("hash for path: %s hash: %q", path, digestHash)
 				digests = append(digests, digestHash)
diff --git a/hash/hash_test.go b/hash/hash_test.go
index 3be81ebf..d73bff28 100644
--- a/hash/hash_test.go
+++ b/hash/hash_test.go
@@ -21,16 +21,15 @@ import (
 	"fmt"
 	"hash/adler32"
 	"io/fs"
-	"k8s.io/apimachinery/pkg/util/rand"
 	"os"
 	"os/exec"
 	"strings"
 	"testing"
 
+	"github.com/davecgh/go-spew/spew"
 	"github.com/katanomi/pkg/command/io"
 	"github.com/onsi/gomega"
-
-	"github.com/davecgh/go-spew/spew"
+	"k8s.io/apimachinery/pkg/util/rand"
 )
 
 type A struct {
@@ -346,6 +345,26 @@ func TestHashFolder(t *testing.T) {
 				return !strings.HasPrefix(path, "testdata/copy/rand")
 			},
 		},
+		"with symlink": {
+			Folder: "testdata/copy",
+			Action: func(folder string, t *testing.T) error {
+				os.RemoveAll("testdata/copy")
+				if err := io.Copy("testdata/chart", "testdata/copy"); err != nil {
+					return err
+				}
+				if err := os.Symlink("../chart", "testdata/copy/symlink"); err != nil {
+					return err
+				}
+
+				return nil
+			},
+			// new hash
+			Expected: "sha256:81cbbdb10d09c20294eea4347b594d6c13c8c9d8ea1e4a3e0cb28e2052482c97",
+			Error:    nil,
+			AfterAction: func() {
+				os.RemoveAll("testdata/copy")
+			},
+		},
 	}
 
 	for k, test := range table {
@@ -361,13 +380,13 @@ func TestHashFolder(t *testing.T) {
 			if test.AfterAction != nil {
 				test.AfterAction()
 			}
-			g.Expect(hashResult).To(gomega.ContainSubstring(test.Expected))
-			t.Logf("expected: %q == %q", hashResult, test.Expected)
 			if test.Error == nil {
 				g.Expect(err).To(gomega.BeNil())
 			} else {
 				g.Expect(err).ToNot(gomega.BeNil())
 			}
+			g.Expect(hashResult).To(gomega.ContainSubstring(test.Expected))
+			t.Logf("expected: %q == %q", hashResult, test.Expected)
 		})
 	}
 }