mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-03 02:19:43 +08:00

The io/ioutil package has been deprecated as of Go 1.16, see https://golang.org/doc/go1.16#ioutil. This commit replaces the existing io/ioutil functions with their new definitions in io and os packages. Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
271 lines
7.4 KiB
Go
271 lines
7.4 KiB
Go
package cmd
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"github.com/kennygrant/sanitize"
|
|
"github.com/leaanthony/slicer"
|
|
)
|
|
|
|
// TemplateMetadata holds all the metadata for a Wails template
|
|
type TemplateMetadata struct {
|
|
Name string `json:"name"`
|
|
Version string `json:"version"`
|
|
ShortDescription string `json:"shortdescription"`
|
|
Description string `json:"description"`
|
|
Install string `json:"install"`
|
|
Build string `json:"build"`
|
|
Author string `json:"author"`
|
|
Created string `json:"created"`
|
|
FrontendDir string `json:"frontenddir"`
|
|
Serve string `json:"serve"`
|
|
Bridge string `json:"bridge"`
|
|
WailsDir string `json:"wailsdir"`
|
|
TemplateDependencies []*TemplateDependency `json:"dependencies,omitempty"`
|
|
|
|
// List of platforms that this template is supported on.
|
|
// No value means all platforms. A platform name is the same string
|
|
// as `runtime.GOOS` will return, eg: "darwin". NOTE: This is
|
|
// case sensitive.
|
|
Platforms []string `json:"platforms,omitempty"`
|
|
}
|
|
|
|
// PlatformSupported returns true if this template supports the
|
|
// currently running platform
|
|
func (m *TemplateMetadata) PlatformSupported() bool {
|
|
|
|
// Default is all platforms supported
|
|
if len(m.Platforms) == 0 {
|
|
return true
|
|
}
|
|
|
|
// Check that the platform is in the list
|
|
platformsSupported := slicer.String(m.Platforms)
|
|
return platformsSupported.Contains(runtime.GOOS)
|
|
}
|
|
|
|
// TemplateDependency defines a binary dependency for the template
|
|
// EG: ng for angular
|
|
type TemplateDependency struct {
|
|
Bin string `json:"bin"`
|
|
Help string `json:"help"`
|
|
}
|
|
|
|
// TemplateDetails holds information about a specific template
|
|
type TemplateDetails struct {
|
|
Name string
|
|
Path string
|
|
Metadata *TemplateMetadata
|
|
fs *FSHelper
|
|
}
|
|
|
|
// TemplateHelper is a utility object to help with processing templates
|
|
type TemplateHelper struct {
|
|
templateDir *Dir
|
|
fs *FSHelper
|
|
metadataFilename string
|
|
}
|
|
|
|
// NewTemplateHelper creates a new template helper
|
|
func NewTemplateHelper() *TemplateHelper {
|
|
|
|
templateDir, err := fs.LocalDir("./templates")
|
|
if err != nil {
|
|
log.Fatal("Unable to find the template directory. Please reinstall Wails.")
|
|
}
|
|
|
|
return &TemplateHelper{
|
|
templateDir: templateDir,
|
|
metadataFilename: "template.json",
|
|
}
|
|
}
|
|
|
|
// IsValidTemplate returns true if the given template name resides on disk
|
|
func (t *TemplateHelper) IsValidTemplate(templateName string) bool {
|
|
pathToTemplate := filepath.Join(t.templateDir.fullPath, templateName)
|
|
return t.fs.DirExists(pathToTemplate)
|
|
}
|
|
|
|
// SanitizeFilename sanitizes the given string to make a valid filename
|
|
func (t *TemplateHelper) SanitizeFilename(name string) string {
|
|
return sanitize.Name(name)
|
|
}
|
|
|
|
// CreateNewTemplate creates a new template based on the given directory name and string
|
|
func (t *TemplateHelper) CreateNewTemplate(dirname string, details *TemplateMetadata) (string, error) {
|
|
|
|
// Check if this template has already been created
|
|
if t.IsValidTemplate(dirname) {
|
|
return "", fmt.Errorf("cannot create template in directory '%s' - already exists", dirname)
|
|
}
|
|
|
|
targetDir := filepath.Join(t.templateDir.fullPath, dirname)
|
|
err := t.fs.MkDir(targetDir)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
targetMetadata := filepath.Join(targetDir, t.metadataFilename)
|
|
err = t.fs.SaveAsJSON(details, targetMetadata)
|
|
|
|
return targetDir, err
|
|
}
|
|
|
|
// LoadMetadata loads the template's 'metadata.json' file
|
|
func (t *TemplateHelper) LoadMetadata(dir string) (*TemplateMetadata, error) {
|
|
templateFile := filepath.Join(dir, t.metadataFilename)
|
|
result := &TemplateMetadata{}
|
|
if !t.fs.FileExists(templateFile) {
|
|
return nil, nil
|
|
}
|
|
rawJSON, err := os.ReadFile(templateFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(rawJSON, &result)
|
|
return result, err
|
|
}
|
|
|
|
// GetTemplateDetails returns a map of Template structs containing details
|
|
// of the found templates
|
|
func (t *TemplateHelper) GetTemplateDetails() (map[string]*TemplateDetails, error) {
|
|
|
|
// Get the subdirectory details
|
|
templateDirs, err := t.templateDir.GetSubdirs()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make(map[string]*TemplateDetails)
|
|
|
|
for name, dir := range templateDirs {
|
|
result[name] = &TemplateDetails{
|
|
Path: dir,
|
|
}
|
|
metadata, err := t.LoadMetadata(dir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result[name].Metadata = metadata
|
|
if metadata.Name != "" {
|
|
result[name].Name = metadata.Name
|
|
} else {
|
|
// Ignore bad templates?
|
|
result[name] = nil
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// GetTemplateFilenames returns all the filenames of the given template
|
|
func (t *TemplateHelper) GetTemplateFilenames(template *TemplateDetails) (*slicer.StringSlicer, error) {
|
|
|
|
// Get the subdirectory details
|
|
templateDir, err := t.fs.Directory(template.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return templateDir.GetAllFilenames()
|
|
}
|
|
|
|
// InstallTemplate installs the template given in the project options to the
|
|
// project path given
|
|
func (t *TemplateHelper) InstallTemplate(projectPath string, projectOptions *ProjectOptions) error {
|
|
|
|
// Check dependencies before installing
|
|
dependencies := projectOptions.selectedTemplate.Metadata.TemplateDependencies
|
|
if dependencies != nil {
|
|
programHelper := NewProgramHelper()
|
|
logger := NewLogger()
|
|
errors := []string{}
|
|
for _, dep := range dependencies {
|
|
program := programHelper.FindProgram(dep.Bin)
|
|
if program == nil {
|
|
errors = append(errors, dep.Help)
|
|
}
|
|
}
|
|
if len(errors) > 0 {
|
|
mainError := "template dependencies not installed"
|
|
if len(errors) == 1 {
|
|
mainError = errors[0]
|
|
} else {
|
|
for _, error := range errors {
|
|
logger.Red(error)
|
|
}
|
|
}
|
|
return fmt.Errorf(mainError)
|
|
}
|
|
}
|
|
|
|
// Get template files
|
|
templateFilenames, err := t.GetTemplateFilenames(projectOptions.selectedTemplate)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
templatePath := projectOptions.selectedTemplate.Path
|
|
|
|
// Save the version
|
|
projectOptions.WailsVersion = Version
|
|
|
|
templateJSONFilename := filepath.Join(templatePath, t.metadataFilename)
|
|
|
|
templateFiles := templateFilenames.Filter(func(filename string) bool {
|
|
filename = filepath.FromSlash(filename)
|
|
return strings.HasPrefix(filename, templatePath) && filename != templateJSONFilename
|
|
})
|
|
|
|
templateFiles.Each(func(templateFile string) {
|
|
|
|
// Setup filenames
|
|
relativeFilename := strings.TrimPrefix(templateFile, templatePath)[1:]
|
|
targetFilename, err := filepath.Abs(filepath.Join(projectOptions.OutputDirectory, relativeFilename))
|
|
if err != nil {
|
|
return
|
|
}
|
|
filedata, err := t.fs.LoadAsBytes(templateFile)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// If file is a template, process it
|
|
if strings.HasSuffix(templateFile, ".template") {
|
|
templateData := string(filedata)
|
|
tmpl := template.New(templateFile)
|
|
tmpl.Parse(templateData)
|
|
var tpl bytes.Buffer
|
|
err = tmpl.Execute(&tpl, projectOptions)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Remove template suffix
|
|
targetFilename = strings.TrimSuffix(targetFilename, ".template")
|
|
|
|
// 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 {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|