cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.72.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/discovery/glob.go

185lines · modecode

1package discovery
2
3import (
4 "errors"
5 "fmt"
6 "io/fs"
7 "log/slog"
8 "os"
9 "path/filepath"
10 "regexp"
11
12 "github.com/prometheus/common/model"
13
14 "github.com/cloudflare/pint/internal/git"
15 "github.com/cloudflare/pint/internal/parser"
16)
17
18func NewGlobFinder(patterns []string, filter git.PathFilter, schema parser.Schema, names model.ValidationScheme, allowedOwners []*regexp.Regexp) GlobFinder {
19 return GlobFinder{
20 patterns: patterns,
21 filter: filter,
22 schema: schema,
23 names: names,
24 allowedOwners: allowedOwners,
25 }
26}
27
28type GlobFinder struct {
29 filter git.PathFilter
30 patterns []string
31 allowedOwners []*regexp.Regexp
32 schema parser.Schema
33 names model.ValidationScheme
34}
35
36func (f GlobFinder) Find() (entries []Entry, err error) {
37 paths := filePaths{}
38 for _, p := range f.patterns {
39 matches, err := filepath.Glob(p)
40 if err != nil {
41 return nil, fmt.Errorf("failed to expand file path pattern %s: %w", p, err)
42 }
43
44 for _, path := range matches {
45 if path == ".git" && isDir(path) {
46 slog.Debug(
47 "Excluding git directory from glob results",
48 slog.String("path", path),
49 slog.String("glob", p),
50 )
51 continue
52 }
53
54 subpaths, err := findFiles(path)
55 if err != nil {
56 return nil, err
57 }
58 for _, subpath := range subpaths {
59 if !paths.hasPath(subpath.path) {
60 paths = append(paths, subpath)
61 }
62 }
63 }
64 }
65
66 if len(paths) == 0 {
67 return nil, errors.New("no matching files")
68 }
69
70 for _, fp := range paths {
71 if !f.filter.IsPathAllowed(fp.path) {
72 continue
73 }
74
75 fd, err := os.Open(fp.path)
76 if err != nil {
77 return nil, err
78 }
79 p := parser.NewParser(!f.filter.IsRelaxed(fp.target), f.schema, f.names)
80 el, err := readRules(fp.target, fp.path, fd, p, f.allowedOwners)
81 if err != nil {
82 fd.Close()
83 return nil, fmt.Errorf("invalid file syntax: %w", err)
84 }
85 fd.Close()
86 for _, e := range el {
87 e.State = Noop
88 if len(e.ModifiedLines) == 0 {
89 e.ModifiedLines = e.Rule.Lines.Expand()
90 }
91 entries = append(entries, e)
92 }
93 }
94
95 slog.Debug("Glob finder completed", slog.Int("count", len(entries)))
96 return entries, nil
97}
98
99func isDir(path string) bool {
100 info, err := os.Stat(path)
101 if err != nil {
102 return false
103 }
104 return info.IsDir()
105}
106
107type filePath struct {
108 path string
109 target string
110}
111
112type filePaths []filePath
113
114func (fps filePaths) hasPath(p string) bool {
115 for _, fp := range fps {
116 if fp.path == p {
117 return true
118 }
119 }
120 return false
121}
122
123func findFiles(path string) (paths filePaths, err error) {
124 target, err := filepath.EvalSymlinks(path)
125 if err != nil {
126 return nil, fmt.Errorf("%s is a symlink but target file cannot be evaluated: %w", path, err)
127 }
128
129 s, err := os.Stat(path)
130 if err != nil {
131 return nil, err
132 }
133
134 // nolint: exhaustive
135 switch {
136 case s.IsDir():
137 subpaths, err := walkDir(path)
138 if err != nil {
139 return nil, err
140 }
141 paths = append(paths, subpaths...)
142 default:
143 paths = append(paths, filePath{path: path, target: target})
144 }
145
146 return paths, nil
147}
148
149func walkDir(dirname string) (paths filePaths, err error) {
150 err = filepath.WalkDir(dirname,
151 func(path string, d fs.DirEntry, err error) error {
152 if err != nil {
153 return err
154 }
155
156 // nolint: exhaustive
157 switch d.Type() {
158 case fs.ModeDir:
159 return nil
160 default:
161 dest, err := filepath.EvalSymlinks(path)
162 if err != nil {
163 return fmt.Errorf("%s is a symlink but target file cannot be evaluated: %w", path, err)
164 }
165
166 s, err := os.Stat(dest)
167 if err != nil {
168 return err
169 }
170 if s.IsDir() {
171 subpaths, err := findFiles(dest)
172 if err != nil {
173 return err
174 }
175 paths = append(paths, subpaths...)
176 } else {
177 paths = append(paths, filePath{path: path, target: dest})
178 }
179 }
180
181 return nil
182 })
183
184 return paths, err
185}
186