diff --git a/sherpa/file_listing.go b/sherpa/file_listing.go index ba3b21c..d0ee771 100644 --- a/sherpa/file_listing.go +++ b/sherpa/file_listing.go @@ -46,6 +46,21 @@ type result struct { value FileEntry } +// NewFileListingHash generates a sha256 hash from the listing of all entries under the roots +func NewFileListingHash(roots ...string) (string, error) { + files, err := NewFileListing(roots...) + if err != nil { + return "", fmt.Errorf("unable to create file listing\n%w", err) + } + + hash := sha256.New() + for _, file := range files { + hash.Write([]byte(file.Path + file.Mode + file.SHA256 + "\n")) + } + + return hex.EncodeToString(hash.Sum(nil)), nil +} + // NewFileListing generates a listing of all entries under the roots. func NewFileListing(roots ...string) ([]FileEntry, error) { entries := make(chan FileEntry) diff --git a/sherpa/file_listing_test.go b/sherpa/file_listing_test.go index b8c5d3b..f390e9c 100644 --- a/sherpa/file_listing_test.go +++ b/sherpa/file_listing_test.go @@ -17,6 +17,8 @@ package sherpa_test import ( + "crypto/sha256" + "encoding/hex" "io/ioutil" "os" "path/filepath" @@ -75,4 +77,23 @@ func testFileListing(t *testing.T, context spec.G, it spec.S) { Expect(e[4].Path).To(HaveSuffix("bravo.txt")) Expect(e[1].SHA256).To(Equal(e[4].SHA256)) // symlink to file should have hash of target file }) + + it("create listing and get SHA256", func() { + Expect(ioutil.WriteFile(filepath.Join(path, "alpha.txt"), []byte{}, 0644)).To(Succeed()) + Expect(os.MkdirAll(filepath.Join(path, "test-directory"), 0755)).To(Succeed()) + Expect(ioutil.WriteFile(filepath.Join(path, "test-directory", "bravo.txt"), []byte{}, 0644)).To(Succeed()) + + e, err := sherpa.NewFileListing(path) + Expect(err).NotTo(HaveOccurred()) + + hash := sha256.New() + for _, file := range e { + hash.Write([]byte(file.Path + file.Mode + file.SHA256 + "\n")) + } + + s, err := sherpa.NewFileListingHash(path) + Expect(err).NotTo(HaveOccurred()) + + Expect(s).To(Equal(hex.EncodeToString(hash.Sum(nil)))) + }) }