fuzzyworld

template / commit

Consolidated template creation.

fd0a4446f86d178d98c06b20a41892ff182b45eb · Pavel Safronov · 2023-04-02 18:02:54 -0700 · parents 8ede9683837b

Consolidated template creation.
Added --script parameter, allowing templating of a script method: template --script "echo {{.YYYY_MM_DD}}"
Minor test change.
 README.md          |  26 +++++++++--
 file.go            | 129 ++++++++++++++++++++++++---------------------------
 go.mod             |   7 ++-
 go.sum             |  15 ++----
 main.go            |  51 ++++++++++++++-------
 name_pattern.go    | 132 +++++++++++++++++++++++++----------------------------
 postscript.go      |  61 +++++++++++--------------
 postscript_test.go |  87 +++++++++++++++++------------------
 templating.go      |  34 ++++++++++++++
 9 files changed, 285 insertions(+), 257 deletions(-)

diff --git a/README.md b/README.md
index 11bba29..02b3ac0 100644
--- a/README.md
+++ b/README.md
@@ -94,6 +94,26 @@ Creating a folder:
 template -d "{{.Year}}-{{.Month}}-{{.Day}}-{{.ProjectName}}.txt" Test123
 ```
 
+### Using a script template directly

+

+You can also specify a template script:

+

+```sh

+template --script "echo 'Hello from {{.YYYY_MM_DD}}!'"

+```

+

+will result in:

+

+```txt

+> template --script "echo 'Hello from {{.YYYY_MM_DD}}!'"

+Project name: 

+Loaded config from C:\Users\pavel\.template.yaml

+Loaded user config from C:\Users\pavel\.template.user.yaml, combining with global config

+Executing post script: cmd /c echo 'Hello from 2023-04-02!'

+Post script output: 'Hello from 2023-04-02!'

+

+```

+

 ## Examples
 
 ### Use `daily` profile to create a new file
@@ -141,19 +161,19 @@ curl -X GET "https://httpbin.org/delay/3" -H  "accept: application/json" 2>&1 |
 ### Specify file pattern and project name
 
 ```sh
-template -f "{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}-{{.ProjectName}}.txt" test

+template -file "{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}-{{.ProjectName}}.txt" test

 ```
 
 ### Specify file pattern, project name, and piped input
 
 ```sh
-history | template -f "{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}-{{.ProjectName}}.txt" "Hi all!" 

+history | template -file "{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}-{{.ProjectName}}.txt" "Hi all!" 

 ```
 
 ### Specify folder pattern and project name
 
 ```sh
-template -d "{{.Year}}-{{.Month}}-{{.Day}}-{{.ProjectName}}" test123

