github.com/tomwright/dasel@v1.27.3/internal/command/validate.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "github.com/spf13/cobra" 6 "io" 7 "path/filepath" 8 "sync" 9 ) 10 11 type validationFile struct { 12 File string 13 Parser string 14 } 15 16 type validationFileResult struct { 17 File validationFile 18 Pass bool 19 Error error 20 } 21 22 type validateOptions struct { 23 Files []validationFile 24 Reader io.Reader 25 Writer io.Writer 26 IncludeError bool 27 } 28 29 func runValidateCommand(opts validateOptions, cmd *cobra.Command) error { 30 fileCount := len(opts.Files) 31 32 wg := &sync.WaitGroup{} 33 wg.Add(fileCount) 34 35 results := make([]validationFileResult, fileCount) 36 37 for i, f := range opts.Files { 38 index := i 39 file := f 40 go func() { 41 defer wg.Done() 42 43 pass, err := validateFile(file) 44 results[index] = validationFileResult{ 45 File: file, 46 Pass: pass, 47 Error: err, 48 } 49 }() 50 } 51 52 wg.Wait() 53 54 failureCount := 0 55 for _, result := range results { 56 if !result.Pass { 57 failureCount++ 58 } 59 } 60 61 // Set up our output writer if one wasn't provided. 62 if opts.Writer == nil { 63 if failureCount > 0 { 64 opts.Writer = cmd.OutOrStderr() 65 } else { 66 opts.Writer = cmd.OutOrStdout() 67 } 68 } 69 70 for _, result := range results { 71 outputString := "" 72 73 if result.Pass { 74 outputString += "pass" 75 } else { 76 outputString += "fail" 77 } 78 79 outputString += " " + result.File.File 80 81 if opts.IncludeError && result.Error != nil { 82 outputString += " " + result.Error.Error() 83 } 84 85 if _, err := fmt.Fprintln(opts.Writer, outputString); err != nil { 86 return fmt.Errorf("could not write output: %w", err) 87 } 88 } 89 90 if failureCount > 0 { 91 return fmt.Errorf("%d files failed validation", failureCount) 92 } 93 return nil 94 } 95 96 func validateFile(file validationFile) (bool, error) { 97 readParser, err := getReadParser(file.File, file.Parser, "") 98 if err != nil { 99 return false, err 100 } 101 _, err = getRootNode(getRootNodeOpts{ 102 File: file.File, 103 Parser: readParser, 104 Reader: nil, 105 }, nil) 106 if err != nil { 107 return false, err 108 } 109 110 return true, nil 111 } 112 113 func validateCommand() *cobra.Command { 114 var includeErrorFlag bool 115 116 cmd := &cobra.Command{ 117 Use: "validate <file> <file> <file>", 118 Short: "Validate a list of files.", 119 RunE: func(cmd *cobra.Command, args []string) error { 120 files := make([]validationFile, 0) 121 for _, a := range args { 122 matches, err := filepath.Glob(a) 123 if err != nil { 124 return err 125 } 126 127 for _, m := range matches { 128 files = append(files, validationFile{ 129 File: m, 130 Parser: "", 131 }) 132 } 133 } 134 135 return runValidateCommand(validateOptions{ 136 Files: files, 137 IncludeError: includeErrorFlag, 138 }, cmd) 139 }, 140 } 141 142 cmd.Flags().BoolVar(&includeErrorFlag, "include-error", true, "Show error/validation information") 143 144 _ = cmd.MarkFlagFilename("file") 145 146 return cmd 147 }