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

energy-command-line, windows 增加 nsis安装选项

上级 489ea789
......@@ -30,7 +30,7 @@ type Command struct {
type Install struct {
Path string `short:"p" long:"path" description:"Installation directory Default current directory"`
Version string `short:"v" long:"version" description:"Specifying a version number"`
Name string `short:"n" long:"name" description:"Name of the frame after installation" default:"EnergyFramework"`
Name string `short:"n" long:"name" description:"Name of the framework directory after installation" default:"EnergyFramework"`
Download string `short:"d" long:"download" description:"Download Source, 0:gitee or 1:github, Default empty" default:""`
CEF string `short:"c" long:"cef" description:"Install system supports CEF version, provide 4 options, default empty. default, windows7, gtk2, flash" default:""`
}
......
......@@ -34,6 +34,13 @@ const (
GolangDefaultVersion = "1.18.10"
)
const (
// NSISDownloadURL 下载地址,默认 3.09
// https://gitee.com/energye/assets/releases/download/environment/nsis.windows.386-3.09.zip
NSISDownloadURL = "https://gitee.com/energye/assets/releases/download/environment/%s"
NSISDownloadVersion = "3.09"
)
const (
CefKey = "cef"
LiblclKey = "liblcl"
......
......@@ -24,6 +24,10 @@ import (
"strings"
)
func SetNSISEnv(nsisRoot string) {
}
func SetGoEnv(goRoot string) {
var goexe = "go"
if command.IsWindows {
......@@ -64,7 +68,7 @@ func SetGoEnv(goRoot string) {
var exGoBin = "export GOBIN=$GOROOT/bin"
var exPath = "export PATH=$PATH:$GOBIN"
var exs = []string{exGoRoot, exGoCache, exGoBin}
setEnv(exs, exPath, "$GOBIN")
setPosixEnv(exs, exPath, "$GOBIN")
}
println("\nHint: Reopen the cmd window for the Go command to take effect.")
}
......@@ -95,13 +99,14 @@ func SetEnergyHomeEnv(homePath string) {
} else {
var energyHome = fmt.Sprintf("export %s=%s", command.EnergyHomeKey, homePath)
exs := []string{energyHome}
setEnv(exs, "", "")
setPosixEnv(exs, "", "")
}
println("\nHint: Reopen the cmd window to make the environment variables take effect.")
}
func setEnv(exs []string, binPath, bin string) {
func setPosixEnv(exs []string, binPath, bin string) {
cmd := toolsCommand.NewCMD()
cmd.IsPrint = false
cmd.MessageCallback = func(s []byte, e error) {
fmt.Println("CMD:", string(s), " error:", e)
}
......@@ -114,8 +119,8 @@ func setEnv(exs []string, binPath, bin string) {
}
homeDir, err := homedir.Dir()
// test
homeDir = "E:\\app"
envFiles = []string{".profile", ".zshrc", ".bashrc"}
//homeDir = "E:\\app"
//envFiles = []string{".profile", ".zshrc", ".bashrc"}
if err != nil {
println(err.Error())
return
......@@ -153,7 +158,12 @@ func setEnv(exs []string, binPath, bin string) {
var lines = strings.Split(content, "\n")
var currentPath string
for i := 0; i < len(lines); i++ {
line := strings.TrimSpace(lines[i])
line := strings.TrimRightFunc(lines[i], func(r rune) bool {
if r == '\n' || r == '\r' {
return true
}
return false
})
// path里是否存在要设置的bin
if binPath != "" && isExportPath(line) {
currentPath = line
......@@ -164,9 +174,9 @@ func setEnv(exs []string, binPath, bin string) {
} else {
newContent.WriteString(line)
}
}
if i < len(lines)-1 {
newContent.WriteString("\n")
if i < len(lines)-1 {
newContent.WriteString("\n")
}
}
}
for _, ext := range tempExts {
......@@ -175,14 +185,17 @@ func setEnv(exs []string, binPath, bin string) {
}
if currentPath != "" { // 不为空说明现有的path里已经存在 bin, 放到最后一行
newContent.WriteString(currentPath)
newContent.WriteString("\n")
} else if binPath != "" { //不为空并且现有的path里没有bin时,自己设置一个带有bin 的 path, 放到最后一行
newContent.WriteString(binPath)
newContent.WriteString("\n")
}
// 有就覆盖掉之前的, 要先关闭掉文件
if err = f.Close(); err == nil {
// 如果任何操作失败, 重新写入覆盖文件
var oldWrite = func() {
if f, err = os.OpenFile(fp, os.O_RDWR, 0666); err == nil {
println("Restore files", file)
f.WriteString(oldContent)
f.Close()
}
......@@ -191,6 +204,7 @@ func setEnv(exs []string, binPath, bin string) {
if newOpenFile, err := os.OpenFile(fp, os.O_RDWR|os.O_TRUNC, 0666); err == nil {
// 写入新的环境配置
if _, err := newOpenFile.Write(newContent.Bytes()); err == nil {
println("Write files success.", file)
newOpenFile.Close()
} else {
//写入失败,把老的内容还原
......
......@@ -221,12 +221,10 @@ func checkEnv(init *command.Init) {
init.INSIS = true
}
// 检查ENERGY_HOME
if !cef() {
if !tools.CheckCEFDir() {
println(`Warning: Dependency framework CEF is not installed or configured to the ENERGY_HOME environment variable
There are several ways to install, configure, or check the environment
"energy install ." Installation and development environment
"energy env ." check ENERGY_HOME are correctly,
"energy setenv -p /to/framework/path ." set ENERGY_HOME environment
`)
} else {
println("\tCEF Framework OK")
......@@ -240,20 +238,3 @@ func checkEnv(init *command.Init) {
init.INpm = true
}
}
func cef() bool {
var lib = func() string {
if command.IsWindows {
return "libcef.dll"
} else if command.IsLinux {
return "libcef.so"
} else if command.IsDarwin {
return "cef_sandbox.a"
}
return ""
}()
if lib != "" {
return tools.IsExist(filepath.Join(os.Getenv("ENERGY_HOME"), lib))
}
return false
}
......@@ -20,8 +20,8 @@ var CmdInstall = &command.Command{
Short: "Automatically configure the CEF and Energy framework",
Long: `
-p Installation directory Default current directory
-v Specifying a version number,Default latest
-n Name of the frame after installation
-v Specifying a version number,Default latest.\
-n Name of the framework directory after installation, Default EnergyFramework.\
-d Download Source, 0:gitee or 1:github, Default empty
-c Install system supports CEF version, provide 4 options, default empty
default : Automatically select support for the latest version based on the current system.
......
......@@ -6,17 +6,14 @@
//
// https://www.apache.org/licenses/LICENSE-2.0
//
//----
package install
import (
"archive/tar"
"archive/zip"
"bytes"
"compress/bzip2"
"compress/gzip"
"encoding/json"
"fmt"
"github.com/energye/energy/v2/cmd/internal/command"
"github.com/energye/energy/v2/cmd/internal/env"
......@@ -25,10 +22,8 @@ import (
"io"
"io/fs"
"net/http"
"net/url"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
)
......@@ -44,23 +39,26 @@ type downloadInfo struct {
}
func Install(c *command.Config) {
// 创建安装目录
// 初始配置和安装目录
initInstall(c)
// 检查Go开发环境
//if !tools.CommandExists("go") {
println("Golang development environment not installed!")
// 如未安装Go开发环境,自动安装Go环境
// 安装Go开发环境
goRoot := installGolang(c)
//goRoot := "C:\\go"
//}
// 安装CEF二进制框架
installCEFFramework(c)
// 设置 energy 环境变量
env.SetEnergyHomeEnv(cefInstallPathName(c))
cefFrameworkRoot := installCEFFramework(c)
// 安装nsis安装包制作工具, 仅windows - amd64
nsisRoot := installNSIS(c)
// 设置nsis环境变量
if nsisRoot != "" {
env.SetNSISEnv(nsisRoot)
}
// 设置 go 环境变量
if goRoot != "" {
env.SetGoEnv(goRoot)
}
// 设置 energy cef 环境变量
if cefFrameworkRoot != "" {
env.SetEnergyHomeEnv(cefFrameworkRoot)
}
}
func cefInstallPathName(c *command.Config) string {
......@@ -82,412 +80,6 @@ func initInstall(c *command.Config) {
os.MkdirAll(filepath.Join(c.Install.Path, command.FrameworkCache), fs.ModePerm)
}
func installGolang(c *command.Config) string {
print("Do you want to install the Go development environment? Y/n: ")
var s string
fmt.Scanln(&s)
if strings.ToLower(s) == "y" {
s = c.Install.Path // 安装目录
exts := map[string]string{
"darwin": "tar.gz",
"linux": "tar.gz",
"windows": "zip",
}
// 开始下载并安装Go开发环境
version := command.GolangDefaultVersion
gos := runtime.GOOS
arch := runtime.GOARCH
//gos = "darwin"
//arch = "amd64"
ext := exts[gos]
if !tools.IsExist(s) {
println("Directory does not exist. Creating directory.", s)
if err := os.MkdirAll(s, fs.ModePerm); err != nil {
println("Failed to create goroot directory", err.Error())
return ""
}
}
fileName := fmt.Sprintf("go%s.%s-%s.%s", version, gos, arch, ext)
downloadUrl := fmt.Sprintf(command.GolangDownloadURL, fileName)
savePath := filepath.Join(s, command.FrameworkCache, fileName)
var err error
println("Golang Download URL:", downloadUrl)
println("Golang Save Path:", savePath)
if !tools.IsExist(savePath) {
// 已经存在不再下载
bar := progressbar.NewBar(100)
bar.SetNotice("\t")
bar.HideRatio()
err = downloadFile(downloadUrl, savePath, func(totalLength, processLength int64) {
bar.PrintBar(int((float64(processLength) / float64(totalLength)) * 100))
})
if err != nil {
bar.PrintEnd("Download [" + fileName + "] failed: " + err.Error())
} else {
bar.PrintEnd("Download [" + fileName + "] success")
}
}
if err == nil {
// 使用 go 名字做为 go 安装目录
targetPath := filepath.Join(s, "go")
// 释放文件
if command.IsWindows {
//zip
ExtractUnZip(savePath, targetPath)
} else {
//tar
ExtractUnTar(savePath, targetPath)
}
return targetPath
}
return ""
}
return ""
}
func installCEFFramework(c *command.Config) {
// 获取提取文件配置
extractData, err := tools.HttpRequestGET(command.DownloadExtractURL)
if err != nil {
fmt.Fprint(os.Stderr, err.Error(), "\n")
os.Exit(1)
}
var extractConfig map[string]any
extractData = bytes.TrimPrefix(extractData, []byte("\xef\xbb\xbf"))
if err := json.Unmarshal(extractData, &extractConfig); err != nil {
fmt.Fprint(os.Stderr, err.Error(), "\n")
os.Exit(1)
}
extractOSConfig := extractConfig[runtime.GOOS].(map[string]any)
// 获取安装版本配置
downloadJSON, err := tools.HttpRequestGET(command.DownloadVersionURL)
if err != nil {
fmt.Fprint(os.Stderr, err.Error()+"\n")
os.Exit(1)
}
var edv map[string]any
downloadJSON = bytes.TrimPrefix(downloadJSON, []byte("\xef\xbb\xbf"))
if err := json.Unmarshal(downloadJSON, &edv); err != nil {
fmt.Fprint(os.Stderr, err.Error()+"\n")
os.Exit(1)
}
// -c cef args value
// default(empty), windows7, gtk2, flash
cef := strings.ToLower(c.Install.CEF)
if cef != command.CefEmpty && cef != command.Cef109 && cef != command.Cef106 && cef != command.Cef87 {
fmt.Fprint(os.Stderr, "-c [cef] Incorrect args value\n")
os.Exit(1)
}
installPathName := cefInstallPathName(c)
println("Install Path", installPathName)
println("Start downloading CEF and Energy dependency")
// 所有版本列表
var versionList = edv["versionList"].(map[string]any)
// 当前安装版本
var installVersion map[string]any
if c.Install.Version == "latest" {
// 默认最新版本
if v, ok := versionList[edv["latest"].(string)]; ok {
installVersion = v.(map[string]any)
}
} else {
// 自己选择版本
if v, ok := versionList[c.Install.Version]; ok {
installVersion = v.(map[string]any)
}
}
println("Check version")
if installVersion == nil || len(installVersion) == 0 {
println("Invalid version number:", c.Install.Version)
os.Exit(1)
}
// 当前版本 cef 和 liblcl 版本选择
var (
cefModuleName, liblclModuleName string
)
// 使用提供的特定版本号
if cef == command.Cef106 {
cefModuleName = "cef-106" // CEF 106.1.1
} else if cef == command.Cef109 {
cefModuleName = "cef-109" // CEF 109.1.18
} else if cef == command.Cef87 {
// cef 87 要和 liblcl 87 配对
cefModuleName = "cef-87" // CEF 87.1.14
liblclModuleName = "liblcl-87" // liblcl 87
}
// 如未指定CEF参数、或参数不正确,选择当前CEF模块最(新)大的版本号
if cefModuleName == "" {
var cefDefault string
var number int
for module, _ := range installVersion {
if strings.Index(module, "cef") == 0 {
if s := strings.Split(module, "-"); len(s) == 2 {
// module = "cef-xxx"
n, _ := strconv.Atoi(s[1])
if n >= number {
number = n
cefDefault = module
}
} else {
// module = "cef"
cefDefault = module
break
}
}
}
cefModuleName = cefDefault
}
// liblcl, 在未指定flash版本时,它是空 ""
if liblclModuleName == "" {
liblclModuleName = "liblcl"
}
// 当前安装版本的所有模块
var modules map[string]any
if m, ok := installVersion["modules"]; ok {
modules = m.(map[string]any)
}
// 根据模块名拿到对应的模块配置
var (
cefModule, liblclModule map[string]any
)
if module, ok := modules[cefModuleName]; ok {
cefModule = module.(map[string]any)
}
if module, ok := modules[liblclModuleName]; ok {
liblclModule = module.(map[string]any)
}
if cefModule == nil {
println("error: cef module", cefModuleName, "is not configured in the current version")
os.Exit(1)
}
// 下载源选择
var replaceSource = func(url, source string, sourceSelect int, module string) string {
s := strings.Split(source, ",")
// liblcl 如果自己选择下载源
if module == "liblcl" && c.Install.Download != "" {
sourceSelect = tools.ToInt(c.Install.Download)
}
if len(s) > sourceSelect {
return strings.ReplaceAll(url, "{source}", s[sourceSelect])
}
return url
}
// 下载集合
var downloads = make(map[string]*downloadInfo)
// 根据模块名拿到版本号
cefVersion := tools.ToRNilString(installVersion[cefModuleName], "")
// 当前模块版本支持系统,如果支持返回下载地址
libCEFOS, isSupport := cefOS(cefModule)
downloadCefURL := tools.ToString(cefModule["downloadUrl"])
downloadCefURL = replaceSource(downloadCefURL, tools.ToString(cefModule["downloadSource"]), tools.ToInt(cefModule["downloadSourceSelect"]), "cef")
downloadCefURL = strings.ReplaceAll(downloadCefURL, "{version}", cefVersion)
downloadCefURL = strings.ReplaceAll(downloadCefURL, "{OSARCH}", libCEFOS)
downloads[command.CefKey] = &downloadInfo{isSupport: isSupport, fileName: urlName(downloadCefURL), downloadPath: filepath.Join(c.Install.Path, command.FrameworkCache, urlName(downloadCefURL)), frameworkPath: installPathName, url: downloadCefURL, module: cefModuleName}
// liblcl
// 如果选定的cef 106,在linux会指定liblcl gtk2 版本, 其它系统和版本以默认的形式区分
// 最后根据模块名称来确定使用哪个liblcl
liblclVersion := tools.ToRNilString(installVersion[liblclModuleName], "")
if liblclModule != nil {
libEnergyOS, isSupport := liblclOS(cef, liblclVersion, tools.ToString(liblclModule["buildSupportOSArch"]))
downloadEnergyURL := tools.ToString(liblclModule["downloadUrl"])
downloadEnergyURL = replaceSource(downloadEnergyURL, tools.ToString(liblclModule["downloadSource"]), tools.ToInt(liblclModule["downloadSourceSelect"]), "liblcl")
module := tools.ToString(liblclModule["module"])
downloadEnergyURL = strings.ReplaceAll(downloadEnergyURL, "{version}", liblclVersion)
downloadEnergyURL = strings.ReplaceAll(downloadEnergyURL, "{module}", module)
downloadEnergyURL = strings.ReplaceAll(downloadEnergyURL, "{OSARCH}", libEnergyOS)
downloads[command.LiblclKey] = &downloadInfo{isSupport: isSupport, fileName: urlName(downloadEnergyURL), downloadPath: filepath.Join(c.Install.Path, command.FrameworkCache, urlName(downloadEnergyURL)), frameworkPath: installPathName, url: downloadEnergyURL, module: liblclModuleName}
}
// 在线下载框架二进制包
for key, dl := range downloads {
fmt.Printf("Download %s: %s\n", key, dl.url)
if !dl.isSupport {
println("Warn module is not built or configured 【", dl.module, "】")
continue
}
bar := progressbar.NewBar(100)
bar.SetNotice("\t")
bar.HideRatio()
err = downloadFile(dl.url, dl.downloadPath, func(totalLength, processLength int64) {
bar.PrintBar(int((float64(processLength) / float64(totalLength)) * 100))
})
bar.PrintEnd("Download [" + dl.fileName + "] success")
if err != nil {
println("Download [", dl.fileName, "] error:", err.Error())
os.Exit(1)
}
dl.success = err == nil
}
// 解压文件, 并根据配置提取文件
println("Unpack files")
for key, di := range downloads {
if !di.isSupport {
println("Warn module is not built or configured 【", di.module, "】")
continue
}
if di.success {
if key == command.CefKey {
bar := progressbar.NewBar(0)
bar.SetNotice("Unpack file " + key + ": ")
tarName := UnBz2ToTar(di.downloadPath, func(totalLength, processLength int64) {
bar.PrintSizeBar(processLength)
})
bar.PrintEnd()
ExtractFiles(key, tarName, di, extractOSConfig)
} else if key == command.LiblclKey {
ExtractFiles(key, di.downloadPath, di, extractOSConfig)
}
println("Unpack file", key, "success\n")
}
}
println("\nSUCCESS \nInstalled version:", c.Install.Version, liblclVersion)
if liblclModule == nil {
println("hint: liblcl module", liblclModuleName, `is not configured in the current version, You need to use built-in binary build. [go build -tags="tempdll"]`)
}
}
func cefOS(module map[string]any) (string, bool) {
buildSupportOSArch := tools.ToString(module["buildSupportOSArch"])
mod := tools.ToString(module["module"])
archs := strings.Split(buildSupportOSArch, ",")
var isSupport = func(goarch string) bool {
for _, v := range archs {
if goarch == v {
return true
}
}
return false
}
if command.IsWindows { // windows arm for 64 bit, windows for 32/64 bit
if runtime.GOARCH == "arm64" {
return "windowsarm64", isSupport(command.WindowsARM64)
}
if strconv.IntSize == 32 {
return fmt.Sprintf("windows%d", strconv.IntSize), isSupport(command.Windows32)
}
return fmt.Sprintf("windows%d", strconv.IntSize), isSupport(command.Windows64)
} else if command.IsLinux { //linux for 64 bit
if runtime.GOARCH == "arm64" {
if mod == command.Cef106 {
return "linuxarm64", isSupport(command.LinuxARM64GTK2)
}
return "linuxarm64", isSupport(command.LinuxARM64) || isSupport(command.LinuxARM64GTK3)
} else if runtime.GOARCH == "amd64" {
if mod == command.Cef106 {
return "linux64", isSupport(command.Linux64GTK2)
}
return "linux64", isSupport(command.Linux64) || isSupport(command.Linux64GTK3)
}
} else if command.IsDarwin { // macosx for 64 bit
//if runtime.GOARCH == "arm64" {
// return "macosarm64", isSupport(MacOSARM64)
//} else if runtime.GOARCH == "amd64" {
// return "macosx64", isSupport(MacOSX64)
//}
// Mac amd64 m1 m2 架构目前使用amd64, m1,m2使用Rosetta2兼容
return "macosx64", isSupport(command.MacOSX64)
}
//not support
return fmt.Sprintf("%v %v", runtime.GOOS, runtime.GOARCH), false
}
var liblclFileNames = map[string]string{
"windows32": command.Windows32,
"windows64": command.Windows64,
"windowsarm64": command.WindowsARM64,
"linuxarm64": command.LinuxARM64,
"linuxarm64gtk2": command.LinuxARM64GTK2,
"linux64": command.Linux64,
"linux64gtk2": command.Linux64GTK2,
"darwin64": command.MacOSX64,
"darwinarm64": command.MacOSARM64,
"windows32_old": "Windows 32 bits",
"windows64_old": "Windows 64 bits",
"linux64gtk2_old": "Linux GTK2 x86 64 bits",
"linux64_old": "Linux x86 64 bits",
"darwin64_old": "MacOSX x86 64 bits",
}
func liblclName(version, cef string) (string, bool) {
var key string
var isOld bool
if runtime.GOARCH == "arm64" {
if command.IsLinux && cef == command.Cef106 { // 只linux区别liblcl gtk2
key = "linuxarm64gtk2"
} else {
if command.IsDarwin {
// Mac amd64 m1 m2 架构目前使用amd64, m1,m2使用Rosetta2兼容
key = fmt.Sprintf("%samd64", runtime.GOOS)
} else {
key = fmt.Sprintf("%sarm64", runtime.GOOS)
}
}
} else if runtime.GOARCH == "amd64" {
if command.IsLinux && cef == command.Cef106 { // 只linux区别liblcl gtk2
key = "linux64gtk2"
} else {
key = fmt.Sprintf("%s%d", runtime.GOOS, strconv.IntSize)
}
}
if tools.Compare("2.2.4", version) {
if key != "" {
key += "_old"
isOld = true
}
}
if key != "" {
return liblclFileNames[key], isOld
}
return "", false
}
// 命名规则 OS+[ARCH]+BIT+[GTK2]
// ARCH: 非必需, ARM 时填写, AMD为空
// GTK2: 非必需, GTK2(Linux CEF 106) 时填写, 非Linux或GTK3时为空
func liblclOS(cef, version, buildSupportOSArch string) (string, bool) {
archs := strings.Split(buildSupportOSArch, ",")
noSuport := fmt.Sprintf("%v %v", runtime.GOOS, runtime.GOARCH)
var isSupport = func(goarch string) bool {
for _, v := range archs {
if goarch == v {
return true
}
}
return false
}
if name, isOld := liblclName(version, cef); isOld {
if name == "" {
return noSuport, false
}
return name, true
} else {
return name, isSupport(name)
}
}
// LibLCLName
func LibLCLName(version, buildSupportOSArch string) (string, bool) {
return liblclOS("", version, buildSupportOSArch)
}
// 提取文件
func ExtractFiles(keyName, sourcePath string, di *downloadInfo, extractOSConfig map[string]any) {
println("Extract", keyName, "sourcePath:", sourcePath, "targetPath:", di.frameworkPath)
files := extractOSConfig[keyName].([]any)
if keyName == command.CefKey {
//tar
ExtractUnTar(sourcePath, di.frameworkPath, files...)
} else if keyName == command.LiblclKey {
//zip
ExtractUnZip(sourcePath, di.frameworkPath, files...)
}
}
func filePathInclude(compressPath string, files ...any) (string, bool) {
if len(files) == 0 {
return compressPath, true
......@@ -527,28 +119,37 @@ func dir(path string) string {
return path[:lastSep]
}
func ExtractUnTar(filePath, targetPath string, files ...any) {
func tarFileReader(filePath string) (*tar.Reader, func()) {
reader, err := os.Open(filePath)
if err != nil {
fmt.Printf("error: cannot open file, error=[%v]\n", err)
return
os.Exit(1)
return nil, nil
}
defer reader.Close()
var tarReader *tar.Reader
if filepath.Ext(filePath) == ".gz" {
gr, err := gzip.NewReader(reader)
if err != nil {
fmt.Printf("error: cannot open gzip file, error=[%v]\n", err)
return
os.Exit(1)
return nil, nil
}
return tar.NewReader(gr), func() {
gr.Close()
reader.Close()
}
defer gr.Close()
tarReader = tar.NewReader(gr)
} else {
tarReader = tar.NewReader(reader)
return tar.NewReader(reader), func() {
reader.Close()
}
}
}
func ExtractUnTar(filePath, targetPath string, files ...any) {
tarReader, close := tarFileReader(filePath)
if tarReader == nil {
return
}
defer close()
bar := progressbar.NewBar(100)
bar.SetNotice("\t")
bar.HideRatio()
......@@ -563,14 +164,13 @@ func ExtractUnTar(filePath, targetPath string, files ...any) {
}
// 去除压缩包内的一级目录
compressPath := filepath.Clean(header.Name[strings.Index(header.Name, "/")+1:])
//compressPath := filepath.Clean(header.Name[])
includePath, isInclude := filePathInclude(compressPath, files...)
if !isInclude {
continue
}
fmt.Println("compressPath:", compressPath)
info := header.FileInfo()
targetFile := filepath.Join(targetPath, includePath)
fmt.Println("compressPath:", compressPath)
if info.IsDir() {
if err = os.MkdirAll(targetFile, info.Mode()); err != nil {
fmt.Printf("error: cannot mkdir file, error=[%v]\n", err)
......@@ -714,16 +314,6 @@ func writeFile(r io.Reader, w *os.File, totalLength int64, callback func(totalLe
}
}
// url文件名
func urlName(downloadUrl string) string {
if u, err := url.QueryUnescape(downloadUrl); err != nil {
return ""
} else {
u = u[strings.LastIndex(u, "/")+1:]
return u
}
}
func isFileExist(filename string, filesize int64) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
......
//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
package install
import (
"bytes"
"encoding/json"
"fmt"
"github.com/energye/energy/v2/cmd/internal/command"
progressbar "github.com/energye/energy/v2/cmd/internal/progress-bar"
"github.com/energye/energy/v2/cmd/internal/tools"
"net/url"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
)
func installCEFFramework(c *command.Config) string {
if tools.CheckCEFDir() {
println("CEF Framework installed")
return ""
}
print("CEF Framework is not installed. Determine whether to install CEF Framework? Y/n: ")
var s string
fmt.Scanln(&s)
if strings.ToLower(s) != "y" {
println("CEF Framework install exit")
return ""
}
// 获取提取文件配置
extractData, err := tools.HttpRequestGET(command.DownloadExtractURL)
if err != nil {
fmt.Println("Error:", err.Error())
os.Exit(1)
return ""
}
var extractConfig map[string]any
extractData = bytes.TrimPrefix(extractData, []byte("\xef\xbb\xbf"))
if err := json.Unmarshal(extractData, &extractConfig); err != nil {
fmt.Println("Error:", err.Error())
os.Exit(1)
return ""
}
extractOSConfig := extractConfig[runtime.GOOS].(map[string]any)
// 获取安装版本配置
downloadJSON, err := tools.HttpRequestGET(command.DownloadVersionURL)
if err != nil {
fmt.Println("Error:", err.Error())
os.Exit(1)
return ""
}
var edv map[string]any
downloadJSON = bytes.TrimPrefix(downloadJSON, []byte("\xef\xbb\xbf"))
if err := json.Unmarshal(downloadJSON, &edv); err != nil {
fmt.Println("Error:", err.Error())
os.Exit(1)
return ""
}
// -c cef args value
// default(empty), windows7, gtk2, flash
cef := strings.ToLower(c.Install.CEF)
if cef != command.CefEmpty && cef != command.Cef109 && cef != command.Cef106 && cef != command.Cef87 {
fmt.Println("Error:", "-c [cef] Incorrect args value")
os.Exit(1)
return ""
}
installPathName := cefInstallPathName(c)
println("Install Path", installPathName)
println("Start downloading CEF and Energy dependency")
// 所有版本列表
var versionList = edv["versionList"].(map[string]any)
// 当前安装版本
var installVersion map[string]any
if c.Install.Version == "latest" {
// 默认最新版本
if v, ok := versionList[edv["latest"].(string)]; ok {
installVersion = v.(map[string]any)
}
} else {
// 自己选择版本
if v, ok := versionList[c.Install.Version]; ok {
installVersion = v.(map[string]any)
}
}
println("Check version")
if installVersion == nil || len(installVersion) == 0 {
fmt.Println("Error:", "Invalid version number ", c.Install.Version)
os.Exit(1)
return ""
}
// 当前版本 cef 和 liblcl 版本选择
var (
cefModuleName, liblclModuleName string
)
// 使用提供的特定版本号
if cef == command.Cef106 {
cefModuleName = "cef-106" // CEF 106.1.1
} else if cef == command.Cef109 {
cefModuleName = "cef-109" // CEF 109.1.18
} else if cef == command.Cef87 {
// cef 87 要和 liblcl 87 配对
cefModuleName = "cef-87" // CEF 87.1.14
liblclModuleName = "liblcl-87" // liblcl 87
}
// 如未指定CEF参数、或参数不正确,选择当前CEF模块最(新)大的版本号
if cefModuleName == "" {
var cefDefault string
var number int
for module, _ := range installVersion {
if strings.Index(module, "cef") == 0 {
if s := strings.Split(module, "-"); len(s) == 2 {
// module = "cef-xxx"
n, _ := strconv.Atoi(s[1])
if n >= number {
number = n
cefDefault = module
}
} else {
// module = "cef"
cefDefault = module
break
}
}
}
cefModuleName = cefDefault
}
// liblcl, 在未指定flash版本时,它是空 ""
if liblclModuleName == "" {
liblclModuleName = "liblcl"
}
// 当前安装版本的所有模块
var modules map[string]any
if m, ok := installVersion["modules"]; ok {
modules = m.(map[string]any)
}
// 根据模块名拿到对应的模块配置
var (
cefModule, liblclModule map[string]any
)
if module, ok := modules[cefModuleName]; ok {
cefModule = module.(map[string]any)
}
if module, ok := modules[liblclModuleName]; ok {
liblclModule = module.(map[string]any)
}
if cefModule == nil {
fmt.Println("Error:", "CEF module", cefModuleName, "is not configured in the current version")
os.Exit(1)
return ""
}
// 下载源选择
var replaceSource = func(url, source string, sourceSelect int, module string) string {
s := strings.Split(source, ",")
// liblcl 如果自己选择下载源
if module == "liblcl" && c.Install.Download != "" {
sourceSelect = tools.ToInt(c.Install.Download)
}
if len(s) > sourceSelect {
return strings.ReplaceAll(url, "{source}", s[sourceSelect])
}
return url
}
// 下载集合
var downloads = make(map[string]*downloadInfo)
// 根据模块名拿到版本号
cefVersion := tools.ToRNilString(installVersion[cefModuleName], "")
// 当前模块版本支持系统,如果支持返回下载地址
libCEFOS, isSupport := cefOS(cefModule)
downloadCefURL := tools.ToString(cefModule["downloadUrl"])
downloadCefURL = replaceSource(downloadCefURL, tools.ToString(cefModule["downloadSource"]), tools.ToInt(cefModule["downloadSourceSelect"]), "cef")
downloadCefURL = strings.ReplaceAll(downloadCefURL, "{version}", cefVersion)
downloadCefURL = strings.ReplaceAll(downloadCefURL, "{OSARCH}", libCEFOS)
downloads[command.CefKey] = &downloadInfo{isSupport: isSupport, fileName: urlName(downloadCefURL), downloadPath: filepath.Join(c.Install.Path, command.FrameworkCache, urlName(downloadCefURL)), frameworkPath: installPathName, url: downloadCefURL, module: cefModuleName}
// liblcl
// 如果选定的cef 106,在linux会指定liblcl gtk2 版本, 其它系统和版本以默认的形式区分
// 最后根据模块名称来确定使用哪个liblcl
liblclVersion := tools.ToRNilString(installVersion[liblclModuleName], "")
if liblclModule != nil {
libEnergyOS, isSupport := liblclOS(cef, liblclVersion, tools.ToString(liblclModule["buildSupportOSArch"]))
downloadEnergyURL := tools.ToString(liblclModule["downloadUrl"])
downloadEnergyURL = replaceSource(downloadEnergyURL, tools.ToString(liblclModule["downloadSource"]), tools.ToInt(liblclModule["downloadSourceSelect"]), "liblcl")
module := tools.ToString(liblclModule["module"])
downloadEnergyURL = strings.ReplaceAll(downloadEnergyURL, "{version}", liblclVersion)
downloadEnergyURL = strings.ReplaceAll(downloadEnergyURL, "{module}", module)
downloadEnergyURL = strings.ReplaceAll(downloadEnergyURL, "{OSARCH}", libEnergyOS)
downloads[command.LiblclKey] = &downloadInfo{isSupport: isSupport, fileName: urlName(downloadEnergyURL), downloadPath: filepath.Join(c.Install.Path, command.FrameworkCache, urlName(downloadEnergyURL)), frameworkPath: installPathName, url: downloadEnergyURL, module: liblclModuleName}
}
// 在线下载框架二进制包
for key, dl := range downloads {
fmt.Printf("Download %s: %s\n", key, dl.url)
if !dl.isSupport {
println("Warn module is not built or configured 【", dl.module, "】")
continue
}
bar := progressbar.NewBar(100)
bar.SetNotice("\t")
bar.HideRatio()
err = downloadFile(dl.url, dl.downloadPath, func(totalLength, processLength int64) {
bar.PrintBar(int((float64(processLength) / float64(totalLength)) * 100))
})
bar.PrintEnd("Download [" + dl.fileName + "] success")
if err != nil {
fmt.Println("Error:", "Download [", dl.fileName, "]", err.Error())
os.Exit(1)
}
dl.success = err == nil
}
// 解压文件, 并根据配置提取文件
println("Unpack files")
for key, di := range downloads {
if !di.isSupport {
println("Warn module is not built or configured 【", di.module, "】")
continue
}
if di.success {
if key == command.CefKey {
bar := progressbar.NewBar(0)
bar.SetNotice("Unpack file " + key + ": ")
tarName := UnBz2ToTar(di.downloadPath, func(totalLength, processLength int64) {
bar.PrintSizeBar(processLength)
})
bar.PrintEnd()
ExtractFiles(key, tarName, di, extractOSConfig)
} else if key == command.LiblclKey {
ExtractFiles(key, di.downloadPath, di, extractOSConfig)
}
println("Unpack file", key, "success\n")
}
}
println("\nSUCCESS \nInstalled version:", c.Install.Version, liblclVersion)
if liblclModule == nil {
println("hint: liblcl module", liblclModuleName, `is not configured in the current version, You need to use built-in binary build. [go build -tags="tempdll"]`)
}
return installPathName
}
func cefOS(module map[string]any) (string, bool) {
buildSupportOSArch := tools.ToString(module["buildSupportOSArch"])
mod := tools.ToString(module["module"])
archs := strings.Split(buildSupportOSArch, ",")
var isSupport = func(goarch string) bool {
for _, v := range archs {
if goarch == v {
return true
}
}
return false
}
if command.IsWindows { // windows arm for 64 bit, windows for 32/64 bit
if runtime.GOARCH == "arm64" {
return "windowsarm64", isSupport(command.WindowsARM64)
}
if strconv.IntSize == 32 {
return fmt.Sprintf("windows%d", strconv.IntSize), isSupport(command.Windows32)
}
return fmt.Sprintf("windows%d", strconv.IntSize), isSupport(command.Windows64)
} else if command.IsLinux { //linux for 64 bit
if runtime.GOARCH == "arm64" {
if mod == command.Cef106 {
return "linuxarm64", isSupport(command.LinuxARM64GTK2)
}
return "linuxarm64", isSupport(command.LinuxARM64) || isSupport(command.LinuxARM64GTK3)
} else if runtime.GOARCH == "amd64" {
if mod == command.Cef106 {
return "linux64", isSupport(command.Linux64GTK2)
}
return "linux64", isSupport(command.Linux64) || isSupport(command.Linux64GTK3)
}
} else if command.IsDarwin { // macosx for 64 bit
//if runtime.GOARCH == "arm64" {
// return "macosarm64", isSupport(MacOSARM64)
//} else if runtime.GOARCH == "amd64" {
// return "macosx64", isSupport(MacOSX64)
//}
// Mac amd64 m1 m2 架构目前使用amd64, m1,m2使用Rosetta2兼容
return "macosx64", isSupport(command.MacOSX64)
}
//not support
return fmt.Sprintf("%v %v", runtime.GOOS, runtime.GOARCH), false
}
var liblclFileNames = map[string]string{
"windows32": command.Windows32,
"windows64": command.Windows64,
"windowsarm64": command.WindowsARM64,
"linuxarm64": command.LinuxARM64,
"linuxarm64gtk2": command.LinuxARM64GTK2,
"linux64": command.Linux64,
"linux64gtk2": command.Linux64GTK2,
"darwin64": command.MacOSX64,
"darwinarm64": command.MacOSARM64,
"windows32_old": "Windows 32 bits",
"windows64_old": "Windows 64 bits",
"linux64gtk2_old": "Linux GTK2 x86 64 bits",
"linux64_old": "Linux x86 64 bits",
"darwin64_old": "MacOSX x86 64 bits",
}
func liblclName(version, cef string) (string, bool) {
var key string
var isOld bool
if runtime.GOARCH == "arm64" {
if command.IsLinux && cef == command.Cef106 { // 只linux区别liblcl gtk2
key = "linuxarm64gtk2"
} else {
if command.IsDarwin {
// Mac amd64 m1 m2 架构目前使用amd64, m1,m2使用Rosetta2兼容
key = fmt.Sprintf("%samd64", runtime.GOOS)
} else {
key = fmt.Sprintf("%sarm64", runtime.GOOS)
}
}
} else if runtime.GOARCH == "amd64" {
if command.IsLinux && cef == command.Cef106 { // 只linux区别liblcl gtk2
key = "linux64gtk2"
} else {
key = fmt.Sprintf("%s%d", runtime.GOOS, strconv.IntSize)
}
}
if tools.Compare("2.2.4", version) {
if key != "" {
key += "_old"
isOld = true
}
}
if key != "" {
return liblclFileNames[key], isOld
}
return "", false
}
// 命名规则 OS+[ARCH]+BIT+[GTK2]
// ARCH: 非必需, ARM 时填写, AMD为空
// GTK2: 非必需, GTK2(Linux CEF 106) 时填写, 非Linux或GTK3时为空
func liblclOS(cef, version, buildSupportOSArch string) (string, bool) {
archs := strings.Split(buildSupportOSArch, ",")
noSuport := fmt.Sprintf("%v %v", runtime.GOOS, runtime.GOARCH)
var isSupport = func(goarch string) bool {
for _, v := range archs {
if goarch == v {
return true
}
}
return false
}
if name, isOld := liblclName(version, cef); isOld {
if name == "" {
return noSuport, false
}
return name, true
} else {
return name, isSupport(name)
}
}
// 提取文件
func ExtractFiles(keyName, sourcePath string, di *downloadInfo, extractOSConfig map[string]any) {
println("Extract", keyName, "sourcePath:", sourcePath, "targetPath:", di.frameworkPath)
files := extractOSConfig[keyName].([]any)
if keyName == command.CefKey {
//tar
ExtractUnTar(sourcePath, di.frameworkPath, files...)
} else if keyName == command.LiblclKey {
//zip
ExtractUnZip(sourcePath, di.frameworkPath, files...)
}
}
// url文件名
func urlName(downloadUrl string) string {
if u, err := url.QueryUnescape(downloadUrl); err != nil {
return ""
} else {
u = u[strings.LastIndex(u, "/")+1:]
return u
}
}
//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
package install
import (
"fmt"
"github.com/energye/energy/v2/cmd/internal/command"
progressbar "github.com/energye/energy/v2/cmd/internal/progress-bar"
"github.com/energye/energy/v2/cmd/internal/tools"
"io/fs"
"os"
"path/filepath"
"runtime"
"strings"
)
// 下载go并配置安装
func installGolang(c *command.Config) string {
if tools.CommandExists("go") {
println("Golang installed")
return ""
}
print("Golang not installed, do you want to install Golang? Y/n: ")
var s string
fmt.Scanln(&s)
if strings.ToLower(s) != "y" {
println("Golang install exit")
return ""
}
s = c.Install.Path // 安装目录
exts := map[string]string{
"darwin": "tar.gz",
"linux": "tar.gz",
"windows": "zip",
}
// 开始下载并安装Go开发环境
version := command.GolangDefaultVersion
gos := runtime.GOOS
arch := runtime.GOARCH
ext := exts[gos]
if !tools.IsExist(s) {
println("Directory does not exist. Creating directory.", s)
if err := os.MkdirAll(s, fs.ModePerm); err != nil {
println("Failed to create goroot directory", err.Error())
return ""
}
}
fileName := fmt.Sprintf("go%s.%s-%s.%s", version, gos, arch, ext)
downloadUrl := fmt.Sprintf(command.GolangDownloadURL, fileName)
savePath := filepath.Join(s, command.FrameworkCache, fileName)
var err error
println("Golang Download URL:", downloadUrl)
println("Golang Save Path:", savePath)
if !tools.IsExist(savePath) {
// 已经存在不再下载
bar := progressbar.NewBar(100)
bar.SetNotice("\t")
bar.HideRatio()
err = downloadFile(downloadUrl, savePath, func(totalLength, processLength int64) {
bar.PrintBar(int((float64(processLength) / float64(totalLength)) * 100))
})
if err != nil {
bar.PrintEnd("Download [" + fileName + "] failed: " + err.Error())
} else {
bar.PrintEnd("Download [" + fileName + "] success")
}
}
if err == nil {
// 使用 go 名字做为 go 安装目录
targetPath := filepath.Join(s, "go")
// 释放文件
if command.IsWindows {
//zip
ExtractUnZip(savePath, targetPath)
} else {
//tar
ExtractUnTar(savePath, targetPath)
}
return targetPath
}
return ""
}
//----------------------------------------
//
// Copyright © yanghy. All Rights Reserved.
//
// Licensed under Apache License Version 2.0, January 2004
//
// https://www.apache.org/licenses/LICENSE-2.0
//
package install
import (
"fmt"
"github.com/energye/energy/v2/cmd/internal/command"
progressbar "github.com/energye/energy/v2/cmd/internal/progress-bar"
"github.com/energye/energy/v2/cmd/internal/tools"
"path/filepath"
"runtime"
"strings"
)
func installNSIS(c *command.Config) string {
if command.IsWindows && runtime.GOARCH == "amd64" {
if tools.CommandExists("makensis") {
println("NSIS installed")
return ""
}
print("NSIS is not installed. Do you want to install NSIS? Y/n: ")
var s string
fmt.Scanln(&s)
if strings.ToLower(s) != "y" {
println("NSIS install exit")
return ""
}
// 下载并安装配置NSIS
s = c.Install.Path // 安装目录
fileName := fmt.Sprintf("nsis.windows.386-%s.zip", command.NSISDownloadVersion)
downloadUrl := fmt.Sprintf(command.NSISDownloadURL, fileName)
savePath := filepath.Join(s, command.FrameworkCache, fileName)
var err error
println("Golang Download URL:", downloadUrl)
println("Golang Save Path:", savePath)
if !tools.IsExist(savePath) {
// 已经存在不再下载
bar := progressbar.NewBar(100)
bar.SetNotice("\t")
bar.HideRatio()
err = downloadFile(downloadUrl, savePath, func(totalLength, processLength int64) {
bar.PrintBar(int((float64(processLength) / float64(totalLength)) * 100))
})
if err != nil {
bar.PrintEnd("Download [" + fileName + "] failed: " + err.Error())
} else {
bar.PrintEnd("Download [" + fileName + "] success")
}
}
if err == nil {
// 使用 go 名字做为 go 安装目录
targetPath := filepath.Join(s, "NSIS")
// 释放文件
//zip
ExtractUnZip(savePath, targetPath)
return targetPath
}
} else {
println("Non Windows amd64 skipping nsis")
}
return ""
}
......@@ -12,11 +12,14 @@ package tools
import (
"bytes"
"github.com/energye/energy/v2/cmd/internal/command"
"github.com/energye/golcl/energy/tools"
"io/ioutil"
"math"
"net/http"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"text/template"
......@@ -158,3 +161,20 @@ func Compare(compare1, compare2 string) bool {
}
return false
}
func CheckCEFDir() bool {
var lib = func() string {
if command.IsWindows {
return "libcef.dll"
} else if command.IsLinux {
return "libcef.so"
} else if command.IsDarwin {
return "cef_sandbox.a"
}
return ""
}()
if lib != "" {
return tools.IsExist(filepath.Join(os.Getenv("ENERGY_HOME"), lib))
}
return false
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册