-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathcli.go
175 lines (150 loc) · 4.47 KB
/
cli.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package cli
import (
"fmt"
"os"
"github.com/Boeing/config-file-validator/pkg/finder"
"github.com/Boeing/config-file-validator/pkg/reporter"
)
// GroupOutput is a global variable that is used to
// store the group by options that the user specifies
var GroupOutput []string
var Quiet bool
type CLI struct {
// FileFinder interface to search for the files
// in the SearchPath
Finder finder.FileFinder
// Reporter interface for outputting the results of the
// the CLI run
Reporter reporter.Reporter
}
// Implement the go options pattern to be able to
// set options to the CLI struct using functional
// programming
type CLIOption func(*CLI)
// Set the CLI Finder
func WithFinder(finder finder.FileFinder) CLIOption {
return func(c *CLI) {
c.Finder = finder
}
}
// Set the reporter type
func WithReporter(reporter reporter.Reporter) CLIOption {
return func(c *CLI) {
c.Reporter = reporter
}
}
func WithGroupOutput(groupOutput []string) CLIOption {
return func(c *CLI) {
GroupOutput = groupOutput
}
}
func WithQuiet(quiet bool) CLIOption {
return func(c *CLI) {
Quiet = quiet
}
}
// Initialize the CLI object
func Init(opts ...CLIOption) *CLI {
defaultFsFinder := finder.FileSystemFinderInit()
defaultReporter := reporter.StdoutReporter{}
cli := &CLI{
defaultFsFinder,
defaultReporter,
}
for _, opt := range opts {
opt(cli)
}
return cli
}
// The Run method performs the following actions:
// - Finds the calls the Find method from the Finder interface to
// return a list of files
// - Reads each file that was found
// - Calls the Validate method from the Validator interface to validate the file
// - Outputs the results using the Reporter
func (c CLI) Run() (int, error) {
errorFound := false
var reports []reporter.Report
foundFiles, err := c.Finder.Find()
if err != nil {
return 1, fmt.Errorf("Unable to find files: %v", err)
}
for _, fileToValidate := range foundFiles {
// read it
fileContent, err := os.ReadFile(fileToValidate.Path)
if err != nil {
return 1, fmt.Errorf("unable to read file: %v", err)
}
isValid, err := fileToValidate.FileType.Validator.Validate(fileContent)
if !isValid {
errorFound = true
}
report := reporter.Report{
FileName: fileToValidate.Name,
FilePath: fileToValidate.Path,
IsValid: isValid,
ValidationError: err,
}
reports = append(reports, report)
}
err = c.printReports(reports)
if err != nil {
fmt.Println("failed to report:", err)
errorFound = true
}
if errorFound {
return 1, nil
} else {
return 0, nil
}
}
// printReports prints the reports based on the specified grouping and reporter type.
// It returns any error encountered during the printing process.
func (c CLI) printReports(reports []reporter.Report) error {
if Quiet {
return nil
}
reportGroup, err := c.groupReports(reports, GroupOutput[0])
if err != nil {
return err
}
// Group the output if the user specified a group by option
// Length is equal to one when empty as it contains an empty string
if len(GroupOutput) == 1 && GroupOutput[0] != "" {
// Check reporter type to determine how to print
if _, ok := c.Reporter.(reporter.JsonReporter); ok {
reporter.PrintSingleGroupJson(reportGroup.(map[string][]reporter.Report))
} else {
reporter.PrintSingleGroupStdout(reportGroup.(map[string][]reporter.Report))
}
} else if len(GroupOutput) == 2 {
if _, ok := c.Reporter.(reporter.JsonReporter); ok {
reporter.PrintDoubleGroupJson(reportGroup.(map[string]map[string][]reporter.Report))
} else {
reporter.PrintDoubleGroupStdout(reportGroup.(map[string]map[string][]reporter.Report))
}
} else if len(GroupOutput) == 3 {
if _, ok := c.Reporter.(reporter.JsonReporter); ok {
reporter.PrintTripleGroupJson(reportGroup.(map[string]map[string]map[string][]reporter.Report))
} else {
reporter.PrintTripleGroupStdout(reportGroup.(map[string]map[string]map[string][]reporter.Report))
}
} else {
return c.Reporter.Print(reports)
}
return nil
}
// groupReports groups the given reports based on the specified grouping option.
// It returns the grouped reports and any error encountered during the grouping process.
func (c CLI) groupReports(reports []reporter.Report, group string) (interface{}, error) {
switch len(GroupOutput) {
case 1:
return GroupBySingle(reports, group)
case 2:
return GroupByDouble(reports, GroupOutput)
case 3:
return GroupByTriple(reports, GroupOutput)
default:
return nil, fmt.Errorf("Invalid number of group outputs: %d", len(GroupOutput))
}
}