template / commit
Adding file templates support:
.vscode/launch.json | 18 ++---------- .vscode/tasks.json | 13 +-------- config.go | 29 +++++++++++-------- file.go | 48 +++++++++++++++++++++++++++++++ name_pattern.go | 61 +++++++++++++++++++++++++++++++++++++++- profile.go | 70 ++++++++-------------------------------------- scripts/clean-install.ps1 | 7 +++++ templates/blog-template.md | 11 ++++++++ 8 files changed, 158 insertions(+), 99 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 8f03d80..c823651 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,24 +5,10 @@ "version": "0.2.0", "configurations": [ { - "name": "Delete ~/.template.yaml", + "name": "Clean install", "type": "PowerShell", "request": "launch", - "script": "Remove-Item ~/.template.yaml -ErrorAction SilentlyContinue", - "cwd": "${workspaceFolder}" - }, - { - "name": "Install template", - "type": "PowerShell", - "request": "launch", - "script": "go install", - "cwd": "${workspaceFolder}" - }, - { - "name": "Refresh install: install and delete config", - "type": "PowerShell", - "request": "launch", - "script": "go install; Remove-Item ~/.template.yaml -ErrorAction SilentlyContinue", + "script": "./scripts/clean-install.ps1", "cwd": "${workspaceFolder}" }, { diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2e7bb7f..f89b479 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,16 +2,5 @@ // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format "version": "2.0.0", - "tasks": [ - { - "label": "remove-template-yaml", - "type": "shell", - "command": "rm ~/.template.yaml -ErrorAction SilentlyContinue", - "options": { - "shell": { - "executable": "powershell.exe" - } - } - } - ] + "tasks": [] } \ No newline at end of file diff --git a/config.go b/config.go index 7f9a6cd..89416ab 100644 --- a/config.go +++ b/config.go @@ -23,14 +23,15 @@ const ( ) type Profile struct { - IsDefault bool - Name string - Path string - Type ProfileType - NamePatterns []string - PostScript []string - ScriptShell string - OS OSType + IsDefault bool + Name string + Path string + Type ProfileType + NamePatterns []string + PostScript []string + ScriptShell string + OS OSType + FileTemplatePath string // FileTemplatePath string } @@ -79,10 +80,11 @@ func defaultConfig() Config { }, }, { - Name: "blog", - OS: "All", - Path: "~/Dropbox/Blog", - Type: FileType, + Name: "blog", + OS: "All", + Path: "~/Dropbox/Blog", + FileTemplatePath: "~/.templates/blog-template.md", + Type: FileType, NamePatterns: []string{ "{{$version := getVersion}}" + "{{.Year}}-{{.Month}}-{{.Day}}" + @@ -137,6 +139,9 @@ func validateConfig(config Config) error { if profile.Type == "" || (profile.Type != FileType && profile.Type != FolderType) { return fmt.Errorf("Invalid profile type %s for profile %s", profile.Type, profile.Name) } + 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) + } } return nil } diff --git a/file.go b/file.go new file mode 100644 index 0000000..fdc1af9 --- /dev/null +++ b/file.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "text/template" + "time" +) + +type FilePatternData struct { + Name string + ProjectName string + Time string +} + +func createFilePatternData(now time.Time, projectName string, name string) FilePatternData { + return FilePatternData{ + Name: name, + ProjectName: projectName, + Time: now.Format("Monday, Jan 02, 2006 15:04:05 MST"), + } +} + +func createTemplateFile(srcPath string, destPath string, projectName string, name string) error { + now := time.Now() + filePatternData := createFilePatternData(now, projectName, name) + + srcPath = getFullPath(srcPath) + srcName := filepath.Base(srcPath) + template, err := template.New(srcName).ParseFiles(srcPath) + if err != nil { + return fmt.Errorf("Error parsing source file '%v': %v", srcPath, err) + } + + destPath = getFullPath(destPath) + writer, err := os.Create(destPath) + if err != nil { + return fmt.Errorf("Error creating destination file '%v': %v", destPath, err) + } + + err = template.Execute(writer, filePatternData) + if err != nil { + return fmt.Errorf("Error executing template: %v", err) + } + + return nil +} diff --git a/name_pattern.go b/name_pattern.go index 064c521..2a79908 100644 --- a/name_pattern.go +++ b/name_pattern.go @@ -1,6 +1,13 @@ package main -import "time" +import ( + "errors" + "strings" + "text/template" + "time" + + "golang.org/x/exp/slices" +) type NamePatternData struct { Year, Month, Day, Hour, Minute, Second string @@ -30,3 +37,55 @@ func createNamePatternData(now time.Time, projectName string) NamePatternData { return patternInfo } + +func createNewNameForProfile(profile Profile, patternData NamePatternData, existingEntities []string) (string, error) { + for index, namePattern := range profile.NamePatterns { + + startingVersion := 1 + invokeCount := 0 + funcMap := template.FuncMap{ + "getVersion": func() int { + invokeCount++ + return startingVersion + }, + } + template := template.New("template-name").Funcs(funcMap) + + for { + + template, err := template.Parse(namePattern) + if err != nil { + return "", err + } + + sb := new(strings.Builder) + err = template.Execute(sb, patternData) + if err != nil { + return "", err + } + + newName := sb.String() + alreadyExists := slices.Contains(existingEntities, newName) + useIndex := invokeCount > 0 + isLastPattern := index == len(profile.NamePatterns)-1 + + // if no conflict, use this name + if !alreadyExists { + 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/profile.go b/profile.go index b183961..d70b936 100644 --- a/profile.go +++ b/profile.go @@ -8,10 +8,7 @@ import ( "path/filepath" "runtime" "strings" - "text/template" "time" - - "golang.org/x/exp/slices" ) func findProfile(config Config, profileName string) (Profile, error) { @@ -109,11 +106,20 @@ func processProfile(profile Profile, projectName string) error { fmt.Printf("Creating directory: %v\n", fullPath) err = os.Mkdir(fullPath, os.ModePerm) if err != nil { - return err + return fmt.Errorf("Error creating directory: %v", err) } } else { - fmt.Printf("Creating file: %v\n", fullPath) - os.WriteFile(fullPath, []byte{}, os.ModePerm) + useTemplateFile := profile.FileTemplatePath != "" + if useTemplateFile { + fmt.Printf("Creating file '%v' from template: %v\n", fullPath, profile.FileTemplatePath) + err := createTemplateFile(profile.FileTemplatePath, fullPath, projectName, newName) + if err != nil { + return fmt.Errorf("Error creating template file: %v", err) + } + } else { + fmt.Printf("Creating empty file: %v\n", fullPath) + os.WriteFile(fullPath, []byte{}, os.ModePerm) + } } // execute PostScript, if present @@ -135,55 +141,3 @@ func processProfile(profile Profile, projectName string) error { return nil } - -func createNewNameForProfile(profile Profile, patternData NamePatternData, existingEntities []string) (string, error) { - for index, namePattern := range profile.NamePatterns { - - startingVersion := 1 - invokeCount := 0 - funcMap := template.FuncMap{ - "getVersion": func() int { - invokeCount++ - return startingVersion - }, - } - template := template.New("template-name").Funcs(funcMap) - - for { - - template, err := template.Parse(namePattern) - if err != nil { - return "", err - } - - sb := new(strings.Builder) - err = template.Execute(sb, patternData) - if err != nil { - return "", err - } - - newName := sb.String() - alreadyExists := slices.Contains(existingEntities, newName) - useIndex := invokeCount > 0 - isLastPattern := index == len(profile.NamePatterns)-1 - - // if no conflict, use this name - if !alreadyExists { - 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/scripts/clean-install.ps1 b/scripts/clean-install.ps1 new file mode 100644 index 0000000..ce4b25b --- /dev/null +++ b/scripts/clean-install.ps1 @@ -0,0 +1,7 @@ +$scriptPath = Split-Path -Path $MyInvocation.MyCommand.Path -Parent +Set-Location "$scriptPath/.." + +Remove-Item ~/.template.yaml -ErrorAction SilentlyContinue +go install +Remove-Item ~/.templates -Recurse -ErrorAction SilentlyContinue +Copy-Item .\templates -Destination ~/.templates -Recurse \ No newline at end of file diff --git a/templates/blog-template.md b/templates/blog-template.md new file mode 100644 index 0000000..bccf68f --- /dev/null +++ b/templates/blog-template.md @@ -0,0 +1,11 @@ +# {{.ProjectName}} + +Created by template, on {{.Time}} + +## Spelling + +cspell:words nanite + +## Removed writing + +## Writing