提交 cb5dc7af 编写于 作者: yanghye's avatar yanghye

energy command-line tools: build - windows

上级 4bdd6545
......@@ -10,11 +10,68 @@
package assets
import "embed"
import (
"embed"
"errors"
"fmt"
"github.com/energye/energy/v2/cmd/internal/project"
"github.com/energye/energy/v2/cmd/internal/tools"
"io/fs"
"os"
"path/filepath"
)
//go:embed assets
var assets embed.FS
func ReadFile(name string) ([]byte, error) {
return assets.ReadFile(name)
// AssetsPath 返回配置资源目录
func AssetsPath(projectData *project.Project, file string) string {
return filepath.ToSlash(filepath.Join(projectData.AssetsDir, file))
}
// BuildOutPath 返回固定构建输出目录 $current/build
func BuildOutPath(projectData *project.Project) string {
return filepath.Join(projectData.ProjectPath, "build")
}
// ReadFile
// 读取文件,根据项目配置先在本地目录读取,如果读取失败,则在内置资源目录读取
func ReadFile(projectData *project.Project, assetsFSPath, file string) ([]byte, error) {
var (
content []byte
err error
)
if projectData != nil {
localFilePath := AssetsPath(projectData, file)
content, err = os.ReadFile(localFilePath)
}
if errors.Is(err, fs.ErrNotExist) || content == nil {
content, err = assets.ReadFile(assetsFSPath + file)
if err != nil {
return nil, err
}
return content, nil
}
return content, err
}
// WriteFile 写文件到本地目录
func WriteFile(projectData *project.Project, file string, content []byte) error {
buildOutDir := BuildOutPath(projectData)
if !tools.IsExist(buildOutDir) {
if err := os.MkdirAll(buildOutDir, 0755); err != nil {
return fmt.Errorf("unable to create directory: %w", err)
}
}
targetPath := filepath.Join(buildOutDir, file)
if !projectData.Clean {
if tools.IsExist(targetPath) {
return nil
}
}
if err := os.WriteFile(targetPath, content, 0644); err != nil {
return err
}
return nil
}
{
"fixed": {
"file_version": "{{.Info.FileVersion}}"
},
"info": {
"0000": {
"ProductVersion": "{{.Info.ProductVersion}}",
"CompanyName": "{{.Info.CompanyName}}",
"FileDescription": "{{.Info.ProductName}}",
"LegalCopyright": "{{.Info.Copyright}}",
"ProductName": "{{.Info.ProductName}}",
"Comments": "{{.Info.Comments}}"
}
}
}
\ No newline at end of file
......@@ -12,6 +12,10 @@ package build
import "github.com/energye/energy/v2/cmd/internal/command"
const (
assetsFSPath = "assets/build/"
)
func Build(c *command.Config) error {
return build(c)
}
......@@ -14,10 +14,26 @@
package build
import (
"bytes"
"fmt"
"github.com/energye/energy/v2/cmd/internal/assets"
"github.com/energye/energy/v2/cmd/internal/command"
"github.com/energye/energy/v2/cmd/internal/project"
"github.com/energye/energy/v2/cmd/internal/tools"
"github.com/energye/energy/v2/pkgs/winicon"
"github.com/energye/energy/v2/pkgs/winres"
"github.com/energye/energy/v2/pkgs/winres/version"
"io/fs"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
)
const (
windowManifest = "windows/app.exe.manifest"
windowVersionInfo = "windows/version.info.json"
)
// 构建windows执行程序
......@@ -26,14 +42,116 @@ import (
// upx
func build(c *command.Config) error {
// 读取项目配置文件 energy.json 在main函数目录
// test
var path = filepath.ToSlash("E:\\SWT\\gopath\\src\\github.com\\energye\\energy\\demo")
var app, err = project.NewProject(path)
if err != nil {
c.Package.Path = "E:\\SWT\\gopath\\src\\github.com\\energye\\energy\\demo"
if proj, err := project.NewProject(c.Package.Path); err != nil {
return err
} else {
var (
iconPath string
syso string
)
if iconPath, err = generaICON(proj); err != nil {
return err
}
defer func() {
if syso != "" {
os.Remove(syso)
}
}()
if syso, err = generaSYSO(iconPath, proj); err != nil {
return err
}
}
fmt.Println(app)
// 生成exe图标
return nil
}
func generaSYSO(iconPath string, proj *project.Project) (string, error) {
rs := &winres.ResourceSet{}
iconFile, err := os.Open(iconPath)
if err != nil {
return "", err
}
defer iconFile.Close()
ico, err := winres.LoadICO(iconFile)
if err != nil {
return "", fmt.Errorf("couldn't load icon from icon.ico: %w", err)
}
err = rs.SetIcon(winres.RT_ICON, ico)
if err != nil {
return "", err
}
manifestData, err := assets.ReadFile(proj, assetsFSPath, windowManifest)
if err != nil {
return "", err
}
xmlData, err := winres.AppManifestFromXML(manifestData)
if err != nil {
return "", err
}
rs.SetManifest(xmlData)
versionInfo, err := assets.ReadFile(proj, assetsFSPath, windowVersionInfo)
if err != nil {
return "", err
}
data := make(map[string]any)
data["Info"] = proj.Info
versionInfo, err = tools.RenderTemplate(string(versionInfo), data)
if err != nil {
return "", err
}
if len(versionInfo) != 0 {
var v version.Info
if err := v.UnmarshalJSON(versionInfo); err != nil {
return "", err
}
rs.SetVersionInfo(v)
}
targetFile := filepath.Join(proj.ProjectPath, fmt.Sprintf("%s-%s.syso", proj.Name, runtime.GOOS))
fout, err := os.Create(targetFile)
if err != nil {
return "", err
}
defer fout.Close()
archs := map[string]winres.Arch{
"amd64": winres.ArchAMD64,
"arm64": winres.ArchARM64,
"386": winres.ArchI386,
}
targetArch, supported := archs[runtime.GOARCH]
if !supported {
return targetFile, fmt.Errorf("arch '%s' not supported", runtime.GOARCH)
}
err = rs.WriteObject(fout, targetArch)
if err != nil {
return targetFile, err
}
return targetFile, nil
}
func generaICON(proj *project.Project) (string, error) {
iconPath := proj.Info.Icon
if !tools.IsExist(iconPath) {
return "", fs.ErrNotExist
}
iconExt := filepath.Ext(iconPath)
if strings.ToLower(iconExt) == ".png" {
// png => ico
content, err := ioutil.ReadFile(iconPath)
if err != nil {
return "", err
}
iconPath = filepath.Join(assets.BuildOutPath(proj), "windows", "icon.ico")
output, err := os.OpenFile(iconPath, os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return "", err
}
defer output.Close()
err = winicon.GenerateIcon(bytes.NewBuffer(content), output, []int{256, 128, 64, 48, 32, 16})
if err != nil {
return "", err
}
}
return iconPath, nil
}
......@@ -71,7 +71,7 @@ func generaProject(c *command.Config) error {
// 读取assets内的文件
var createFile = func(readFilePath, outFilePath string, data map[string]any) error {
// 创建 energy.json template
if fileData, err := assets.ReadFile(readFilePath); err != nil {
if fileData, err := assets.ReadFile(nil, "", readFilePath); err != nil {
return err
} else {
if data != nil {
......
......@@ -20,7 +20,6 @@ import (
"github.com/energye/energy/v2/cmd/internal/project"
"github.com/energye/energy/v2/cmd/internal/tools"
"github.com/energye/golcl/tools/command"
"io/fs"
"os"
"path/filepath"
)
......@@ -45,7 +44,7 @@ func GeneraInstaller(projectData *project.Project) error {
func windows(projectData *project.Project) error {
// 创建构建输出目录
buildOutDir := buildOutPath(projectData)
buildOutDir := assets.BuildOutPath(projectData)
buildOutDir = filepath.Join(buildOutDir, "windows")
if !tools.IsExist(buildOutDir) {
if err := os.MkdirAll(buildOutDir, 0755); err != nil {
......@@ -53,15 +52,15 @@ func windows(projectData *project.Project) error {
}
}
// 生成安装生成配置文件 nsis.nsi
if nsisData, err := readFile(projectData, windowsNsis); err != nil {
if nsisData, err := assets.ReadFile(projectData, assetsFSPath, windowsNsis); err != nil {
return err
} else {
if err = writeFile(projectData, windowsNsis, nsisData); err != nil {
if err = assets.WriteFile(projectData, windowsNsis, nsisData); err != nil {
return err
}
}
// tools.nsh
if toolsData, err := readFile(projectData, windowsNsisTools); err != nil {
if toolsData, err := assets.ReadFile(projectData, assetsFSPath, windowsNsisTools); err != nil {
return err
} else {
data := make(map[string]any)
......@@ -71,7 +70,7 @@ func windows(projectData *project.Project) error {
data["Info"] = projectData.Info.FromSlash()
if content, err := tools.RenderTemplate(string(toolsData), data); err != nil {
return err
} else if err = writeFile(projectData, windowsNsisTools, content); err != nil {
} else if err = assets.WriteFile(projectData, windowsNsisTools, content); err != nil {
return err
}
}
......@@ -87,75 +86,8 @@ func makeNSIS(projectData *project.Project) error {
cmd.MessageCallback = func(bytes []byte, err error) {
println("makensis:", string(bytes))
}
nsisScriptPath := filepath.Join(buildOutPath(projectData), windowsNsis)
//var binary string
//if consts.IsWindows {
// binary = filepath.Join(projectData.ProjectPath, projectData.Name+".exe")
//} else {
// binary = filepath.Join(projectData.ProjectPath, projectData.Name)
//}
//args = append(args, "-DARG_ENERGY_BINARY="+binary)
//if projectData.Info.InstallPack.License != "" {
// // 授权信息文本目录: ..\LICENSE.txt
// args = append(args, "-DARG_ENERGY_PAGE_LICENSE="+projectData.Info.License)
//}
//if projectData.Info.Language != "" {
// // default English
// // 可选多种语言: SimpChinese, 参考目录: NSIS\Contrib\Language files
// args = append(args, "-DARG_ENERGY_LANGUAGE="+projectData.Info.Language)
//}
////框架目录
//args = append(args, "-DARG_ENERGY_CEF_FRAMEWORK="+projectData.FrameworkPath)
nsisScriptPath := filepath.Join(assets.BuildOutPath(projectData), windowsNsis)
args = append(args, nsisScriptPath)
cmd.Command("makensis", args...)
return nil
}
// 返回配置资源目录
func assetsPath(projectData *project.Project, file string) string {
return filepath.ToSlash(filepath.Join(projectData.AssetsDir, file))
}
// 返回固定构建输出目录 $current/build
func buildOutPath(projectData *project.Project) string {
return filepath.Join(projectData.ProjectPath, "build")
}
// ReadFile
// 读取文件,根据项目配置先在本地目录读取,如果读取失败,则在内置资源目录读取
func readFile(projectData *project.Project, file string) ([]byte, error) {
localFilePath := assetsPath(projectData, file)
content, err := os.ReadFile(localFilePath)
if errors.Is(err, fs.ErrNotExist) {
content, err = assets.ReadFile(assetsFSPath + file)
if err != nil {
return nil, err
}
return content, nil
}
return content, err
}
// 写文件
func writeFile(projectData *project.Project, file string, content []byte) error {
buildOutDir := buildOutPath(projectData)
if !tools.IsExist(buildOutDir) {
if err := os.MkdirAll(buildOutDir, 0755); err != nil {
return fmt.Errorf("unable to create directory: %w", err)
}
}
targetPath := filepath.Join(buildOutDir, file)
if !projectData.Clean {
if tools.IsExist(targetPath) {
return nil
}
}
if err := os.WriteFile(targetPath, content, 0644); err != nil {
return err
}
return nil
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册