+template -dir "{{.Year}}-{{.Month}}-{{.Day}}-{{.ProjectName}}" test123

 ```
 
 ## Requirements
diff --git a/file.go b/file.go
index 2b451fe..1f1764b 100644
--- a/file.go
+++ b/file.go
@@ -1,70 +1,59 @@
-package main
-
-import (
-	"bufio"
-	"fmt"
-	"os"
-	"strings"
-	"text/template"
-
-	log "github.com/sirupsen/logrus"
-)
-
-func createFile(
-	prePatternData PrePatternData,
-	fileTemplate ParameterizedText,
-	fullPath string,
-	pipeInputScanner *bufio.Scanner) error {
-
-	useTemplate := fileTemplate != ""
-	useInputPipe := pipeInputScanner != nil
-
-	if useInputPipe {
-		log.WithFields(log.Fields{"fullPath": fullPath}).Debug("Creating file from input pipe content", fullPath)
-
-		file, err := monkey.OSCreate(fullPath)
-		if err != nil {
-			return fmt.Errorf("error creating file: %v", err)
-		}
-		defer file.Close()
-
-		writer := bufio.NewWriter(file)
-		for pipeInputScanner.Scan() {
-			line := pipeInputScanner.Text()
-			_, err := writer.WriteString(line + "\n")
-			if err != nil {
-				return fmt.Errorf("error writing file: %v", err)
-			}
-		}
-		writer.Flush()
-	} else if useTemplate {
-		postPatternData := createPostPatternData(fullPath, prePatternData)
-		log.WithFields(log.Fields{"fullPath": fullPath}).Debug("Creating file from template string\n", fullPath)
-
-		// parse template
-		template, err := template.New("text-template").Parse(string(fileTemplate))
-		if err != nil {
-			return fmt.Errorf("error parsing template text: %v", err)
-		}
-
-		// create output string
-		sb := new(strings.Builder)
-		err = template.Execute(sb, postPatternData)
-		if err != nil {
-			return fmt.Errorf("error creating templated file: %v", err)
-		}
-
-		templateString := sb.String()
-		err = monkey.OSWriteFile(fullPath, []byte(templateString), os.ModePerm)
-		if err != nil {
-			return fmt.Errorf("error writing file: %v", err)
-		}
-	} else {
-		log.WithFields(log.Fields{"fullPath": fullPath}).Debug("Creating empty file", fullPath)
-		err := monkey.OSWriteFile(fullPath, []byte{}, os.ModePerm)
-		if err != nil {
-			return fmt.Errorf("error writing file: %v", err)
-		}
-	}
-	return nil
-}
+package main

+

+import (

+	"bufio"

+	"fmt"

+	"os"

+

+	log "github.com/sirupsen/logrus"

+)

+

+func createFile(

+	prePatternData PrePatternData,

+	fileTemplate ParameterizedText,

+	fullPath string,

+	pipeInputScanner *bufio.Scanner) error {

+

+	useTemplate := fileTemplate != ""

+	useInputPipe := pipeInputScanner != nil

+

+	if useInputPipe {

+		log.WithFields(log.Fields{"fullPath": fullPath}).Debug("Creating file from input pipe content", fullPath)

+

+		file, err := monkey.OSCreate(fullPath)

+		if err != nil {

+			return fmt.Errorf("error creating file: %v", err)

+		}

+		defer file.Close()

+

+		writer := bufio.NewWriter(file)

+		for pipeInputScanner.Scan() {

+			line := pipeInputScanner.Text()

+			_, err := writer.WriteString(line + "\n")

+			if err != nil {

+				return fmt.Errorf("error writing file: %v", err)

+			}

+		}

+		writer.Flush()

+	} else if useTemplate {

+		postPatternData := createPostPatternData(fullPath, prePatternData)

+		log.WithFields(log.Fields{"fullPath": fullPath}).Debug("Creating file from template string\n", fullPath)

+

+		templateString, err := parseAndExecTemplate(newTemplate(), fileTemplate, postPatternData)

+		if err != nil {

+			return fmt.Errorf("error creating templated file: %v", err)

+		}

+

+		err = monkey.OSWriteFile(fullPath, []byte(templateString), os.ModePerm)

+		if err != nil {

+			return fmt.Errorf("error writing file: %v", err)

+		}

+	} else {

+		log.WithFields(log.Fields{"fullPath": fullPath}).Debug("Creating empty file", fullPath)

+		err := monkey.OSWriteFile(fullPath, []byte{}, os.ModePerm)

+		if err != nil {

+			return fmt.Errorf("error writing file: %v", err)

+		}

+	}

+	return nil

+}

diff --git a/go.mod b/go.mod
index c8adc7c..6cc1a02 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,6 @@ module gitlab.com/PavelSafronov/template
 go 1.19
 
 require (
-	github.com/Masterminds/sprig/v3 v3.2.2
 	github.com/sirupsen/logrus v1.9.0
 	github.com/stretchr/testify v1.8.0
 	github.com/urfave/cli/v2 v2.16.3
@@ -11,9 +10,11 @@ require (
 	gopkg.in/yaml.v3 v3.0.1
 )
 
+require github.com/Masterminds/semver v1.5.0 // indirect
+
 require (
 	github.com/Masterminds/goutils v1.1.1 // indirect
-	github.com/Masterminds/semver/v3 v3.1.1 // indirect
+	github.com/Masterminds/sprig v2.22.0+incompatible
 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/google/uuid v1.1.1 // indirect
@@ -23,8 +24,6 @@ require (
 	github.com/mitchellh/reflectwalk v1.0.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
-	github.com/shopspring/decimal v1.2.0 // indirect
-	github.com/spf13/cast v1.3.1 // indirect
 	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
 	golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 // indirect
 	golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
diff --git a/go.sum b/go.sum
index 35dfbc7..bb4b6d8 100644
--- a/go.sum
+++ b/go.sum
@@ -1,9 +1,9 @@
 github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
 github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
-github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
-github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
+github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
+github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
+github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
 github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
 github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -23,16 +23,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
-github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
-github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
@@ -55,7 +49,6 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/main.go b/main.go
index 5392e2c..4d50cce 100644
--- a/main.go
+++ b/main.go
@@ -27,6 +27,7 @@ type ArgumentValues struct {
 	projectName    string
 	fileTemplate   string
 	dirTemplate    string
+	scriptTemplate string
 	configFilePath string
 	userConfigPath string
 	extrasFilePath string
@@ -77,6 +78,13 @@ func main() {
 				Usage:       "folder pattern to use to create a directory",
 				Destination: &argumentValues.dirTemplate,
 			},
+			&cli.StringFlag{
+				Name:        "script",
+				Aliases:     []string{"s"},
+				Value:       "",
+				Usage:       "templated script to run in the shell",
+				Destination: &argumentValues.scriptTemplate,
+			},
 			&cli.StringFlag{
 				Name:        "name",
 				Aliases:     []string{"n"},
@@ -252,7 +260,7 @@ func createSettings(
 
 	log.WithFields(log.Fields{"args": args}).Debug("Args parsed")
 
-	skipProfile := len(settings.fileTemplate) > 0 || len(settings.dirTemplate) > 0
+	skipProfile := len(settings.fileTemplate) > 0 || len(settings.dirTemplate) > 0 || len(settings.scriptTemplate) > 0
 	currentParamIndex := 0
 
 	if !skipProfile {
@@ -354,24 +362,33 @@ func findProfile(settings Settings) (Profile, error) {
 	var profile Profile = Profile{}
 	var err error
 	config := settings.config
-	createTempProfile := len(settings.fileTemplate) > 0 || len(settings.dirTemplate) > 0
+	createTempProfile := len(settings.fileTemplate) > 0 || len(settings.dirTemplate) > 0 || len(settings.scriptTemplate) > 0
 
 	if createTempProfile {
-		profileType := FileType
-		if len(settings.dirTemplate) > 0 {
-			profileType = FolderType
-		}
-		patterns := []ParameterizedText{}
-		if len(settings.fileTemplate) > 0 {
-			patterns = append(patterns, ParameterizedText(settings.fileTemplate))
-		} else if len(settings.dirTemplate) > 0 {
-			patterns = append(patterns, ParameterizedText(settings.dirTemplate))
-		}
-		profile = Profile{
-			Name:         "temp",
-			Description:  "temp",
-			Type:         profileType,
-			NamePatterns: patterns,
+		if len(settings.scriptTemplate) > 0 {
+			profile = Profile{
+				Name:        "temp",
+				Description: "temp-script-profile",
+				Type:        ScriptType,
+				PostScripts: []ParameterizedText{ParameterizedText(settings.scriptTemplate)},
+			}
+		} else {
+			profileType := FileType
+			if len(settings.dirTemplate) > 0 {
+				profileType = FolderType
+			}
+			patterns := []ParameterizedText{}
+			if len(settings.fileTemplate) > 0 {
+				patterns = append(patterns, ParameterizedText(settings.fileTemplate))
+			} else if len(settings.dirTemplate) > 0 {
+				patterns = append(patterns, ParameterizedText(settings.dirTemplate))
+			}
+			profile = Profile{
+				Name:         "temp",
+				Description:  fmt.Sprintf("temp-%s-profile", profileType),
+				Type:         profileType,
+				NamePatterns: patterns,
+			}
 		}
 	} else {
 		if settings.profile == "" {
diff --git a/name_pattern.go b/name_pattern.go
index 0c7dde8..da8db8e 100644
--- a/name_pattern.go
+++ b/name_pattern.go
@@ -1,71 +1,61 @@
-package main
-
-import (
-	"errors"
-	"fmt"
-	"strings"
-	"text/template"
-	"time"
-
-	"github.com/Masterminds/sprig/v3"
-)
-
-func createNewNameForPatterns(
-	now time.Time,
-	patternData PrePatternData,
-	projectName string,
-	namePatterns []ParameterizedText,
-	extras map[string]string,
-	validator func(newName string) bool) (string, error) {
-	for index, namePattern := range namePatterns {
-
-		startingVersion := 1
-		invokeCount := 0
-		funcMap := template.FuncMap{
-			"getVersion": func() int {
-				invokeCount++
-				return startingVersion
-			},
-		}
-		template := template.New("template-name").Funcs(funcMap)
-		template = template.Funcs(sprig.FuncMap())
-
-		for {
-
-			template, err := template.Parse(string(namePattern))
-			if err != nil {
-				return "", fmt.Errorf("error parsing name pattern %d: %w", index, err)
-			}
-
-			sb := new(strings.Builder)
-			err = template.Execute(sb, patternData)
-			if err != nil {
-				return "", fmt.Errorf("error executing name pattern %d: %w", index, err)
-			}
-
-			newName := sb.String()
-			isValid := validator(newName)
-			useIndex := invokeCount > 0
-			isLastPattern := index == len(namePatterns)-1
-
-			// if new name is valid, use this name
-			if isValid {
-				return newName, nil
-			}
-
-			// if index is not being used (template did not invoke getVersion)
-			// then we're done
-			if !useIndex {
-				break
-			}
-
-			// if getVersion was used, but this isn't the last pattern, report an error
-			if useIndex && !isLastPattern {
-				return "", errors.New("cannot use function getVersion in a pattern that is not the last pattern")
-			}
-
-			startingVersion++
-		}
-	}
-	return "", errors.New("couldn't find a new name")
-}
+package main

+

+import (

+	"errors"

+	"fmt"

+	"text/template"

+	"time"

+)

+

+func createNewNameForPatterns(

+	now time.Time,

+	patternData PrePatternData,

+	projectName string,

+	namePatterns []ParameterizedText,

+	extras map[string]string,

+	validator func(newName string) bool) (string, error) {

+	for index, namePattern := range namePatterns {

+

+		startingVersion := 1

+		invokeCount := 0

+		funcMap := template.FuncMap{

+			"getVersion": func() int {

+				invokeCount++

+				return startingVersion

+			},

+		}

+		t := newTemplate()

+		t = t.Funcs(funcMap)

+

+		for {

+

+			newName, err := parseAndExecTemplate(t, namePattern, patternData)

+			if err != nil {

+				return "", fmt.Errorf("error templating name pattern %d: %w", index, err)

+			}

+

+			isValid := validator(newName)

+			useIndex := invokeCount > 0

+			isLastPattern := index == len(namePatterns)-1

+

+			// if new name is valid, use this name

+			if isValid {

+				return newName, nil

+			}

+

+			// if index is not being used (template did not invoke getVersion)

+			// then we're done

+			if !useIndex {

+				break

+			}

+

+			// if getVersion was used, but this isn't the last pattern, report an error

+			if useIndex && !isLastPattern {

+				return "", errors.New("cannot use function getVersion in a pattern that is not the last pattern")

+			}

+

+			startingVersion++

+		}

+	}

+	return "", errors.New("couldn't find a new name")

+}

diff --git a/postscript.go b/postscript.go
index 23d0f6c..a2f353f 100644
--- a/postscript.go
+++ b/postscript.go
@@ -1,35 +1,26 @@
-package main
-
-import (
-	"fmt"
-	"strings"
-	"text/template"
-)
-
-func createPostScriptArrays(
-	profile Profile,
-	postPatternData PostPatternData) ([]string, error) {
-	array := make([]string, 0)
-
-	if profile.PostScripts == nil || len(profile.PostScripts) == 0 {
-		return nil, fmt.Errorf("no post scripts specified")
-	}
-
-	for _, postScriptPattern := range profile.PostScripts {
-		template, err := template.New("postscript").Parse(string(postScriptPattern))
-		if err != nil {
-			return nil, err
-		}
-
-		sb := new(strings.Builder)
-		err = template.Execute(sb, postPatternData)
-		if err != nil {
-			return nil, err
-		}
-
-		postScript := sb.String()
-		array = append(array, postScript)
-	}
-
-	return array, nil
-}
+package main

+

+import (

+	"fmt"

+)

+

+func createPostScriptArrays(

+	profile Profile,

+	postPatternData PostPatternData) ([]string, error) {

+	array := make([]string, 0)

+

+	if profile.PostScripts == nil || len(profile.PostScripts) == 0 {

+		return nil, fmt.Errorf("no post scripts specified")

+	}

+

+	for _, postScriptPattern := range profile.PostScripts {

+		postScript, err := parseAndExecTemplate(newTemplate(), postScriptPattern, postPatternData)

+		if err != nil {

+			return nil, fmt.Errorf("error parsing post script: %w", err)

+		}

+

+		array = append(array, postScript)

+	}

+

+	return array, nil

+}

diff --git a/postscript_test.go b/postscript_test.go
index e4e4fae..a1f9b98 100644
--- a/postscript_test.go
+++ b/postscript_test.go
@@ -1,46 +1,41 @@
-package main
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestCreatePostScriptArrays(t *testing.T) {
-	testFailure := func(profile Profile) {
-		_, err := createPostScriptArrays(profile, PostPatternData{FullPath: "test"})
-		assert.NotNil(t, err, "Expected to fail to create post script arrays, but succeeded")
-	}
-	testSuccess := func(profile Profile) {
-		postscripts, err := createPostScriptArrays(profile, PostPatternData{
-			FullPath: "test",
-			PrePatternData: PrePatternData{
-				Extras: map[string]string{"foo": "bar"},
-			},
-		})
-		assert.Nil(t, err, "Error creating postscript array")
-		assert.Equal(t, postscripts, []string{"echo \"test\"-bar "})
-	}
-
-	testSuccess(Profile{
-		PostScripts: []ParameterizedText{
-			"echo \"{{.FullPath}}\"-{{.Extras.foo}} ",
-		},
-	})
-	testFailure(Profile{
-		PostScripts: nil,
-	})
-	testFailure(Profile{
-		PostScripts: []ParameterizedText{},
-	})
-	testFailure(Profile{
-		PostScripts: []ParameterizedText{
-			"echo \"{{.Name\"",
-		},
-	})
-	testFailure(Profile{
-		PostScripts: []ParameterizedText{
-			"echo \"{{.NameUnknown}}\"",
-		},
-	})
-}
+package main

+

+import (

+	"testing"

+

+	"github.com/stretchr/testify/assert"

+)

+

+func TestCreatePostScriptArrays(t *testing.T) {

+	callCreatePostScriptArrays := func(postScripts []ParameterizedText) ([]string, error) {

+		return createPostScriptArrays(

+			Profile{PostScripts: postScripts},

+			PostPatternData{

+				FullPath: "test",

+				PrePatternData: PrePatternData{

+					Extras: map[string]string{"foo": "bar"},

+				},

+			})

+	}

+

+	arr, err := callCreatePostScriptArrays([]ParameterizedText{"echo \"{{.FullPath}}\"-{{.Extras.foo}} "})

+	assert.Nil(t, err, "Error creating postscript array")

+	assert.Equal(t, 1, len(arr))

+	assert.Equal(t, arr[0], "echo \"test\"-bar ")

+

+	arr, err = callCreatePostScriptArrays(nil)

+	assert.NotNil(t, err, "nil postscripts should fail")

+	assert.Nil(t, arr)

+

+	arr, err = callCreatePostScriptArrays([]ParameterizedText{})

+	assert.NotNil(t, err, "empty postscripts should fail")

+	assert.Nil(t, arr)

+

+	arr, err = callCreatePostScriptArrays([]ParameterizedText{"echo \"{{.Name"})

+	assert.NotNil(t, err, "invalid template should fail")

+	assert.Nil(t, arr)

+

+	arr, err = callCreatePostScriptArrays([]ParameterizedText{"echo \"{{.NameUnknown}}\""})

+	assert.NotNil(t, err, "invalid template variable should fail")

+	assert.Nil(t, arr)

+}

diff --git a/templating.go b/templating.go
new file mode 100644
index 0000000..ed70933
--- /dev/null
+++ b/templating.go
@@ -0,0 +1,34 @@
+package main

+

+import (

+	"fmt"

+	"strings"

+	"text/template"

+

+	"github.com/Masterminds/sprig"

+)

+

+func newTemplate() *template.Template {

+	t := template.New("text-template")

+	t = t.Option("missingkey=error")

+	t = t.Funcs(sprig.FuncMap())

+	return t

+}

+

+func parseAndExecTemplate(t *template.Template, text ParameterizedText, data any) (string, error) {

+	// parse template

+	template, err := t.Parse(string(text))

+	if err != nil {

+		return "", fmt.Errorf("error parsing template text: %v", err)

+	}

+

+	// create output string

+	sb := new(strings.Builder)

+	err = template.Execute(sb, data)

+	if err != nil {

+		return "", fmt.Errorf("error creating templated file: %v", err)

+	}

+

+	templateString := sb.String()

+	return templateString, nil

+}