mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-03 06:51:26 +08:00
use mewn for templates
massively improve template handling
This commit is contained in:
parent
c20aabc8f8
commit
c180d7dccb
30
cmd/cmd-mewn.go
Normal file
30
cmd/cmd-mewn.go
Normal file
File diff suppressed because one or more lines are too long
@ -41,6 +41,12 @@ func (fs *FSHelper) FileExists(path string) bool {
|
|||||||
return fi.Mode().IsRegular()
|
return fi.Mode().IsRegular()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *FSHelper) CreateFile(filename string, data []byte) error {
|
||||||
|
// Ensure directory exists
|
||||||
|
fs.MkDirs(filepath.Dir(filename))
|
||||||
|
return ioutil.WriteFile(filename, data, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
// MkDirs creates the given nested directories.
|
// MkDirs creates the given nested directories.
|
||||||
// Returns error on failure
|
// Returns error on failure
|
||||||
func (fs *FSHelper) MkDirs(fullPath string, mode ...os.FileMode) error {
|
func (fs *FSHelper) MkDirs(fullPath string, mode ...os.FileMode) error {
|
||||||
|
@ -14,6 +14,8 @@ import (
|
|||||||
"github.com/leaanthony/spinner"
|
"github.com/leaanthony/spinner"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var fs = NewFSHelper()
|
||||||
|
|
||||||
// ValidateFrontendConfig checks if the frontend config is valid
|
// ValidateFrontendConfig checks if the frontend config is valid
|
||||||
func ValidateFrontendConfig(projectOptions *ProjectOptions) error {
|
func ValidateFrontendConfig(projectOptions *ProjectOptions) error {
|
||||||
if projectOptions.FrontEnd.Dir == "" {
|
if projectOptions.FrontEnd.Dir == "" {
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type author struct {
|
type author struct {
|
||||||
@ -47,15 +49,11 @@ func NewProjectHelper() *ProjectHelper {
|
|||||||
// GenerateProject generates a new project using the options given
|
// GenerateProject generates a new project using the options given
|
||||||
func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
|
func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
|
||||||
|
|
||||||
fs := NewFSHelper()
|
// exists := ph.templates.TemplateExists(projectOptions.Template)
|
||||||
exists, err := ph.templates.TemplateExists(projectOptions.Template)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
// if !exists {
|
||||||
return fmt.Errorf("template '%s' is invalid", projectOptions.Template)
|
// return fmt.Errorf("template '%s' is invalid", projectOptions.Template)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Calculate project path
|
// Calculate project path
|
||||||
projectPath, err := filepath.Abs(projectOptions.OutputDirectory)
|
projectPath, err := filepath.Abs(projectOptions.OutputDirectory)
|
||||||
@ -63,6 +61,8 @@ func (ph *ProjectHelper) GenerateProject(projectOptions *ProjectOptions) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = projectPath
|
||||||
|
|
||||||
if fs.DirExists(projectPath) {
|
if fs.DirExists(projectPath) {
|
||||||
return fmt.Errorf("directory '%s' already exists", projectPath)
|
return fmt.Errorf("directory '%s' already exists", projectPath)
|
||||||
}
|
}
|
||||||
@ -121,7 +121,6 @@ func (ph *ProjectHelper) NewProjectOptions() *ProjectOptions {
|
|||||||
system: NewSystemHelper(),
|
system: NewSystemHelper(),
|
||||||
log: NewLogger(),
|
log: NewLogger(),
|
||||||
templates: NewTemplateHelper(),
|
templates: NewTemplateHelper(),
|
||||||
templateNameMap: make(map[string]string),
|
|
||||||
Author: &author{},
|
Author: &author{},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,12 +149,12 @@ type ProjectOptions struct {
|
|||||||
system *SystemHelper
|
system *SystemHelper
|
||||||
log *Logger
|
log *Logger
|
||||||
templates *TemplateHelper
|
templates *TemplateHelper
|
||||||
templateNameMap map[string]string // Converts template prompt text to template name
|
selectedTemplate *TemplateDetails
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defaults sets the default project template
|
// Defaults sets the default project template
|
||||||
func (po *ProjectOptions) Defaults() {
|
func (po *ProjectOptions) Defaults() {
|
||||||
po.Template = "basic"
|
po.Template = "vuebasic"
|
||||||
}
|
}
|
||||||
|
|
||||||
// PromptForInputs asks the user to input project details
|
// PromptForInputs asks the user to input project details
|
||||||
@ -170,48 +169,31 @@ func (po *ProjectOptions) PromptForInputs() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
templateDetails, err := po.templates.GetTemplateDetails()
|
// Process Templates
|
||||||
if err != nil {
|
templateList := slicer.Interface()
|
||||||
return err
|
options := slicer.String()
|
||||||
|
for _, templateDetails := range po.templates.TemplateList.details {
|
||||||
|
templateList.Add(templateDetails)
|
||||||
|
options.Add(fmt.Sprintf("%s - %s", templateDetails.Metadata.Name, templateDetails.Metadata.ShortDescription))
|
||||||
}
|
}
|
||||||
|
|
||||||
templates := []string{}
|
templateIndex := 0
|
||||||
// Add a Custom Template
|
|
||||||
// templates = append(templates, "Custom - Choose your own CSS framework")
|
if len(options.AsSlice()) > 1 {
|
||||||
for templateName, templateDetails := range templateDetails {
|
templateIndex = PromptSelection("Please select a template", options.AsSlice(), 0)
|
||||||
templateText := templateName
|
|
||||||
// Check if metadata json exists
|
|
||||||
if templateDetails.Metadata != nil {
|
|
||||||
shortdescription := templateDetails.Metadata["shortdescription"]
|
|
||||||
if shortdescription != "" {
|
|
||||||
templateText += " - " + shortdescription.(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
templates = append(templates, templateText)
|
|
||||||
po.templateNameMap[templateText] = templateName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if po.Template != "" {
|
// After selection do this....
|
||||||
if _, ok := templateDetails[po.Template]; !ok {
|
po.selectedTemplate = templateList.AsSlice()[templateIndex].(*TemplateDetails)
|
||||||
po.log.Error("Template '%s' invalid.", po.Template)
|
|
||||||
templateSelected := PromptSelection("Select template", templates)
|
|
||||||
po.Template = templates[templateSelected]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
templateSelected := PromptSelection("Select template", templates)
|
|
||||||
po.Template = templates[templateSelected]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup NPM Project name
|
// Setup NPM Project name
|
||||||
po.NPMProjectName = strings.ToLower(strings.Replace(po.Name, " ", "_", -1))
|
po.NPMProjectName = strings.ToLower(strings.Replace(po.Name, " ", "_", -1))
|
||||||
|
|
||||||
// Fix template name
|
// Fix template name
|
||||||
if po.templateNameMap[po.Template] != "" {
|
po.Template = strings.Split(po.selectedTemplate.Path, "/")[0]
|
||||||
po.Template = po.templateNameMap[po.Template]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate template details
|
// // Populate template details
|
||||||
templateMetadata := templateDetails[po.Template].Metadata
|
templateMetadata := po.selectedTemplate.Metadata
|
||||||
|
|
||||||
err = processTemplateMetadata(templateMetadata, po)
|
err = processTemplateMetadata(templateMetadata, po)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -299,36 +281,36 @@ func processBinaryName(po *ProjectOptions) {
|
|||||||
fmt.Println("Output binary Name: " + po.BinaryName)
|
fmt.Println("Output binary Name: " + po.BinaryName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func processTemplateMetadata(templateMetadata map[string]interface{}, po *ProjectOptions) error {
|
func processTemplateMetadata(templateMetadata *TemplateMetadata, po *ProjectOptions) error {
|
||||||
if templateMetadata["frontenddir"] != nil {
|
if templateMetadata.FrontendDir != "" {
|
||||||
po.FrontEnd = &frontend{}
|
po.FrontEnd = &frontend{}
|
||||||
po.FrontEnd.Dir = templateMetadata["frontenddir"].(string)
|
po.FrontEnd.Dir = templateMetadata.FrontendDir
|
||||||
}
|
}
|
||||||
if templateMetadata["install"] != nil {
|
if templateMetadata.Install != "" {
|
||||||
if po.FrontEnd == nil {
|
if po.FrontEnd == nil {
|
||||||
return fmt.Errorf("install set in template metadata but not frontenddir")
|
return fmt.Errorf("install set in template metadata but not frontenddir")
|
||||||
}
|
}
|
||||||
po.FrontEnd.Install = templateMetadata["install"].(string)
|
po.FrontEnd.Install = templateMetadata.Install
|
||||||
}
|
}
|
||||||
if templateMetadata["build"] != nil {
|
if templateMetadata.Build != "" {
|
||||||
if po.FrontEnd == nil {
|
if po.FrontEnd == nil {
|
||||||
return fmt.Errorf("build set in template metadata but not frontenddir")
|
return fmt.Errorf("build set in template metadata but not frontenddir")
|
||||||
}
|
}
|
||||||
po.FrontEnd.Build = templateMetadata["build"].(string)
|
po.FrontEnd.Build = templateMetadata.Build
|
||||||
}
|
}
|
||||||
|
|
||||||
if templateMetadata["bridge"] != nil {
|
if templateMetadata.Bridge != "" {
|
||||||
if po.FrontEnd == nil {
|
if po.FrontEnd == nil {
|
||||||
return fmt.Errorf("bridge set in template metadata but not frontenddir")
|
return fmt.Errorf("bridge set in template metadata but not frontenddir")
|
||||||
}
|
}
|
||||||
po.FrontEnd.Bridge = templateMetadata["bridge"].(string)
|
po.FrontEnd.Bridge = templateMetadata.Bridge
|
||||||
}
|
}
|
||||||
|
|
||||||
if templateMetadata["serve"] != nil {
|
if templateMetadata.Serve != "" {
|
||||||
if po.FrontEnd == nil {
|
if po.FrontEnd == nil {
|
||||||
return fmt.Errorf("serve set in template metadata but not frontenddir")
|
return fmt.Errorf("serve set in template metadata but not frontenddir")
|
||||||
}
|
}
|
||||||
po.FrontEnd.Serve = templateMetadata["serve"].(string)
|
po.FrontEnd.Serve = templateMetadata.Serve
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -34,18 +34,29 @@ func PromptRequired(question string, defaultValue ...string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PromptSelection asks the user to choose an option
|
// PromptSelection asks the user to choose an option
|
||||||
func PromptSelection(question string, options []string) int {
|
func PromptSelection(question string, options []string, optionalDefaultValue ...int) int {
|
||||||
|
|
||||||
|
defaultValue := -1
|
||||||
|
message := "Please choose an option"
|
||||||
fmt.Println(question + ":")
|
fmt.Println(question + ":")
|
||||||
|
|
||||||
|
if len(optionalDefaultValue) > 0 {
|
||||||
|
defaultValue = optionalDefaultValue[0] + 1
|
||||||
|
message = fmt.Sprintf("%s [%d]", message, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
for index, option := range options {
|
for index, option := range options {
|
||||||
fmt.Printf(" %d: %s\n", index+1, option)
|
fmt.Printf(" %d: %s\n", index+1, option)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
selectedValue := -1
|
selectedValue := -1
|
||||||
|
|
||||||
for {
|
for {
|
||||||
choice := Prompt("Please choose an option")
|
choice := Prompt(message)
|
||||||
|
if choice == "" && defaultValue > -1 {
|
||||||
|
selectedValue = defaultValue - 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
// index
|
// index
|
||||||
number, err := strconv.Atoi(choice)
|
number, err := strconv.Atoi(choice)
|
||||||
|
335
cmd/templates.go
335
cmd/templates.go
@ -3,112 +3,95 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"log"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
mewn "github.com/leaanthony/mewn"
|
||||||
|
mewnlib "github.com/leaanthony/mewn/lib"
|
||||||
|
"github.com/leaanthony/slicer"
|
||||||
)
|
)
|
||||||
|
|
||||||
const templateSuffix = ".template"
|
// TemplateMetadata holds all the metadata for a Wails template
|
||||||
|
type TemplateMetadata struct {
|
||||||
// TemplateHelper helps with creating projects
|
Name string `json:"name"`
|
||||||
type TemplateHelper struct {
|
ShortDescription string `json:"shortdescription"`
|
||||||
system *SystemHelper
|
Description string `json:"description"`
|
||||||
fs *FSHelper
|
Install string `json:"install"`
|
||||||
templateDir string
|
Build string `json:"build"`
|
||||||
// templates map[string]string
|
Author string `json:"author"`
|
||||||
templateSuffix string
|
Created string `json:"created"`
|
||||||
metadataFilename string
|
FrontendDir string `json:"frontenddir"`
|
||||||
|
Serve string `json:"serve"`
|
||||||
|
Bridge string `json:"bridge"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Template defines a single template
|
// TemplateDetails holds information about a specific template
|
||||||
|
type TemplateDetails struct {
|
||||||
|
BasePath string
|
||||||
|
Path string
|
||||||
|
Metadata *TemplateMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
// TemplateList is a list of available templates
|
||||||
|
type TemplateList struct {
|
||||||
|
details map[string]*TemplateDetails
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTemplateList creates a new TemplateList object
|
||||||
|
func NewTemplateList(filenames *mewnlib.FileGroup) *TemplateList {
|
||||||
|
// Iterate each template and store information
|
||||||
|
|
||||||
|
result := &TemplateList{details: make(map[string]*TemplateDetails)}
|
||||||
|
|
||||||
|
entries := slicer.String()
|
||||||
|
entries.AddSlice(filenames.Entries())
|
||||||
|
|
||||||
|
// Find all template.json files
|
||||||
|
metadataFiles := entries.Filter(func(filename string) bool {
|
||||||
|
match, _ := regexp.MatchString("(.)+template.json$", filename)
|
||||||
|
return match
|
||||||
|
})
|
||||||
|
|
||||||
|
// Load each metadata file
|
||||||
|
metadataFiles.Each(func(filename string) {
|
||||||
|
fileData := filenames.Bytes(filename)
|
||||||
|
var metadata TemplateMetadata
|
||||||
|
err := json.Unmarshal(fileData, &metadata)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("corrupt metadata for template: %s", filename)
|
||||||
|
}
|
||||||
|
path := strings.Split(filename, string(filepath.Separator))[0]
|
||||||
|
thisTemplate := &TemplateDetails{Path: path, Metadata: &metadata}
|
||||||
|
result.details[filename] = thisTemplate
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template holds details about a Wails template
|
||||||
type Template struct {
|
type Template struct {
|
||||||
Name string
|
Name string
|
||||||
Dir string
|
Path string
|
||||||
Metadata map[string]interface{}
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TemplateHelper is a utility object to help with processing templates
|
||||||
|
type TemplateHelper struct {
|
||||||
|
TemplateList *TemplateList
|
||||||
|
Files *mewnlib.FileGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTemplateHelper creates a new template helper
|
// NewTemplateHelper creates a new template helper
|
||||||
func NewTemplateHelper() *TemplateHelper {
|
func NewTemplateHelper() *TemplateHelper {
|
||||||
result := TemplateHelper{
|
files := mewn.Group("./templates")
|
||||||
system: NewSystemHelper(),
|
|
||||||
fs: NewFSHelper(),
|
|
||||||
templateSuffix: ".template",
|
|
||||||
metadataFilename: "template.json",
|
|
||||||
}
|
|
||||||
// Calculate template base dir
|
|
||||||
_, filename, _, _ := runtime.Caller(1)
|
|
||||||
result.templateDir = filepath.Join(path.Dir(filename), "templates")
|
|
||||||
// result.templateDir = filepath.Join(result.system.homeDir, "go", "src", "github.com", "wailsapp", "wails", "cmd", "templates")
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTemplateNames returns a map of all available templates
|
return &TemplateHelper{
|
||||||
func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) {
|
TemplateList: NewTemplateList(files),
|
||||||
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
|
Files: files,
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return templateDirs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTemplateDetails returns a map of Template structs containing details
|
|
||||||
// of the found templates
|
|
||||||
func (t *TemplateHelper) GetTemplateDetails() (map[string]*Template, error) {
|
|
||||||
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make(map[string]*Template)
|
|
||||||
|
|
||||||
for name, dir := range templateDirs {
|
|
||||||
result[name] = &Template{
|
|
||||||
Dir: dir,
|
|
||||||
}
|
|
||||||
metadata, err := t.LoadMetadata(dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result[name].Metadata = metadata
|
|
||||||
if metadata["name"] != nil {
|
|
||||||
result[name].Name = metadata["name"].(string)
|
|
||||||
} else {
|
|
||||||
// Ignore bad templates?
|
|
||||||
result[name] = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadMetadata loads the template's 'metadata.json' file
|
|
||||||
func (t *TemplateHelper) LoadMetadata(dir string) (map[string]interface{}, error) {
|
|
||||||
templateFile := filepath.Join(dir, t.metadataFilename)
|
|
||||||
result := make(map[string]interface{})
|
|
||||||
if !t.fs.FileExists(templateFile) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
rawJSON, err := ioutil.ReadFile(templateFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(rawJSON, &result)
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TemplateExists returns true if the given template name exists
|
|
||||||
func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) {
|
|
||||||
templates, err := t.GetTemplateNames()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
_, exists := templates[templateName]
|
|
||||||
return exists, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InstallTemplate installs the template given in the project options to the
|
// InstallTemplate installs the template given in the project options to the
|
||||||
@ -116,162 +99,56 @@ func (t *TemplateHelper) TemplateExists(templateName string) (bool, error) {
|
|||||||
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
|
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
|
||||||
|
|
||||||
// Get template files
|
// Get template files
|
||||||
template, err := t.getTemplateFiles(projectOptions.Template)
|
templatePath := projectOptions.selectedTemplate.Path
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy files to target
|
templateFilenames := slicer.String()
|
||||||
err = template.Install(projectPath, projectOptions)
|
templateFilenames.AddSlice(projectOptions.templates.Files.Entries())
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
templateJSONFilename := filepath.Join(templatePath, "template.json")
|
||||||
}
|
|
||||||
|
|
||||||
// templateFiles categorises files found in a template
|
templateFiles := templateFilenames.Filter(func(filename string) bool {
|
||||||
type templateFiles struct {
|
return strings.HasPrefix(filename, templatePath) && filename != templateJSONFilename
|
||||||
BaseDir string
|
|
||||||
StandardFiles []string
|
|
||||||
Templates []string
|
|
||||||
Dirs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// newTemplateFiles returns a new TemplateFiles struct
|
|
||||||
func (t *TemplateHelper) newTemplateFiles(dir string) *templateFiles {
|
|
||||||
pathsep := string(os.PathSeparator)
|
|
||||||
// Ensure base directory has trailing slash
|
|
||||||
if !strings.HasSuffix(dir, pathsep) {
|
|
||||||
dir = dir + pathsep
|
|
||||||
}
|
|
||||||
return &templateFiles{
|
|
||||||
BaseDir: dir,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddStandardFile adds the given file to the list of standard files
|
|
||||||
func (t *templateFiles) AddStandardFile(filename string) {
|
|
||||||
localPath := strings.TrimPrefix(filename, t.BaseDir)
|
|
||||||
t.StandardFiles = append(t.StandardFiles, localPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddTemplate adds the given file to the list of template files
|
|
||||||
func (t *templateFiles) AddTemplate(filename string) {
|
|
||||||
localPath := strings.TrimPrefix(filename, t.BaseDir)
|
|
||||||
t.Templates = append(t.Templates, localPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddDir adds the given directory to the list of template dirs
|
|
||||||
func (t *templateFiles) AddDir(dir string) {
|
|
||||||
localPath := strings.TrimPrefix(dir, t.BaseDir)
|
|
||||||
t.Dirs = append(t.Dirs, localPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getTemplateFiles returns a struct categorising files in
|
|
||||||
// the template directory
|
|
||||||
func (t *TemplateHelper) getTemplateFiles(templateName string) (*templateFiles, error) {
|
|
||||||
|
|
||||||
templates, err := t.GetTemplateNames()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
templateDir := templates[templateName]
|
|
||||||
result := t.newTemplateFiles(templateDir)
|
|
||||||
var localPath string
|
|
||||||
err = filepath.Walk(templateDir, func(dir string, info os.FileInfo, err error) error {
|
|
||||||
if dir == templateDir {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't copy template metadata
|
|
||||||
localPath = strings.TrimPrefix(dir, templateDir+string(filepath.Separator))
|
|
||||||
if localPath == t.metadataFilename {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Categorise the file
|
|
||||||
switch {
|
|
||||||
case info.IsDir():
|
|
||||||
result.AddDir(dir)
|
|
||||||
case strings.HasSuffix(info.Name(), templateSuffix):
|
|
||||||
result.AddTemplate(dir)
|
|
||||||
default:
|
|
||||||
result.AddStandardFile(dir)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error processing template '%s' in path '%q': %v", templateName, templateDir, err)
|
|
||||||
}
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install the template files into the given project path
|
|
||||||
func (t *templateFiles) Install(projectPath string, projectOptions *ProjectOptions) error {
|
|
||||||
|
|
||||||
fs := NewFSHelper()
|
|
||||||
|
|
||||||
// Create directories
|
|
||||||
var targetDir string
|
|
||||||
for _, dirname := range t.Dirs {
|
|
||||||
targetDir = filepath.Join(projectPath, dirname)
|
|
||||||
fs.MkDir(targetDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy standard files
|
|
||||||
var targetFile, sourceFile string
|
|
||||||
var err error
|
var err error
|
||||||
for _, filename := range t.StandardFiles {
|
templateFiles.Each(func(templateFile string) {
|
||||||
sourceFile = filepath.Join(t.BaseDir, filename)
|
|
||||||
targetFile = filepath.Join(projectPath, filename)
|
|
||||||
|
|
||||||
err = fs.CopyFile(sourceFile, targetFile)
|
// Setup filenames
|
||||||
|
relativeFilename := strings.TrimPrefix(templateFile, templatePath)[1:]
|
||||||
|
targetFilename, err := filepath.Abs(filepath.Join(projectOptions.OutputDirectory, relativeFilename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
filedata := projectOptions.templates.Files.Bytes(templateFile)
|
||||||
|
|
||||||
// Do we have template files?
|
// If file is a template, process it
|
||||||
if len(t.Templates) > 0 {
|
if strings.HasSuffix(templateFile, ".template") {
|
||||||
|
templateData := projectOptions.templates.Files.String(templateFile)
|
||||||
// Iterate over the templates
|
tmpl := template.New(templateFile)
|
||||||
var templateFile string
|
tmpl.Parse(templateData)
|
||||||
var tmpl *template.Template
|
|
||||||
for _, filename := range t.Templates {
|
|
||||||
|
|
||||||
// Load template text
|
|
||||||
templateFile = filepath.Join(t.BaseDir, filename)
|
|
||||||
templateText, err := fs.LoadAsString(templateFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply template
|
|
||||||
tmpl = template.New(templateFile)
|
|
||||||
tmpl.Parse(templateText)
|
|
||||||
|
|
||||||
// Write the template to a buffer
|
|
||||||
var tpl bytes.Buffer
|
var tpl bytes.Buffer
|
||||||
err = tmpl.Execute(&tpl, projectOptions)
|
err = tmpl.Execute(&tpl, projectOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("ERROR!!! " + err.Error())
|
return
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save buffer to disk
|
// Remove template suffix
|
||||||
targetFilename := strings.TrimSuffix(filename, templateSuffix)
|
targetFilename = strings.TrimSuffix(targetFilename, ".template")
|
||||||
targetFile = filepath.Join(projectPath, targetFilename)
|
|
||||||
err = ioutil.WriteFile(targetFile, tpl.Bytes(), 0644)
|
// Set the filedata to the template result
|
||||||
|
filedata = tpl.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal file, just copy it
|
||||||
|
err = fs.CreateFile(targetFilename, filedata)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ Any flags that are required and not given will be prompted for.`
|
|||||||
LongDescription(commandDescription).
|
LongDescription(commandDescription).
|
||||||
BoolFlag("f", "Use defaults", &projectOptions.UseDefaults).
|
BoolFlag("f", "Use defaults", &projectOptions.UseDefaults).
|
||||||
StringFlag("dir", "Directory to create project in", &projectOptions.OutputDirectory).
|
StringFlag("dir", "Directory to create project in", &projectOptions.OutputDirectory).
|
||||||
StringFlag("template", "Template name", &projectOptions.Template).
|
// StringFlag("template", "Template name", &projectOptions.Template).
|
||||||
StringFlag("name", "Project name", &projectOptions.Name).
|
StringFlag("name", "Project name", &projectOptions.Name).
|
||||||
StringFlag("description", "Project description", &projectOptions.Description).
|
StringFlag("description", "Project description", &projectOptions.Description).
|
||||||
StringFlag("output", "Output binary name", &projectOptions.BinaryName)
|
StringFlag("output", "Output binary name", &projectOptions.BinaryName)
|
||||||
|
4
go.mod
4
go.mod
@ -27,8 +27,8 @@ require (
|
|||||||
github.com/grpc-ecosystem/grpc-gateway v1.7.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway v1.7.0 // indirect
|
||||||
github.com/jackmordaunt/icns v1.0.0
|
github.com/jackmordaunt/icns v1.0.0
|
||||||
github.com/kisielk/errcheck v1.2.0 // indirect
|
github.com/kisielk/errcheck v1.2.0 // indirect
|
||||||
github.com/leaanthony/mewn v0.9.1
|
github.com/leaanthony/mewn v0.9.4
|
||||||
github.com/leaanthony/slicer v1.0.0
|
github.com/leaanthony/slicer v1.2.0
|
||||||
github.com/leaanthony/spinner v0.5.0
|
github.com/leaanthony/spinner v0.5.0
|
||||||
github.com/mattn/go-colorable v0.1.0 // indirect
|
github.com/mattn/go-colorable v0.1.0 // indirect
|
||||||
github.com/microcosm-cc/bluemonday v1.0.2 // indirect
|
github.com/microcosm-cc/bluemonday v1.0.2 // indirect
|
||||||
|
4
go.sum
4
go.sum
@ -101,8 +101,12 @@ github.com/leaanthony/mewn v0.9.0 h1:GExA7M15ikWytAIBKgs9SDl9EOC04JSjvL29qiLTAq4
|
|||||||
github.com/leaanthony/mewn v0.9.0/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
github.com/leaanthony/mewn v0.9.0/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
||||||
github.com/leaanthony/mewn v0.9.1 h1:+qmAnR5nETU/00o5wvYJ7w9Y36R9uIBRB9I15E9Ru8A=
|
github.com/leaanthony/mewn v0.9.1 h1:+qmAnR5nETU/00o5wvYJ7w9Y36R9uIBRB9I15E9Ru8A=
|
||||||
github.com/leaanthony/mewn v0.9.1/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
github.com/leaanthony/mewn v0.9.1/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
||||||
|
github.com/leaanthony/mewn v0.9.4 h1:thDAdV8DkCwqHcFLnfMLQtTHqK1N8leF7sD/SPsLMHI=
|
||||||
|
github.com/leaanthony/mewn v0.9.4/go.mod h1:CRkTx8unLiSSilu/Sd7i1LwrdaAL+3eQ3ses99qGMEQ=
|
||||||
github.com/leaanthony/slicer v1.0.0 h1:BV2CySexcZ20qyHp5qBTxQhsazR6e8MBTF1EHmGu1xw=
|
github.com/leaanthony/slicer v1.0.0 h1:BV2CySexcZ20qyHp5qBTxQhsazR6e8MBTF1EHmGu1xw=
|
||||||
github.com/leaanthony/slicer v1.0.0/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
github.com/leaanthony/slicer v1.0.0/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
||||||
|
github.com/leaanthony/slicer v1.2.0 h1:XZ+1l7cCO36j238iv5ZXkJAcM3hPtD0xb41/WE+QmuU=
|
||||||
|
github.com/leaanthony/slicer v1.2.0/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
||||||
github.com/leaanthony/spinner v0.5.0 h1:HQykt/iTy7fmINEREtRbWrt+8j4MxC8dtvWBxEWM9oA=
|
github.com/leaanthony/spinner v0.5.0 h1:HQykt/iTy7fmINEREtRbWrt+8j4MxC8dtvWBxEWM9oA=
|
||||||
github.com/leaanthony/spinner v0.5.0/go.mod h1:8TSFz9SL1AUC4XSbEFYE6SfN5Mlus51qYluVGrie9ww=
|
github.com/leaanthony/spinner v0.5.0/go.mod h1:8TSFz9SL1AUC4XSbEFYE6SfN5Mlus51qYluVGrie9ww=
|
||||||
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
|
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user