Browse Source

add macos appstore

master
skyboy 10 months ago
parent
commit
0fcdbdd3ac
  1. 29
      build.linux.sh
  2. 4
      docs/Store.md
  3. 13
      frontend/package-lock.json
  4. 1100
      godo/deps/darwin/brew-install.sh
  5. 2
      godo/go.mod
  6. 2
      godo/go.sum
  7. 64
      godo/store/cmds.go
  8. 25
      godo/store/install.go
  9. 153
      godo/store/os.go

29
build.linux.sh

@ -1,4 +1,25 @@
wails build -platform linux/amd64 -s -o godoos-linux-amd64
wails build -platform linux/arm64 -s -o godoos-linux-arm64
wails build -platform darwin/amd64 -s -o godoos-darwin-amd64
wails build -platform darwin/arm64 -s -o godoos-darwin-arm64
#!/bin/bash
# 定义一个函数来执行压缩操作
compress_to_zip() {
local target_file="./build/bin/godoos$2"
local zip_name="./build/bin/$1.zip"
# 检查ZIP文件是否已经存在,如果存在则跳过压缩
if [ ! -f "$zip_name" ]; then
echo "Compressing $target_file to $zip_name"
zip -j "$zip_name" "$target_file"
else
echo "$zip_name already exists. Skipping compression."
fi
}
# 构建和压缩
wails build -platform linux/amd64 -s
compress_to_zip "godoos-linux-amd64" ""
wails build -platform linux/arm64 -s
compress_to_zip "godoos-linux-arm64" ""
wails build -platform darwin/amd64 -s
compress_to_zip "godoos-darwin-amd64" ".app"
wails build -platform darwin/arm64 -s
compress_to_zip "godoos-darwin-arm64" ".app"

4
docs/Store.md

