fuzzyworld

template / commit

Merge branch 'extras' into 'main'

32035957d746268f33cecb16f22caf477da16a46 · Pavel S · 2022-10-05 22:33:34 +0000 · parents 2c2e12410009 55c36f6a80d1

Merge branch 'extras' into 'main'

Add support for user-defined template variables

See merge request fuzzy-rp/template!2
 .gitignore           |  1 +
 .vscode/launch.json  | 38 +++++++++++++++++--------------
 config.go            | 43 +++++++++++++++++++++++++++++++++++
 extras-test.yaml     |  2 ++
 extras.go            | 24 ++++++++++++++++++++
 extras_test.go       | 52 ++++++++++++++++++++++++++++++++++++++++++
 file.go              | 14 +++++++-----
 go.mod               |  3 +++
 go.sum               | 11 +++++++++
 main.go              | 64 ++++++++++++++++++++++++++++++++--------------------
 name_pattern.go      |  4 +++-
 name_pattern_test.go | 34 ++++++++++++++++------------
 postscript.go        | 12 ++++++----
 profile.go           | 10 ++++----
 14 files changed, 240 insertions(+), 72 deletions(-)

diff --git a/.gitignore b/.gitignore
index c47543f..984b600 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 .git
 template.exe
+template
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 99d1872..addb872 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -4,6 +4,14 @@
     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
     "version": "0.2.0",
     "configurations": [
+        {
+            "name": "Launch tests",
+            "type": "go",
+            "request": "launch",
+            "mode": "test",
+            "program": ".",
+            "args": []
+        },
         {
             "name": "Clean install",
             "type": "PowerShell",
@@ -17,6 +25,7 @@
             "request": "launch",
             "mode": "auto",
             "program": ".",
+            "args": ["--default-config"]
         },
         {
             "name": "Run: template blog",
@@ -24,9 +33,7 @@
             "request": "launch",
             "mode": "auto",
             "program": ".",
-            "args": [
-                "blog"
-            ]
+            "args": ["blog", "--default-config"]
         },
         {
             "name": "Run: template daily",
@@ -34,9 +41,7 @@
             "request": "launch",
             "mode": "auto",
             "program": ".",
-            "args": [
-                "daily"
-            ]
+            "args": ["daily", "--default-config"]
         },
         {
             "name": "Run: template work",
@@ -44,9 +49,7 @@
             "request": "launch",
             "mode": "auto",
             "program": ".",
-            "args": [
-                "work"
-            ]
+            "args": ["work", "--default-config"]
         },
         {
             "name": "Run: template --profile work --project testProj",
@@ -58,7 +61,8 @@
                 "--profile",
                 "work",
                 "--project",
-                "testProj"
+                "testProj",
+                "--default-config"
             ]
         },
         {
@@ -67,10 +71,7 @@
             "request": "launch",
             "mode": "auto",
             "program": ".",
-            "args": [
-                "note",
-                "whoa"
-            ]
+            "args": ["note", "whoa", "--default-config"]
         },
         {
             "name": "Run: template test blah",
@@ -79,11 +80,14 @@
             "mode": "auto",
             "program": ".",
             "args": [
+                "--profile",
                 "test",
+                "--name",
                 "blah",
-                "--value1=1",
-                "--value2=two"
+                "--extras-yaml",
+                "extras-test.yaml",
+                "--default-config"
             ]
         }
     ]
-}
\ No newline at end of file
+}
diff --git a/config.go b/config.go
index 2df6583..7bc8769 100644
--- a/config.go
+++ b/config.go
@@ -196,6 +196,8 @@ Today's notes
 				PostScripts: []string{
 					"echo \"Name={{.Name}}\"",
 					"echo \"Path={{.Path}}\"",
+					"echo \"Value1={{.Extras.value1}}\"",
+					"echo \"Value2={{.Extras.value2}}\"",
 				},
 			},
 		},
