github.com/hairyhenderson/gomplate/v3@v3.11.7/gomplate.go (about)

     1  // Package gomplate is a template renderer which supports a number of datasources,
     2  // and includes hundreds of built-in functions.
     3  package gomplate
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"fmt"
     9  	"path/filepath"
    10  	"strings"
    11  	"text/template"
    12  	"time"
    13  
    14  	"github.com/hairyhenderson/gomplate/v3/data"
    15  	"github.com/hairyhenderson/gomplate/v3/internal/config"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  // RunTemplates - run all gomplate templates specified by the given configuration
    20  //
    21  // Deprecated: use the Renderer interface instead
    22  func RunTemplates(o *Config) error {
    23  	cfg, err := o.toNewConfig()
    24  	if err != nil {
    25  		return err
    26  	}
    27  	return Run(context.Background(), cfg)
    28  }
    29  
    30  // Run all gomplate templates specified by the given configuration
    31  func Run(ctx context.Context, cfg *config.Config) error {
    32  	Metrics = newMetrics()
    33  	defer runCleanupHooks()
    34  
    35  	// apply defaults before validation
    36  	cfg.ApplyDefaults()
    37  
    38  	err := cfg.Validate()
    39  	if err != nil {
    40  		return fmt.Errorf("failed to validate config: %w\n%+v", err, cfg)
    41  	}
    42  
    43  	funcMap := template.FuncMap{}
    44  	err = bindPlugins(ctx, cfg, funcMap)
    45  	if err != nil {
    46  		return err
    47  	}
    48  
    49  	// if a custom Stdin is set in the config, inject it into the context now
    50  	ctx = data.ContextWithStdin(ctx, cfg.Stdin)
    51  
    52  	opts := optionsFromConfig(cfg)
    53  	opts.Funcs = funcMap
    54  	tr := NewRenderer(opts)
    55  
    56  	start := time.Now()
    57  
    58  	namer := chooseNamer(cfg, tr)
    59  	tmpl, err := gatherTemplates(ctx, cfg, namer)
    60  	Metrics.GatherDuration = time.Since(start)
    61  	if err != nil {
    62  		Metrics.Errors++
    63  		return fmt.Errorf("failed to gather templates for rendering: %w", err)
    64  	}
    65  	Metrics.TemplatesGathered = len(tmpl)
    66  
    67  	err = tr.RenderTemplates(ctx, tmpl)
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	return nil
    73  }
    74  
    75  func chooseNamer(cfg *config.Config, tr *Renderer) func(context.Context, string) (string, error) {
    76  	if cfg.OutputMap == "" {
    77  		return simpleNamer(cfg.OutputDir)
    78  	}
    79  	return mappingNamer(cfg.OutputMap, tr)
    80  }
    81  
    82  func simpleNamer(outDir string) func(ctx context.Context, inPath string) (string, error) {
    83  	return func(_ context.Context, inPath string) (string, error) {
    84  		outPath := filepath.Join(outDir, inPath)
    85  		return filepath.Clean(outPath), nil
    86  	}
    87  }
    88  
    89  func mappingNamer(outMap string, tr *Renderer) func(context.Context, string) (string, error) {
    90  	return func(ctx context.Context, inPath string) (string, error) {
    91  		tr.data.Ctx = ctx
    92  		tcontext, err := createTmplContext(ctx, tr.tctxAliases, tr.data)
    93  		if err != nil {
    94  			return "", err
    95  		}
    96  
    97  		// add '.in' to the template context and preserve the original context
    98  		// in '.ctx'
    99  		tctx := &tmplctx{}
   100  		//nolint: gocritic
   101  		switch c := tcontext.(type) {
   102  		case *tmplctx:
   103  			for k, v := range *c {
   104  				if k != "in" && k != "ctx" {
   105  					(*tctx)[k] = v
   106  				}
   107  			}
   108  		}
   109  		(*tctx)["ctx"] = tcontext
   110  		(*tctx)["in"] = inPath
   111  
   112  		out := &bytes.Buffer{}
   113  		err = tr.renderTemplatesWithData(ctx,
   114  			[]Template{{Name: "<OutputMap>", Text: outMap, Writer: out}}, tctx)
   115  		if err != nil {
   116  			return "", errors.Wrapf(err, "failed to render outputMap with ctx %+v and inPath %s", tctx, inPath)
   117  		}
   118  
   119  		return filepath.Clean(strings.TrimSpace(out.String())), nil
   120  	}
   121  }