@ -220,7 +220,7 @@ const comp = await fetch('http://localhost:56780/store/setting', {
2. `static`目录下的在执行install时文件会自动复制到`.godoos/static/`应用目录下
3. `store.json`如果设置了`icon`,并且`static`目录下存在该文件,则应用图标为该文件。否则为`install.json`中的icon
### 内置应用说明
### `commands`内置函数说明
- 系统封装了一些用于处理进程控制和文件操作的功能函数,以下是各函数的详细描述:
1. `start` 启动应用
2. `stop` 停止应用
@ -235,6 +235,8 @@ const comp = await fetch('http://localhost:56780/store/setting', {
11. `startApp` 启动其他应用,content为应用名
12. `stopApp` 停止其他应用,content为应用名
- 保留命令`uninstall`,如果设置了`uninstall`,系统在卸载的时候将会执行它
### 进阶操作
1. 下载[mysql8.0](https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.39-winx64.zip)
2. 参考demo下的mysql8.0目录,尝试自己制作安装包

13
frontend/package-lock.json

@ -1262,17 +1262,6 @@
"integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==",
"dev": true
},
"node_modules/core-js": {
"version": "3.37.1",
"resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.37.1.tgz",
"integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==",
"hasInstallScript": true,
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
@ -2191,7 +2180,7 @@
"version": "5.5.4",
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"devOptional": true,
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"

1100
godo/deps/darwin/brew-install.sh

File diff suppressed because it is too large

2
godo/go.mod

@ -3,6 +3,7 @@ module godo
go 1.22.5
require (
github.com/cavaliergopher/grab/v3 v3.0.1
github.com/fsnotify/fsnotify v1.7.0
github.com/gorilla/mux v1.8.1
github.com/minio/selfupdate v0.6.0
@ -11,7 +12,6 @@ require (
require (
aead.dev/minisign v0.2.0 // indirect
github.com/cavaliergopher/grab/v3 v3.0.1 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect

2
godo/go.sum

@ -37,8 +37,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=

64
godo/store/cmds.go

@ -30,19 +30,9 @@ func runStart(storeInfo StoreInfo) error {
}
}
binPath := storeInfo.Setting.BinPath
if !libs.PathExists(binPath) {
return fmt.Errorf("script file %s does not exist", storeInfo.Setting.BinPath)
}
var cmd *exec.Cmd
if len(storeInfo.Start.StartCmds) > 0 {
cmd = exec.Command(binPath, storeInfo.Start.StartCmds...)
} else {
cmd = exec.Command(binPath)
}
if runtime.GOOS == "windows" {
// 在Windows上,通过设置CreationFlags来隐藏窗口
cmd = SetHideConsoleCursor(cmd)
cmd, err := GetRunCmd(storeInfo.Setting.BinPath, storeInfo.Start.StartCmds)
if err != nil {
return fmt.Errorf("failed to get run cmd: %w", err)
}
if err := cmd.Start(); err != nil {
//log.Println("Error starting script:", err)
@ -69,9 +59,46 @@ func runStart(storeInfo StoreInfo) error {
}
return nil
}
func GetRunCmd(binPath string, cmds []string) (*exec.Cmd, error) {
var cmd *exec.Cmd
if binPath != "" {
if !libs.PathExists(binPath) {
return cmd, fmt.Errorf("script file %s does not exist", binPath)
}
// 如果是非Windows环境,设置可执行权限
if runtime.GOOS != "windows" {
// 设置文件权限,0755是一个常见的可执行文件权限掩码
if err := os.Chmod(binPath, 0755); err != nil {
return cmd, fmt.Errorf("failed to set executable permissions on %s: %w", binPath, err)
}
}
if len(cmds) > 0 {
cmd = exec.Command(binPath, cmds...)
} else {
cmd = exec.Command(binPath)
}
} else {
if len(cmds) == 0 {
return cmd, fmt.Errorf("no commands provided")
}
if len(cmds) > 1 {
cmd = exec.Command(cmds[0], cmds[1:]...)
} else {
cmd = exec.Command(cmds[0])
}
}
if runtime.GOOS == "windows" {
// 在Windows上,通过设置CreationFlags来隐藏窗口
cmd = SetHideConsoleCursor(cmd)
}
return cmd, nil
}
func RunStartApp(appName string) error {
return ExecuteScript(appName)
}
func RunStopApp(appName string) error {
return StopCmd(appName)
}
@ -87,13 +114,12 @@ func runExec(storeInfo StoreInfo, cmdParam Cmd) error {
if err != nil {
return fmt.Errorf("failed to set start environment variable %s: %w", storeInfo.Name, err)
}
log.Printf("bin path:%v", cmdParam.BinPath)
log.Printf("cmds:%v", cmdParam.Cmds)
cmd := exec.Command(cmdParam.BinPath, cmdParam.Cmds...)
if runtime.GOOS == "windows" {
// 在Windows上,通过设置CreationFlags来隐藏窗口
cmd = SetHideConsoleCursor(cmd)
cmd, err := GetRunCmd(cmdParam.BinPath, cmdParam.Cmds)
if err != nil {
return fmt.Errorf("failed to get run cmd: %w", err)
}
if err := cmd.Start(); err != nil {
return fmt.Errorf("failed to run exec process %s: %w", storeInfo.Name, err)
}

25
godo/store/install.go

@ -168,6 +168,15 @@ func Uninstallation(pluginName string) error {
return fmt.Errorf("the app is being used by other applications: %v", hasDeps)
}
}
storeInfo, err := GetStoreInfo(pluginName)
if err == nil {
if _, ok := storeInfo.Commands["uninstall"]; ok {
replacePlaceholdersInCmds(&storeInfo)
if err := RunCmds(storeInfo, "uninstall"); err != nil {
return fmt.Errorf("error running uninstall command: %w", err)
}
}
}
// Remove the application directory
exePath := GetExePath(pluginName)
if libs.PathExists(exePath) {
@ -413,6 +422,22 @@ func replacePlaceholdersInCmds(storeInfo *StoreInfo) {
},
)
}
if len(cmd.Cmds) > 0 {
for j, cmd := range cmd.Cmds {
strValue := convertValueToString(value)
// 使用正则表达式替换Content中的占位符
storeInfo.Commands[cmdGroupName][i].Cmds[j] = pattern.ReplaceAllStringFunc(
cmd,
func(match string) string {
// 检查占位符是否与Config中的键匹配
if strings.Trim(match, "{}") == key {
return strValue
}
return match
},
)
}
}
}
}

153
godo/store/os.go

@ -0,0 +1,153 @@
package store
import (
"bufio"
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"syscall"
)
// DetectOperatingSystem returns the operating system name and version.
func DetectOperatingSystem() (name string, version string, err error) {
switch runtime.GOOS {
case "darwin":
// macOS specific detection
cmd := exec.Command("sw_vers")
out, err := cmd.CombinedOutput()
if err != nil {
return "", "", err
}
output := string(out)
lines := strings.Split(output, "\n")
if len(lines) >= 2 {
name = strings.TrimSpace(strings.Split(lines[0], ":")[1])
version = strings.TrimSpace(strings.Split(lines[1], ":")[1])
}
case "linux":
// Linux specific detection
file, err := os.Open("/etc/os-release")
if err != nil {
return "", "", err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "ID=") {
name = strings.TrimPrefix(line, "ID=")
name = strings.Trim(name, "\"")
} else if strings.HasPrefix(line, "VERSION_ID=") {
version = strings.TrimPrefix(line, "VERSION_ID=")
version = strings.Trim(version, "\"")
}
}
if err := scanner.Err(); err != nil {
return "", "", err
}
if name == "" || version == "" {
return "", "", fmt.Errorf("could not determine Linux distribution from /etc/os-release")
}
case "windows":
// Windows specific detection
cmd := exec.Command("cmd", "/c", "ver")
out, err := cmd.CombinedOutput()
if err != nil {
return "", "", err
}
version = strings.TrimSpace(string(out))
name = "Windows"
default:
// For other operating systems, just return the GOOS value
name = runtime.GOOS
version = ""
}
return name, version, nil
}
// DetectPackageManager returns the package manager based on the detected operating system.
func DetectPackageManager() (pm string, err error) {
switch runtime.GOOS {
case "darwin":
// macOS specific detection
cmd := exec.Command("which", "brew")
out, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("homebrew not found: %w", err)
}
pm = strings.TrimSpace(string(out))
if pm != "" {
pm = "brew"
}
case "linux":
// Linux specific detection
file, err := os.Open("/etc/os-release")
if err != nil {
return "", err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "ID=") {
id := strings.TrimPrefix(line, "ID=")
id = strings.Trim(id, "\"")
switch id {
case "debian", "ubuntu", "linuxmint", "elementary":
pm = "apt"
case "centos", "fedora", "rhel":
cmd := exec.Command("which", "dnf")
out, err := cmd.CombinedOutput()
if err != nil {
cmd = exec.Command("which", "yum")
out, err = cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("neither dnf nor yum found: %w", err)
}
}
pm = strings.TrimSpace(string(out))
if pm != "" {
pm = "dnf"
} else {
pm = "yum"
}
}
}
}
if err := scanner.Err(); err != nil {
return "", err
}
case "windows":
// Windows specific detection - Not applicable for this context
return "", fmt.Errorf("windows does not use apt, yum, or brew")
default:
// For other operating systems, just return an error
return "", fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
}
return pm, nil
}
func CheckPathInstalled(execName string, execCommands string) bool {
cmd := exec.Command(execName, execCommands)
out, err := cmd.CombinedOutput()
if err != nil {
// 如果命令执行失败,可能是因为brew没有安装
if exitErr, ok := err.(*exec.ExitError); ok {
// 判断是否是因为找不到命令导致的错误
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 127 {
return false // brew没有安装
}
}
}
fmt.Printf("Homebrew version: %s\n", out)
return true
}
Loading…
Cancel
Save