@@ -233,6 +235,9 @@ func validateConfig(config Config) error {
 		if profile.Type != FileType && profile.FileTemplatePath != "" {
 			return fmt.Errorf("file template path is not supported for profile %s, which has Type=%s", profile.Name, profile.Type)
 		}
+		if profile.Type != ScriptType && profile.NamePatterns != nil && len(profile.NamePatterns) > 1 {
+			return fmt.Errorf("multiple name patterns are not supported for profile %s, which has Type=%s", profile.Name, profile.Type)
+		}
 		if profile.ScriptShell == "" && profile.PostScripts != nil && len(profile.PostScripts) > 0 {
 			return fmt.Errorf("script shell is required for profile %s", profile.Name)
 		}
@@ -269,3 +274,41 @@ func saveConfig(path string, config Config) error {
 
 	return nil
 }
+
+func getOrCreateConfig(configFilePath string) (Config, error) {
+	emptyConfig := Config{}
+
+	fullConfigPath, err := getFullPath(configFilePath)
+	if err != nil {
+		return emptyConfig, fmt.Errorf("failed to get full path for config file %v: %v", configFilePath, err)
+	}
+
+	// try and load config
+	config, err := loadConfig(fullConfigPath)
+	if err != nil {
+		fmt.Printf("No config present at '%v', creating and using sample config\n", fullConfigPath)
+
+		// create config and save
+		err := saveConfig(fullConfigPath, defaultConfig())
+		if err != nil {
+			return emptyConfig, fmt.Errorf("error creating config: %v", err)
+		}
+
+		// load config
+		config, err = loadConfig(fullConfigPath)
+		if err != nil {
+			return emptyConfig, fmt.Errorf("error loading config: %v", err)
+		}
+	} else {
+		// log successful load
+		fmt.Printf("Config loaded from '%v'\n", fullConfigPath)
+	}
+
+	// validate config
+	err = validateConfig(config)
+	if err != nil {
+		return emptyConfig, fmt.Errorf("error validating config: %v", err)
+	}
+
+	return config, nil
+}
diff --git a/extras-test.yaml b/extras-test.yaml
new file mode 100644
index 0000000..b63838a
--- /dev/null
+++ b/extras-test.yaml
@@ -0,0 +1,2 @@
+value1: "1"
+value2: "two"
diff --git a/extras.go b/extras.go
new file mode 100644
index 0000000..d7a0293
--- /dev/null
+++ b/extras.go
@@ -0,0 +1,24 @@
+package main
+
+import (
+	"os"
+
+	"gopkg.in/yaml.v3"
+)
+
+func loadExtras(path string) (map[string]string, error) {
+	emptyMap := make(map[string]string)
+
+	file, error := os.ReadFile(path)
+	if error != nil {
+		return emptyMap, error
+	}
+
+	result := make(map[string]string)
+	error = yaml.Unmarshal(file, &result)
+	if error != nil {
+		return emptyMap, error
+	}
+
+	return result, nil
+}
diff --git a/extras_test.go b/extras_test.go
new file mode 100644
index 0000000..9a72542
--- /dev/null
+++ b/extras_test.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+	"os"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"gopkg.in/yaml.v3"
+)
+
+func TestExtras(t *testing.T) {
+	// setup code
+	extras := map[string]string{
+		"version":  "1",
+		"id":       "123",
+		"customer": "abc",
+	}
+
+	file, error := os.CreateTemp("", "extras.yaml")
+	if error != nil {
+		t.Error("Error creating temp file: ", error)
+	}
+
+	// cleanup code
+	deleteFile := func() {
+		os.Remove(file.Name())
+	}
+	defer deleteFile()
+
+	// write extras to file
+	encoder := yaml.NewEncoder(file)
+	error = encoder.Encode(extras)
+	if error != nil {
+		t.Error("Error encoding extras: ", error)
+	}
+
+	// close file
+	error = file.Close()
+	if error != nil {
+		t.Error("Error closing file: ", error)
+	}
+
+	// file name
+	fileName := file.Name()
+
+	// happy path
+	loadedExtras, error := loadExtras(fileName)
+	if error != nil {
+		t.Error("Error loading extras: ", error)
+	}
+	assert.Equal(t, extras, loadedExtras)
+}
diff --git a/file.go b/file.go
index a82aa49..f604e55 100644
--- a/file.go
+++ b/file.go
@@ -14,9 +14,10 @@ type FilePatternData struct {
 	ProjectName      string
 	Time             string
 	Year, Month, Day string
+	Extras           map[string]string
 }
 
