github.com/JarrahG/buffalocli@v0.0.0-20230801092127-b85bfd5d395a/internal/genny/build/validate.go (about)

     1  package build
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"html/template"
     7  	"io/fs"
     8  	"strings"
     9  
    10  	"github.com/gobuffalo/genny/v2"
    11  	"github.com/gobuffalo/plush/v4"
    12  )
    13  
    14  // TemplateValidator is given a file and returns an
    15  // effort if there is a template validation error
    16  // with the template
    17  type TemplateValidator func(f genny.File) error
    18  
    19  // ValidateTemplates returns a genny.RunFn that will walk the
    20  // given filesystem and run each of the files found through each of the
    21  // template validators
    22  func ValidateTemplates(fsys fs.FS, tvs []TemplateValidator) genny.RunFn {
    23  	if len(tvs) == 0 {
    24  		return func(r *genny.Runner) error {
    25  			return nil
    26  		}
    27  	}
    28  	return func(r *genny.Runner) error {
    29  		var errs []string
    30  		err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
    31  			if err != nil {
    32  				return err
    33  			}
    34  
    35  			if d.IsDir() {
    36  				return nil
    37  			}
    38  
    39  			b, err := fsys.Open(path)
    40  			if err != nil {
    41  				return err
    42  			}
    43  			f := genny.NewFile(path, b)
    44  			for _, tv := range tvs {
    45  				err := safeRun(func() {
    46  					if err := tv(f); err != nil {
    47  						errs = append(errs, fmt.Sprintf("template error in file %s: %s", path, err.Error()))
    48  					}
    49  				})
    50  				if err != nil {
    51  					return err
    52  				}
    53  			}
    54  
    55  			return nil
    56  		})
    57  		if err != nil {
    58  			return err
    59  		}
    60  		if len(errs) == 0 {
    61  			return nil
    62  		}
    63  		return fmt.Errorf(strings.Join(errs, "\n"))
    64  	}
    65  }
    66  
    67  // PlushValidator validates the file is a valid
    68  // Plush file if the extension is .md, .html, or .plush
    69  func PlushValidator(f genny.File) error {
    70  	if !genny.HasExt(f, ".html", ".md", ".plush") {
    71  		return nil
    72  	}
    73  	_, err := plush.Parse(f.String())
    74  	return err
    75  }
    76  
    77  // GoTemplateValidator validates the file is a
    78  // valid Go text/template file if the extension
    79  // is .tmpl
    80  func GoTemplateValidator(f genny.File) error {
    81  	if !genny.HasExt(f, ".tmpl") {
    82  		return nil
    83  	}
    84  	t := template.New(f.Name())
    85  	_, err := t.Parse(f.String())
    86  	return err
    87  }
    88  
    89  // safeRun the function safely knowing that if it panics
    90  // the panic will be caught and returned as an error
    91  func safeRun(fn func()) (err error) {
    92  	defer func() {
    93  		if ex := recover(); ex != nil {
    94  			if e, ok := ex.(error); ok {
    95  				err = e
    96  				return
    97  			}
    98  			err = errors.New(fmt.Sprint(ex))
    99  		}
   100  	}()
   101  
   102  	fn()
   103  	return nil
   104  }