diff --git a/cmd/docker/catalog.go b/cmd/docker/catalog.go index e3a18bc..4d01961 100644 --- a/cmd/docker/catalog.go +++ b/cmd/docker/catalog.go @@ -2,6 +2,7 @@ package docker import ( "fmt" + "io/fs" "log" "os" @@ -15,7 +16,7 @@ var catalogCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { if templateName == "" { - files, err := os.ReadDir("templates") + files, err := fs.ReadDir(TemplateFs, TemplateRootPath) if err != nil { log.Fatal(err) } @@ -36,7 +37,7 @@ var catalogCmd = &cobra.Command{ } } } else { - body, err := os.ReadFile("templates/" + templateName + "/prompts.yaml") + body, err := fs.ReadFile(TemplateFs, TemplateRootPath+"/"+templateName+"/prompts.yaml") if err != nil { if templateDirectory == "" { log.Fatalf("unable to read file: %v", err) diff --git a/cmd/docker/init.go b/cmd/docker/init.go index 4000a34..c88676f 100644 --- a/cmd/docker/init.go +++ b/cmd/docker/init.go @@ -46,7 +46,7 @@ var initCmd = &cobra.Command{ } promptValues := pkg.GetPromptValues(templateRoot, templateName, defaultPromptValues) - templateList, err := pkg.GetTemplatesInPathHierarchy(templateRoot + "/" + templateName) + templateList, err := pkg.GetTemplatesInPathHierarchy(templateRoot+"/"+templateName, templateDirectory == "") if err != nil { panic(err) } @@ -57,7 +57,11 @@ var initCmd = &cobra.Command{ panic(err) } name := filepath.Base(t) - tpl := template.Must(template.New(name).Funcs(templateFuncs).ParseFiles(t)) + // Parsing template files from embedded FS or external FS + tpl, err := template.New(name).Funcs(templateFuncs).ParseFS(pkg.TemplateFs, t) + if err != nil { + tpl = template.Must(template.New(name).Funcs(templateFuncs).ParseFiles(t)) + } err = tpl.ExecuteTemplate(f, name, promptValues) if err != nil { panic(err) diff --git a/cmd/docker/root.go b/cmd/docker/root.go index 4ce30cf..ce74c9a 100644 --- a/cmd/docker/root.go +++ b/cmd/docker/root.go @@ -1,12 +1,15 @@ package docker import ( + "embed" "fmt" "os" "github.com/spf13/cobra" ) +var TemplateFs embed.FS + var rootCmd = &cobra.Command{ Use: "docker", Short: "docker - a fake CLI to support Init command extension", diff --git a/main.go b/main.go index 81d0027..28cfe3c 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,17 @@ package main import ( + "embed" + "github.com/aborroy/docker-init-with-templates/cmd/docker" + "github.com/aborroy/docker-init-with-templates/pkg" ) +//go:embed all:templates +var templateFs embed.FS + func main() { + pkg.TemplateFs = templateFs + docker.TemplateFs = templateFs docker.Execute() } diff --git a/pkg/hidden.go b/pkg/hidden.go new file mode 100644 index 0000000..9018a5c --- /dev/null +++ b/pkg/hidden.go @@ -0,0 +1,9 @@ +package pkg + +import "slices" + +var Allowed = []string{".env.tpl", ".dockerignore.tpl"} + +func IsAllowedHiddenFile(name string) bool { + return slices.Contains(Allowed, name) +} diff --git a/pkg/hidden_unix.go b/pkg/hidden_unix.go index 8db2b24..e9dd47f 100644 --- a/pkg/hidden_unix.go +++ b/pkg/hidden_unix.go @@ -6,5 +6,5 @@ package pkg const dotCharacter = 46 func IsHidden(path string) bool { - return path[0] == dotCharacter + return path[0] == dotCharacter && !IsAllowedHiddenFile(path) } diff --git a/pkg/hidden_windows.go b/pkg/hidden_windows.go index 0a9102d..2e3554a 100644 --- a/pkg/hidden_windows.go +++ b/pkg/hidden_windows.go @@ -13,7 +13,7 @@ const dotCharacter = 46 func IsHidden(path string) bool { if path[0] == dotCharacter { - return true + return !IsAllowedHiddenFile(path) } absPath, err := filepath.Abs(path) diff --git a/pkg/io.go b/pkg/io.go index 1eb9db3..9cf4a04 100644 --- a/pkg/io.go +++ b/pkg/io.go @@ -1,7 +1,9 @@ package pkg import ( + "embed" "io" + "io/fs" "os" "path/filepath" "strings" @@ -9,7 +11,29 @@ import ( const TemplateExtension string = ".tpl" -func GetTemplatesInPathHierarchy(path string) ([]string, error) { +var TemplateFs embed.FS + +func EmbedWalk(root string) ([]string, error) { + var paths []string + fs.WalkDir(TemplateFs, root, func(path string, d fs.DirEntry, err error) error { + if err != nil { + panic(err) + } + if d.IsDir() { + return nil + } + if err != nil { + return err + } + if strings.HasSuffix(path, TemplateExtension) { + paths = append(paths, path) + } + return nil + }) + return paths, nil +} + +func FilesystemWalk(path string) ([]string, error) { var paths []string err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { if err != nil { @@ -26,6 +50,14 @@ func GetTemplatesInPathHierarchy(path string) ([]string, error) { return paths, nil } +func GetTemplatesInPathHierarchy(path string, useFS bool) ([]string, error) { + if useFS { + return EmbedWalk(path) + } else { + return FilesystemWalk(path) + } +} + func CreateOutputFile(outputRoot string, outputFile string, templateName string) (io.Writer, string, error) { position := strings.Index(outputFile, "/"+templateName+"/") outputFile = outputFile[position+len("/"+templateName+"/"):] diff --git a/pkg/prompt.go b/pkg/prompt.go index 206a920..170722e 100644 --- a/pkg/prompt.go +++ b/pkg/prompt.go @@ -2,6 +2,7 @@ package pkg import ( "fmt" + "io/fs" "os" "reflect" "strings" @@ -100,9 +101,13 @@ func IsPromptVisible(expression string, values map[string]interface{}) bool { func GetPromptValues(templateRootPath string, template string, cmdPromptValues map[string]string) reflect.Value { - file, err := os.ReadFile(templateRootPath + "/" + template + "/prompts.yaml") + // Read prompt file from embed FS or external FS + file, err := fs.ReadFile(TemplateFs, templateRootPath+"/"+template+"/prompts.yaml") if err != nil { - panic(err) + file, err = os.ReadFile(templateRootPath + "/" + template + "/prompts.yaml") + if err != nil { + panic(err) + } } data := orderedmap.New[string, Prompt]()