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  }