/
sum.go
82 lines (71 loc) · 1.63 KB
/
sum.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package fsutil
import (
"crypto/sha256"
"fmt"
"io"
"os"
"path"
"sort"
"strings"
"github.com/go-git/go-billy/v5"
)
func SumFileNameAndContents(fs billy.Filesystem) (string, error) {
var (
err error
fds []os.FileInfo
)
var recursiveSum func(fs billy.Filesystem, path string) ([]byte, error)
recursiveSum = func(fs billy.Filesystem, p string) ([]byte, error) {
if fds, err = fs.ReadDir(p); err != nil {
return nil, err
}
sort.Sort(sorter{
len(fds),
func(i, j int) { fds[i], fds[j] = fds[j], fds[i] },
func(i, j int) bool {
return strings.Compare(fds[i].Name(), fds[j].Name()) > 0
},
})
var sums []byte
for _, fd := range fds {
nm := path.Join(p, fd.Name())
if fd.IsDir() {
sum, err := recursiveSum(fs, nm)
if err != nil {
return nil, err
}
sums = append(sums, sum...)
} else {
h := sha256.New()
f, err := fs.Open(nm)
if err != nil {
return nil, err
}
if _, err := h.Write([]byte(nm)); err != nil {
return nil, err
}
if _, err := io.Copy(h, f); err != nil {
return nil, err
}
sums = append(sums, h.Sum(nil)...)
}
}
sm := sha256.Sum256(sums)
return sm[:], nil
}
buf, err := recursiveSum(fs, "/")
if err != nil {
return "", err
}
return fmt.Sprintf("%x", buf), nil
}
// srt "generic"
// https://medium.com/capital-one-tech/closures-are-the-generics-for-go-cb32021fb5b5
type sorter struct {
len int
swap func(i, j int)
less func(i, j int) bool
}
func (x sorter) Len() int { return x.len }
func (x sorter) Swap(i, j int) { x.swap(i, j) }
func (x sorter) Less(i, j int) bool { return x.less(i, j) }