github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/piperenv/templating.go (about)

     1  package piperenv
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strings"
     7  	"text/template"
     8  )
     9  
    10  const DEFAULT_START_DELIMITER = "{{"
    11  const DEFAULT_END_DELIMITER = "}}"
    12  
    13  // ParseTemplate allows to parse a template which contains references to the CPE
    14  // Utility functions make it simple to access specific parts of the CPE
    15  func (c *CPEMap) ParseTemplate(cpeTemplate string) (*bytes.Buffer, error) {
    16  	return c.ParseTemplateWithDelimiter(cpeTemplate, DEFAULT_START_DELIMITER, DEFAULT_END_DELIMITER)
    17  }
    18  
    19  func (c *CPEMap) ParseTemplateWithDelimiter(cpeTemplate string, startDelimiter string, endDelimiter string) (*bytes.Buffer, error) {
    20  	funcMap := template.FuncMap{
    21  		"cpe":         c.cpe,
    22  		"cpecustom":   c.custom,
    23  		"git":         c.git,
    24  		"imageDigest": c.imageDigest,
    25  		"imageTag":    c.imageTag,
    26  
    27  		// ToDo: add template function for artifacts
    28  		// This requires alignment on artifact handling before, though
    29  	}
    30  
    31  	tmpl, err := template.New("cpetemplate").Delims(startDelimiter, endDelimiter).Funcs(funcMap).Parse(cpeTemplate)
    32  	if err != nil {
    33  		return nil, fmt.Errorf("failed to parse cpe template '%v': %w", cpeTemplate, err)
    34  	}
    35  
    36  	tmplParams := struct {
    37  		CPE map[string]interface{}
    38  	}{
    39  		CPE: map[string]interface{}(*c),
    40  	}
    41  
    42  	var generated bytes.Buffer
    43  	err = tmpl.Execute(&generated, tmplParams)
    44  	if err != nil {
    45  		return nil, fmt.Errorf("failed to execute cpe template '%v': %w", cpeTemplate, err)
    46  	}
    47  
    48  	return &generated, nil
    49  }
    50  
    51  func (c *CPEMap) cpe(element string) string {
    52  	// ToDo: perform validity checks to allow only selected fields for now?
    53  	// This would allow a stable contract and could perform conversions in case a contract changes.
    54  
    55  	return fmt.Sprint(map[string]interface{}(*c)[element])
    56  }
    57  
    58  func (c *CPEMap) custom(element string) string {
    59  	return fmt.Sprint(map[string]interface{}(*c)[fmt.Sprintf("custom/%v", element)])
    60  }
    61  
    62  func (c *CPEMap) git(element string) string {
    63  	var el string
    64  	if element == "organization" || element == "repository" {
    65  		el = fmt.Sprint(map[string]interface{}(*c)[fmt.Sprintf("github/%v", element)])
    66  	} else {
    67  		el = fmt.Sprint(map[string]interface{}(*c)[fmt.Sprintf("git/%v", element)])
    68  	}
    69  	return el
    70  }
    71  
    72  func (c *CPEMap) imageDigest(imageName string) string {
    73  	digests, _ := map[string]interface{}(*c)["container/imageDigests"].([]interface{})
    74  	imageNames, _ := map[string]interface{}(*c)["container/imageNames"].([]interface{})
    75  	if len(digests) > 0 && len(digests) == len(imageNames) {
    76  		for i, image := range imageNames {
    77  			if fmt.Sprint(image) == imageName {
    78  				return fmt.Sprint(digests[i])
    79  			}
    80  		}
    81  	}
    82  	return ""
    83  }
    84  
    85  func (c *CPEMap) imageTag(imageName string) string {
    86  	nameTags, _ := map[string]interface{}(*c)["container/imageNameTags"].([]interface{})
    87  	for _, nameTag := range nameTags {
    88  		nt := strings.Split(fmt.Sprint(nameTag), ":")
    89  		if nt[0] == imageName {
    90  			return nt[1]
    91  		}
    92  	}
    93  	return ""
    94  }