-
Notifications
You must be signed in to change notification settings - Fork 8
/
simple_tree_verifier.go
135 lines (115 loc) · 2.91 KB
/
simple_tree_verifier.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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//go:build !tinywasm
package gtree
import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
)
func newVerifierSimple(dir string, strict bool) verifierSimple {
targetDir := "."
if len(dir) != 0 {
targetDir = dir
}
return &defaultVerifierSimple{
strict: strict,
targetDir: targetDir,
}
}
type defaultVerifierSimple struct {
strict bool
targetDir string
}
func (dv *defaultVerifierSimple) verify(roots []*Node) error {
for i := range roots {
extra, noExists, err := dv.verifyRoot(roots[i])
if err != nil {
return err
}
if err := dv.handleErr(extra, noExists); err != nil {
return err
}
}
return nil
}
func (dv *defaultVerifierSimple) verifyRoot(root *Node) ([]string, []string, error) {
dirsMarkdown := map[string]struct{}{}
if err := dv.fillDirsMarkdown(root, dirsMarkdown); err != nil {
return nil, nil, err
}
dirsFilesystem := map[string]struct{}{}
extraDirs := []string{}
if err := fs.WalkDir(
os.DirFS(filepath.Join(dv.targetDir, root.path())),
".",
func(path string, d fs.DirEntry, err error) error {
dir := filepath.Join(dv.targetDir, root.path(), path)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
// markdown上のrootが検査対象パスに無いとエラー
return verifyError{noExists: []string{dir}}
}
return err
}
if _, ok := dirsMarkdown[dir]; !ok {
// Markdownに無いパスがディレクトリに有る => strictモードでエラー
extraDirs = append(extraDirs, dir)
}
dirsFilesystem[dir] = struct{}{}
return nil
},
); err != nil {
return nil, nil, err
}
// Markdownに有るパスがディレクトリに無い時 => 通常/strictモード共通でエラー
noExistDirs := []string{}
for dir := range dirsMarkdown {
if _, ok := dirsFilesystem[dir]; !ok {
noExistDirs = append(noExistDirs, dir)
}
}
return extraDirs, noExistDirs, nil
}
func (dv *defaultVerifierSimple) fillDirsMarkdown(node *Node, dirs map[string]struct{}) error {
dirs[filepath.Join(dv.targetDir, node.path())] = struct{}{}
for i := range node.children {
if err := dv.fillDirsMarkdown(node.children[i], dirs); err != nil {
return err
}
}
return nil
}
func (dv *defaultVerifierSimple) handleErr(extra, noExists []string) error {
if (dv.strict && len(extra) != 0) || len(noExists) != 0 {
return verifyError{
strict: dv.strict,
extra: extra,
noExists: noExists,
}
}
return nil
}
type verifyError struct {
strict bool
extra []string
noExists []string
}
func (v verifyError) Error() string {
tabPrefix := func(arr []string) string {
tmp := ""
for i := range arr {
tmp += fmt.Sprintf("\t%s\n", arr[i])
}
return tmp
}
msg := ""
if v.strict && len(v.extra) != 0 {
msg += fmt.Sprintf("Extra paths exist:\n%s", tabPrefix(v.extra))
}
if len(v.noExists) != 0 {
msg += fmt.Sprintf("Required paths does not exist:\n%s", tabPrefix(v.noExists))
}
return strings.TrimSuffix(msg, "\n")
}