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

energy command-line tools: package linux

上级 6d842a91
......@@ -12,7 +12,8 @@
"comments": "Built using ENERGY (https://github.com/energye/energy)"
},
"dpkg": {
"assets": [],
"include": [],
"exclude": ["cache"],
"package": "com.{{.CompanyName}}.{{.CompanyName}}",
"homepage": "https://github.com/energye/energy",
"compress": "7zz"
......
......@@ -15,7 +15,8 @@
"fileDescription": "Built using ENERGY (https://github.com/energye/energy)"
},
"nsis": {
"assets": [],
"include": [],
"exclude": ["cache"],
"icon": "{{.ProjectPath}}/resources/icon.ico",
"unIcon": "{{.ProjectPath}}/resources/icon.ico",
"license": "",
......
......@@ -5,4 +5,5 @@ Name={{.Name}}
Exec={{.Exec}}
Icon={{.Icon}}
Comment={{.Comments}}
Encoding=UTF-8
Categories=Utility;
\ No newline at end of file
......@@ -39,7 +39,7 @@ RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" ; admin or ""
File /r "{{.FrameworkPath}}\*.*"
{{end}}
{{range $i,$path := .NSIS.Assets }}
{{range $i,$path := .NSIS.Include }}
File /r "{{$path}}"{{end}}
!macroend
......
......@@ -21,10 +21,13 @@ import (
"github.com/energye/energy/v2/cmd/internal/project"
"github.com/energye/energy/v2/cmd/internal/term"
"github.com/energye/energy/v2/cmd/internal/tools"
"github.com/energye/golcl/tools/command"
"io"
"io/fs"
"os"
"path/filepath"
"runtime"
"strings"
)
const (
......@@ -57,23 +60,64 @@ func GeneraInstaller(proj *project.Project) error {
}
}
var err error
// create debian/control
if err = linuxControl(proj, appRoot); err != nil {
return err
}
// create debian/copyright
if err = linuxCopyright(proj, appRoot); err != nil {
return err
}
// create app.desktop
if err = linuxDesktop(proj, appRoot); err != nil {
return err
}
if err = linuxOpt(proj, appRoot); err != nil {
// copy source
if err = linuxOptCopy(proj, appRoot); err != nil {
return err
}
// dpkg -b
var debName string
if debName, err = dpkgB(proj); err != nil {
return err
}
// out log
outInstall := filepath.Join(assets.BuildOutPath(proj), "linux", debName)
successLog := "Success \n\tInstall Package: %s\n\tInstall: sudo dpkg -i %s\n\tRemove: sudo dpkg -r %s"
term.Section.Println(fmt.Sprintf(successLog, outInstall, debName, proj.Dpkg.Package))
return nil
}
func dpkgB(proj *project.Project) (string, error) {
dir := filepath.Join(assets.BuildOutPath(proj), "linux")
//sudo dpkg -b demo-1.0.0/ demo-[os]-[arch].deb
app := fmt.Sprintf("%s-%s", proj.Name, proj.Info.ProductVersion)
debName := fmt.Sprintf("%s-%s-%s.deb", proj.Name, runtime.GOOS, runtime.GOARCH)
outFile := filepath.Join(dir, debName)
term.Logger.Info("Generate dpkg package. Almost complete", term.Logger.Args("deb", debName))
cmd := command.NewCMD()
cmd.IsPrint = false
cmd.Dir = dir
var err error
cmd.MessageCallback = func(bytes []byte, e error) {
if e != nil {
err = e
}
}
if tools.IsExist(outFile) {
os.Remove(outFile)
}
var args = []string{"-b", app, debName}
cmd.Command("dpkg", args...)
cmd.Close()
return debName, err
}
func opt(proj *project.Project) string {
return filepath.Join("/opt", proj.Info.CompanyName, proj.Info.ProductName)
}
func linuxOpt(proj *project.Project, appRoot string) error {
func linuxOptCopy(proj *project.Project, appRoot string) error {
term.Logger.Info("Generate dpkg copy:",
term.Logger.Args("company", proj.Info.CompanyName, "product", proj.Info.ProductName, "opt",
fmt.Sprintf("/opt/%s/%s", proj.Info.CompanyName, proj.Info.ProductName)))
......@@ -88,6 +132,11 @@ func linuxOpt(proj *project.Project, appRoot string) error {
if !tools.IsExist(exeDir) {
return fmt.Errorf("execution file not found: %s", exeDir)
}
exeIconDir := proj.Info.Icon
if !tools.IsExist(exeIconDir) {
return fmt.Errorf("execution file not found: %s", exeDir)
}
term.Logger.Info("Generate dpkg execution " + exeDir)
cefDir := os.Getenv(consts.EnergyHomeKey)
if !tools.IsExist(cefDir) {
......@@ -98,14 +147,53 @@ func linuxOpt(proj *project.Project, appRoot string) error {
if srcFile, err := os.Open(src); err != nil {
return err
} else {
defer srcFile.Close()
st, err := srcFile.Stat()
if err != nil {
return err
}
if st.IsDir() {
srcFile.Close() //close
var pathLen = len(src)
err := filepath.WalkDir(src, func(path string, d fs.DirEntry, err error) error {
if path == src { // current root
return nil
}
outPath := path[pathLen:]
// exclude file or dir
for _, p := range proj.Dpkg.Exclude {
if strings.Contains(outPath, p) {
return nil
}
}
targetPath := filepath.Join(dst, outPath)
info, _ := d.Info()
if d.IsDir() {
return os.MkdirAll(targetPath, info.Mode())
} else {
if tools.IsExistAndSize(targetPath, info.Size()) {
term.Logger.Info("\tcopy skip: " + outPath)
return nil
}
srcFile, err := os.Open(path)
if err != nil {
return err
}
defer srcFile.Close()
dstFile, err := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY, info.Mode())
if err != nil {
return err
}
defer dstFile.Close()
term.Logger.Info("\tcopy: " + outPath)
_, err = io.Copy(dstFile, srcFile)
return err
}
})
if err != nil {
return err
}
} else {
defer srcFile.Close()
dstFilePath := filepath.Join(dst, st.Name())
dstFile, err := os.OpenFile(dstFilePath, os.O_CREATE|os.O_WRONLY, st.Mode())
if err != nil {
......@@ -122,11 +210,15 @@ func linuxOpt(proj *project.Project, appRoot string) error {
}
term.Logger.Info("Generate dpkg copy:", term.Logger.Args("execution", exeDir))
if err := copyFiles(exeDir, optDir); err != nil {
return nil
return err
}
term.Logger.Info("Generate dpkg copy:", term.Logger.Args("icon", exeIconDir))
if err := copyFiles(exeIconDir, optDir); err != nil {
return err
}
term.Logger.Info("Generate dpkg copy:", term.Logger.Args("framework", cefDir))
if err := copyFiles(cefDir, optDir); err != nil {
return nil
return err
}
return nil
}
......@@ -162,6 +254,11 @@ func linuxDesktop(proj *project.Project, appRoot string) error {
return nil
}
func linuxCopyright(proj *project.Project, appRoot string) error {
term.Logger.Info("Generate dpkg copyright")
return nil
}
func linuxControl(proj *project.Project, appRoot string) error {
term.Logger.Info("Generate dpkg control")
buildOutDir := assets.BuildOutPath(proj)
......
......@@ -134,7 +134,8 @@ func windows(proj *project.Project) error {
// 使用nsis生成安装包
func makeNSIS(proj *project.Project) (string, error) {
term.Logger.Info("NSIS Making Installation, Almost complete")
installPackage := proj.Name + "-installer.exe"
term.Logger.Info("NSIS Making Installation, Almost complete", term.Logger.Args("Install Package", installPackage))
var args []string
cmd := command.NewCMD()
cmd.IsPrint = false
......@@ -145,6 +146,6 @@ func makeNSIS(proj *project.Project) (string, error) {
nsisScriptPath := filepath.Join(assets.BuildOutPath(proj), windowsNsis)
args = append(args, nsisScriptPath)
cmd.Command("makensis", args...)
outInstall := filepath.Join(filepath.Dir(nsisScriptPath), proj.Name+"-installer.exe")
outInstall := filepath.Join(filepath.Dir(nsisScriptPath), installPackage)
return outInstall, nil
}
......@@ -109,23 +109,24 @@ func (m *Info) ToSlash() {
func (m *NSIS) FromSlash() {
m.Icon = filepath.FromSlash(m.Icon)
m.UnIcon = filepath.FromSlash(m.UnIcon)
for i, as := range m.Assets {
m.Assets[i] = filepath.FromSlash(as)
for i, as := range m.Include {
m.Include[i] = filepath.FromSlash(as)
}
}
func (m *NSIS) ToSlash() {
m.Icon = filepath.ToSlash(m.Icon)
m.UnIcon = filepath.ToSlash(m.UnIcon)
for i, as := range m.Assets {
m.Assets[i] = filepath.ToSlash(as)
for i, as := range m.Include {
m.Include[i] = filepath.ToSlash(as)
}
}
// NSIS windows NSIS
type NSIS struct {
Icon string `json:"icon"` //安装包图标
Assets []string `json:"assets"` //打包的资源目录、或文件 ["/to/path/file.txt", "/to/dir/*.*", "/to/dir"]
Include []string `json:"include"` //打包资源目录、或文件 ["/to/path/file.txt", "/to/dir/*.*", "/to/dir"]
Exclude []string `json:"exclude"` //打包排除资源目录、或文件 ["/to/path/file.txt", "/to/dir/*.*", "/to/dir"]
UnIcon string `json:"unIcon"` //安装包卸载图标
License string `json:"license"` //安装包授权信息,(license.txt)文件路径
Language string `json:"language"` //安装包语言, 中文: SimpChinese, 英文: English, 语言在 NSIS_HOME/Contrib/Language files
......@@ -136,7 +137,8 @@ type NSIS struct {
}
type DPKG struct {
Assets []string `json:"assets"` //打包的资源目录、或文件 ["/to/path/file.txt", "/to/dir/*.*", "/to/dir"]
Include []string `json:"include"` //打包资源目录、或文件 ["/to/path/file.txt", "/to/dir/*.*", "/to/dir"]
Exclude []string `json:"exclude"` //打包排除资源目录、或文件 ["/to/path/file.txt", "/to/dir/*.*", "/to/dir"]
Package string `json:"package"`
Homepage string `json:"homepage"`
Compress string `json:"compress"` //压纹CEF, 当前仅支持7z/a压缩,""(空)时不启用压缩 默认: 7za
......
......@@ -106,6 +106,19 @@ func IsExist(path string) bool {
return true
}
func IsExistAndSize(path string, size int64) bool {
s, err := os.Stat(path)
if err != nil {
if os.IsExist(err) && s.Size() == size {
return true
} else if os.IsNotExist(err) {
return false
}
return false
}
return true
}
func RenderTemplate(templateText string, data map[string]any) ([]byte, error) {
tmpl, err := template.New("").Parse(templateText)
if err != nil {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册