mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-03 05:00:31 +08:00
278 lines
6.8 KiB
Go
278 lines
6.8 KiB
Go
package cmd
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"text/template"
|
|
)
|
|
|
|
const templateSuffix = ".template"
|
|
|
|
// TemplateHelper helps with creating projects
|
|
type TemplateHelper struct {
|
|
system *SystemHelper
|
|
fs *FSHelper
|
|
templateDir string
|
|
// templates map[string]string
|
|
templateSuffix string
|
|
metadataFilename string
|
|
}
|
|
|
|
// Template defines a single template
|
|
type Template struct {
|
|
Name string
|
|
Dir string
|
|
Metadata map[string]interface{}
|
|
}
|
|
|
|
// NewTemplateHelper creates a new template helper
|
|
func NewTemplateHelper() *TemplateHelper {
|
|
result := TemplateHelper{
|
|
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
|
|
func (t *TemplateHelper) GetTemplateNames() (map[string]string, error) {
|
|
templateDirs, err := t.fs.GetSubdirs(t.templateDir)
|
|
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
|
|
// project path given
|
|
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
|
|
|
|
// Get template files
|
|
template, err := t.getTemplateFiles(projectOptions.Template)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Copy files to target
|
|
err = template.Install(projectPath, projectOptions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// templateFiles categorises files found in a template
|
|
type templateFiles struct {
|
|
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
|
|
for _, filename := range t.StandardFiles {
|
|
sourceFile = filepath.Join(t.BaseDir, filename)
|
|
targetFile = filepath.Join(projectPath, filename)
|
|
|
|
err = fs.CopyFile(sourceFile, targetFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Do we have template files?
|
|
if len(t.Templates) > 0 {
|
|
|
|
// Iterate over the templates
|
|
var templateFile string
|
|
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
|
|
err = tmpl.Execute(&tpl, projectOptions)
|
|
if err != nil {
|
|
fmt.Println("ERROR!!! " + err.Error())
|
|
return err
|
|
}
|
|
|
|
// Save buffer to disk
|
|
targetFilename := strings.TrimSuffix(filename, templateSuffix)
|
|
targetFile = filepath.Join(projectPath, targetFilename)
|
|
err = ioutil.WriteFile(targetFile, tpl.Bytes(), 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|