-func createFilePatternData(now time.Time, projectName string, name string) FilePatternData {
+func createFilePatternData(now time.Time, projectName string, name string, extras map[string]string) FilePatternData {
 	return FilePatternData{
 		Name:        name,
 		ProjectName: projectName,
@@ -24,15 +25,16 @@ func createFilePatternData(now time.Time, projectName string, name string) FileP
 		Year:        now.Format("2006"),
 		Month:       now.Format("01"),
 		Day:         now.Format("02"),
+		Extras:      extras,
 	}
 }
 
-func createTemplateFile(srcPath string, destPath string, projectName string, name string) error {
+func createTemplateFile(srcPath string, destPath string, projectName string, name string, extras map[string]string) error {
 	now := time.Now()
-	filePatternData := createFilePatternData(now, projectName, name)
+	filePatternData := createFilePatternData(now, projectName, name, extras)
 
 	// standardize paths
-	srcPath,err := getFullPath(srcPath)
+	srcPath, err := getFullPath(srcPath)
 	if err != nil {
 		return err
 	}
@@ -63,9 +65,9 @@ func createTemplateFile(srcPath string, destPath string, projectName string, nam
 	return nil
 }
 
-func createTemplateString(templateText string, projectName string, name string) (string, error) {
+func createTemplateString(templateText string, projectName string, name string, extras map[string]string) (string, error) {
 	now := time.Now()
-	filePatternData := createFilePatternData(now, projectName, name)
+	filePatternData := createFilePatternData(now, projectName, name, extras)
 
 	// parse template
 	template, err := template.New("text-template").Parse(templateText)
diff --git a/go.mod b/go.mod
index fb5860f..d26de5c 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module gitlab.com/fuzzy-rp/template
 go 1.19
 
 require (
+	github.com/stretchr/testify v1.8.0
 	github.com/urfave/cli/v2 v2.16.3
 	golang.org/x/exp v0.0.0-20220921164117-439092de6870
 	gopkg.in/yaml.v3 v3.0.1
@@ -10,6 +11,8 @@ require (
 
 require (
 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
 )
diff --git a/go.sum b/go.sum
index 059a9a7..536755f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,17 @@
 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=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+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/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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk=
 github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
@@ -10,5 +20,6 @@ golang.org/x/exp v0.0.0-20220921164117-439092de6870 h1:j8b6j9gzSigH28O5SjSpQSSh9
 golang.org/x/exp v0.0.0-20220921164117-439092de6870/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
 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.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/main.go b/main.go
index 4276b22..028a555 100644
--- a/main.go
+++ b/main.go
@@ -11,14 +11,18 @@ import (
 )
 
 func main() {
-	configFilePath := getFullPath("~/.template.yaml")
 	var profileName string
 	var projectName string
+	var configFilePath string
+	var extrasFilePath string
+	var useDefaultConfig bool
+	var err error
 
 	app := &cli.App{
 		Name:                 "template",
 		Usage:                "create file or directory from a template",
 		EnableBashCompletion: true,
+		Suggest:              true,
 		Flags: []cli.Flag{
 			&cli.StringFlag{
 				Name:        "profile",
@@ -37,37 +41,45 @@ func main() {
 				Value:       "",
 				Destination: &projectName,
 			},
+			&cli.PathFlag{
+				Name:        "config-yaml",
+				Aliases:     []string{"c"},
+				Usage:       "path to the config yaml file",
+				Value:       "~/.template.yaml",
+				Destination: &configFilePath,
+			},
+			&cli.PathFlag{
+				Name:        "extras-yaml",
+				Aliases:     []string{"e"},
+				Usage:       "path to the extras yaml file",
+				Value:       "~/.template-extras.yaml",
+				Destination: &extrasFilePath,
+			},
+			&cli.BoolFlag{
+				Name:        "default-config",
+				Aliases:     []string{"d"},
+				Usage:       "use the default hard-coded config (testing only)",
+				Value:       false,
+				Destination: &useDefaultConfig,
+			},
 		},
 		Action: func(context *cli.Context) error {
-			// try and load config
-			config, err := loadConfig(configFilePath)
-			if err != nil {
-				fmt.Printf("No config present at '%v', creating and using sample config\n", configFilePath)
 
-				// create config and save
-				err := saveConfig(configFilePath, defaultConfig())
-				if err != nil {
-					return fmt.Errorf("error creating config: %v", err)
-				}
-
-				// load config
-				config, err = loadConfig(configFilePath)
+			// get config
+			var config Config
+			if useDefaultConfig {
+				config = defaultConfig()
+			} else {
+				config, err = getOrCreateConfig(configFilePath)
 				if err != nil {
-					return fmt.Errorf("error loading config: %v", err)
+					return err
 				}
-			} else {
-				// log successful load
-				fmt.Printf("Config loaded from '%v'\n", configFilePath)
-			}
-
-			// validate config
-			err = validateConfig(config)
-			if err != nil {
-				return fmt.Errorf("error validating config: %v", err)
 			}
 
 			// read args
 			args := context.Args()
+			fmt.Println("args:", args)
+			// args.Get(0)
 
 			// get profile name from args
 			// if not set explicitly, use first arg, if present
@@ -86,6 +98,10 @@ func main() {
 			}
 
 			// extra features
+			extras, err := loadExtras(extrasFilePath)
+			if err != nil {
+				return nil
+			}
 
 			// list profiles
 			if profileName == "list" {
@@ -120,7 +136,7 @@ func main() {
 			}
 
 			// process profile
-			err = processProfile(profile, projectName)
+			err = processProfile(profile, projectName, extras)
 			if err != nil {
 				return fmt.Errorf("error processing profile: %v", err)
 			}
diff --git a/name_pattern.go b/name_pattern.go
index d16494a..c383b63 100644
--- a/name_pattern.go
+++ b/name_pattern.go
@@ -12,9 +12,10 @@ import (
 type NamePatternData struct {
 	Year, Month, Day, Hour, Minute, Second string
 	ProjectName                            string
+	Extras                                 map[string]string
 }
 
-func createNewNameForProfile(now time.Time, projectName string, profile Profile, existingEntities []string) (string, error) {
+func createNewNameForProfile(now time.Time, projectName string, profile Profile, extras map[string]string, existingEntities []string) (string, error) {
 	for index, namePattern := range profile.NamePatterns {
 
 		startingVersion := 1
@@ -34,6 +35,7 @@ func createNewNameForProfile(now time.Time, projectName string, profile Profile,
 			Minute:      now.Format("04"),
 			Second:      now.Format("05"),
 			ProjectName: projectName,
+			Extras:      extras,
 		}
 
 		for {
diff --git a/name_pattern_test.go b/name_pattern_test.go
index 61aa852..f0e4dc9 100644
--- a/name_pattern_test.go
+++ b/name_pattern_test.go
@@ -8,25 +8,28 @@ import (
 func TestCreateNewName(t *testing.T) {
 	// setup code
 
+	extras := make(map[string]string)
+	extras["test1"] = "test1"
+
 	// Mon Jan 2 15:04:05 MST 2006
 	now := time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC)
 	profile := Profile{
 		IsDefault: true,
 		Type:      FileType,
 		NamePatterns: []string{
-			"{{.Year}}-{{.Month}}-{{.Day}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.txt",
-			"{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.txt",
-			"{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}-{{.ProjectName}}.txt",
+			"{{.Extras.test1}}-{{.Year}}-{{.Month}}-{{.Day}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.txt",
+			"{{.Extras.test1}}-{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}{{if .ProjectName}}-{{.ProjectName}}{{end}}.txt",
+			"{{.Extras.test1}}-{{.Year}}-{{.Month}}-{{.Day}}-{{.Hour}}-{{.Minute}}-{{.Second}}-{{.ProjectName}}.txt",
 		},
 	}
-	newNameNoProject := "2006-01-02.txt"
-	newName1 := "2006-01-02-test-project.txt"
-	newName2 := "2006-01-02-15-test-project.txt"
-	newName3 := "2006-01-02-15-04-05-test-project.txt"
+	newNameNoProject := "test1-2006-01-02.txt"
+	newName1 := "test1-2006-01-02-test-project.txt"
+	newName2 := "test1-2006-01-02-15-test-project.txt"
+	newName3 := "test1-2006-01-02-15-04-05-test-project.txt"
 
 	testHappyPath := func(projectName string, expectedName string, existingEntities []string) func(t *testing.T) {
 		return func(t *testing.T) {
-			newName, err := createNewNameForProfile(now, projectName, profile, existingEntities)
+			newName, err := createNewNameForProfile(now, projectName, profile, extras, existingEntities)
 			if err != nil {
 				t.Error("Error creating new name: ", err)
 			}
@@ -37,7 +40,7 @@ func TestCreateNewName(t *testing.T) {
 	}
 	testErrorPath := func(projectName string, existingEntities []string) func(t *testing.T) {
 		return func(t *testing.T) {
-			_, err := createNewNameForProfile(now, projectName, profile, existingEntities)
+			_, err := createNewNameForProfile(now, projectName, profile, extras, existingEntities)
 			if err == nil {
 				t.Error("Expected error but got none")
 			}
@@ -57,22 +60,25 @@ func TestCreateNewName(t *testing.T) {
 }
 
 func TestCreateNewName_Index(t *testing.T) {
+	extras := make(map[string]string)
+	extras["test1"] = "test1"
+
 	// Mon Jan 2 15:04:05 MST 2006
 	now := time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC)
 	profile := Profile{
 		IsDefault: true,
 		Type:      FileType,
 		NamePatterns: []string{
-			"{{$version := getVersion}}{{.Year}}-{{.Month}}-{{.Day}}v{{$version}}.txt",
+			"{{.Extras.test1}}-{{$version := getVersion}}{{.Year}}-{{.Month}}-{{.Day}}v{{$version}}.txt",
 		},
 	}
-	newName1 := "2006-01-02v1.txt"
-	newName2 := "2006-01-02v2.txt"
-	newName3 := "2006-01-02v3.txt"
+	newName1 := "test1-2006-01-02v1.txt"
+	newName2 := "test1-2006-01-02v2.txt"
+	newName3 := "test1-2006-01-02v3.txt"
 
 	testHappyPath := func(expectedName string, existingEntities []string) func(t *testing.T) {
 		return func(t *testing.T) {
-			newName, err := createNewNameForProfile(now, "test-project", profile, existingEntities)
+			newName, err := createNewNameForProfile(now, "test-project", profile, extras, existingEntities)
 			if err != nil {
 				t.Error("Error creating new name: ", err)
 			}
diff --git a/postscript.go b/postscript.go
index def2ccb..dfc2024 100644
--- a/postscript.go
+++ b/postscript.go
@@ -6,11 +6,12 @@ import (
 )
 
 type PostScriptPatternData struct {
-	Name string
-	Path string
+	Name   string
+	Path   string
+	Extras map[string]string
 }
 
-func createPostScriptArrays(profile Profile, newName string, fullPath string) ([]string, error) {
+func createPostScriptArrays(profile Profile, newName string, fullPath string, extras map[string]string) ([]string, error) {
 	array := make([]string, 0)
 
 	if profile.PostScripts == nil || len(profile.PostScripts) == 0 {
@@ -18,8 +19,9 @@ func createPostScriptArrays(profile Profile, newName string, fullPath string) ([
 	}
 
 	patternData := PostScriptPatternData{
-		Name: newName,
-		Path: fullPath,
+		Name:   newName,
+		Path:   fullPath,
+		Extras: extras,
 	}
 
 	for _, postScriptPattern := range profile.PostScripts {
diff --git a/profile.go b/profile.go
index 8208fc2..6389435 100644
--- a/profile.go
+++ b/profile.go
@@ -32,7 +32,7 @@ func findProfile(config Config, profileName string) (Profile, error) {
 	return Profile{}, errors.New("couldn't find profile")
 }
 
-func processProfile(profile Profile, projectName string) error {
+func processProfile(profile Profile, projectName string, extras map[string]string) error {
 	// validate profile
 	if profile.NamePatterns == nil || len(profile.NamePatterns) == 0 {
 		return errors.New("no name patterns specified")
@@ -87,7 +87,7 @@ func processProfile(profile Profile, projectName string) error {
 
 	// generate a new name based on time, profile, and existing entities
 	now := time.Now()
-	newName, err := createNewNameForProfile(now, projectName, profile, entities)
+	newName, err := createNewNameForProfile(now, projectName, profile, extras, entities)
 	if err != nil {
 		return err
 	}
@@ -114,13 +114,13 @@ func processProfile(profile Profile, projectName string) error {
 		useTemplate := profile.FileTemplate != ""
 		if useTemplateFile {
 			fmt.Printf("Creating file '%v' from template: %v\n", fullPath, profile.FileTemplatePath)
-			err := createTemplateFile(profile.FileTemplatePath, fullPath, projectName, newName)
+			err := createTemplateFile(profile.FileTemplatePath, fullPath, projectName, newName, extras)
 			if err != nil {
 				return fmt.Errorf("error creating template file: %v", err)
 			}
 		} else if useTemplate {
 			fmt.Printf("Creating file '%v' from template string\n", fullPath)
-			templateString, err := createTemplateString(profile.FileTemplate, projectName, newName)
+			templateString, err := createTemplateString(profile.FileTemplate, projectName, newName, extras)
 			if err != nil {
 				return fmt.Errorf("error creating template: %v", err)
 			}
@@ -134,7 +134,7 @@ func processProfile(profile Profile, projectName string) error {
 	}
 
 	// execute PostScript, if present
-	postScripts, err := createPostScriptArrays(profile, newName, fullPath)
+	postScripts, err := createPostScriptArrays(profile, newName, fullPath, extras)
 	if err != nil {
 		return err
 	}